Modbus TCPIP基础知识-------------C#编写Modbus TCP客户端程序(二)

本文通过一个C#示例程序详细解析了ModbusTCP报文的数据组成和传输方法,包括客户端设置、异步连接处理及读写保持寄存器数据的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面已经讲解了有关ModbusTCPIP协议的有关内容,相关链接:https://blog.youkuaiyun.com/sgmcumt/article/details/87435191
下面我们具体用一个C#的例程来说明一下ModbusTCP报文的数据组成和传输方法。
使用的调试工具是Modbus Slave和Modbus Poll。工具的使用可参照:https://blog.youkuaiyun.com/byxdaz/article/details/77979114

1 客户端概述

1.1 设置Modbus slave

我们使用Modbus slave作为服务器,Modbus slave的IP地址根据自己的电脑IP来确定,端口号默认为502。
modbus slave设置

1.2 客户端预览

客户端的设计界面如下图所示:

modbustcp客户端界面

为了保证程序的完整性,下面是整个程序的代码

using System;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace ModbusDemo
{
    public partial class FrmChildren : Form
    {
        private Socket tcpSocket = null;
        /// <summary>
        /// 是否已与服务器建立连接
        /// </summary>
        public bool Connected { get { return tcpSocket.Connected; } }
        public FrmChildren()
        {
            InitializeComponent();
        }

        private void btnLink_Click(object sender, EventArgs e)
        {
            IPAddress plcIPAddress = IPAddress.Parse(txtPLCIP.Text.ToString());
            int plcPort = int.Parse(txtPLCPort.Text.ToString());
            IPEndPoint pcIpport = new IPEndPoint(IPAddress.Parse(txtPCIP.Text.ToString()), int.Parse(txtPCPort.Text.ToString()));
            tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //tcpSocket.ServerConnectedAsync += TcpSocket_ServerConnected;
            if (!tcpSocket.Connected)
                // 开始异步连接操作
                tcpSocket.BeginConnect(plcIPAddress, plcPort, HandleTcpServerConnected, pcIpport);
        }
        /// <summary>
        /// 异步连接执行后处理程序
        /// </summary>
        /// <param name="ar"></param>
        private void HandleTcpServerConnected(IAsyncResult ar)
        {
            try
            {
                tcpSocket.EndConnect(ar);
                RaiseServerConnected();
            }
            catch (Exception ex)
            {
                    // 错误信息写入日志
                
            }
        }
        private void RaiseServerConnected()
        {
            //如果连接成功,textbox背景色为蓝色,否则为红色
            if (Connected)
            {
                txtPCIP.Invoke(new Action(() =>
                {
                    txtPCIP.BackColor = Color.Blue;
                    txtPCPort.BackColor = Color.Blue;
                }));
            }
            else
            {
                txtPCIP.Invoke(new Action(() =>
                {
                    txtPCIP.BackColor = Color.Red;
                    txtPCPort.BackColor = Color.Red;
                }));
            }
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            byte[] sendMessage = ConvertBytes(txtSendMessage.Text.ToString().Trim());
            tcpSocket.Send(sendMessage);
            byte[] reciveMessage = new byte[256];

            int receiveLength=Receive(ref reciveMessage, reciveMessage.Length);
            if (receiveLength != 0)
            {
                txtReceiveMessage.Text = ConvertString(reciveMessage);
            }
        }
        /// <summary>
        /// 接收从PLC发回来的数据
        /// </summary>
        /// <param name="response">存放接收数据的数组</param>
        /// <param name="respLength">接收的长度</param>
        /// <returns></returns>
        private int Receive(ref Byte[] response, int respLength)
        {
            int await = 3;
            if (!this.Connected)
            {
                throw new Exception("Socket is not connected.");
            }
            //如果服务器(PLC)没有数据传送过来,等待300ms;
            while (this.tcpSocket.Available == 0 && await > 0)
            {
                await--;
                Thread.Sleep(100);
            }
            if (this.tcpSocket.Available == 0) return 0;                //等待300ms后仍没有数据,则退出
            int recvLength = this.tcpSocket.Receive(response, respLength, SocketFlags.None);
            return recvLength;
        }
        private byte[] ConvertBytes(string sourceStr)
        {
            string[] tmpSrt = sourceStr.Trim().Split(' ');
            
            byte[] destinationByte = new byte[tmpSrt.Count()];
            for (int i = 0; i < tmpSrt.Count(); i++)
            {
                destinationByte[i] = Convert.ToByte(Convert.ToInt32( tmpSrt[i],16));
            }
            return destinationByte;
        }
        private string ConvertString(byte[] sourceBytes)
        {
            string byteStr = string.Empty;
            for (int i = 0; i <sourceBytes.Length; i++)
            {
                byteStr += string.Format("{0:D2}", sourceBytes[i]) + " ";
            }
            return byteStr;
        }
    }
}

2 案例讲解

2.1 参数设置

Modbus slave连接成功后,选择setup–>slave definition,Function选择“03 Holding Register”,其它设置如图所示:
modbusslave definition
设置完成后,在主界面的MBslave1页面设置地址1到10的数值为1到10,格式为十六进制,如图所示:
Mbslave1数据设置

2.2 读保持寄存器数据

我们的目的是请求读保持寄存器1-10的数据,根据上节1.1,1.2和3.3,可以很容易得出需要发送的byte[]数组:

01 01 00 00 00 06 FF 03 00 00 00 0A

接收的数据为:

01 01 00 00 00 23 255 03 20 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 10

注:接收的数据是十进制,所以FF为255。

程序界面如下图所示:
modbustcp测试界面

2.3 写单个保持寄存器数据

我们的目的是请求将十六进制 00 0A 写入寄存器2,根据上节1.1,1.2和3.6,可以很容易得出需要发送的byte[]数组:

02 01 00 00 00 06 FF 06 00 01 00 0A

接收的数据为:

02 01 00 00 00 06 255 06 00 01 00 10

程序界面如下图所示:

modbustcp测试界面(写数据)

Mbslave1数据更改后的界面如下图所示:

Mbslave数据更改后界面

### 配置西门子 S7-1200 PLC 的 TCP/IP 通信 西门子 S7-1200 PLC 支持多种通信协议,包括 TCP/IP,适用于与上位机、HMI 或其他设备进行高效通信。以下是配置和编程实现的指南。 #### 1. 硬件准备与网络配置 确保 S7-1200 PLC 与上位机处于同一局域网内,并正确设置 IP 地址。S7-1200 通常出厂默认 IP 地址为 `192.168.0.1`。如果需要更改 IP 地址,可以通过 TIA Portal 进行配置。 在 TIA Portal 中: 1. 打开项目并选择 S7-1200 PLC。 2. 在设备视图中,点击“设备名称”选项卡。 3. 输入新的 IP 地址和子网掩码。 4. 下载配置到 PLC。 确保网线连接正常,通信模块的指示灯(如 TX、RX)在数据传输时闪烁,表示通信正常 [^2]。 #### 2. 使用 TIA Portal 配置 TCP/IP 通信 在 TIA Portal 中,可以通过以下步骤配置 TCP/IP 通信: 1. 打开项目并进入“网络视图”。 2. 拖动“开放式用户通信”或“ISO 协议”到 PLC 的通信接口。 3. 配置目标 IP 地址和端口号。 4. 选择通信协议(如 ISO 协议或 TCP/IP)。 5. 生成并下载项目到 PLC。 在 PLC 程序中,可以使用 `T_CONNECT` 指令建立连接,使用 `T_SEND` 和 `T_RECV` 指令发送和接收数据。 #### 3. 使用 C# 编程实现 TCP/IP 通信 可以使用 C# 编写上位机程序,通过 TCP/IP 协议与 S7-1200 PLC 通信。以下是一个简单的 C# 示例代码: ```csharp using System; using System.Net.Sockets; class Program { static void Main() { TcpClient client = new TcpClient(); try { // 连接到 S7-1200 PLC client.Connect("192.168.0.1", 102); // 102 是 S7 协议的标准端口 Console.WriteLine("Connected to PLC"); // 获取网络流 NetworkStream stream = client.GetStream(); // 发送数据 string message = "Hello PLC"; byte[] data = System.Text.Encoding.ASCII.GetBytes(message); stream.Write(data, 0, data.Length); Console.WriteLine("Sent: {0}", message); // 接收响应 data = new byte[256]; int bytes = stream.Read(data, 0, data.Length); string response = System.Text.Encoding.ASCII.GetString(data, 0, bytes); Console.WriteLine("Received: {0}", response); // 关闭连接 stream.Close(); client.Close(); } catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); } } } ``` #### 4. 常见通信故障排查 通信故障是较为常见的问题,及时准确地排查和解决这些故障,对于保障系统的稳定运行至关重要。以下是一些常见的通信故障现象及对应的排查思路和解决方法: - **无法连接**:当 S7-1200 与 Modbus 设备无法建立连接时,首先要进行硬件检查。仔细查看硬件连接是否牢固,确保 RS485 线缆或以太网线缆的各个接头都紧密连接,没有松动、虚接的情况。检查通信模块的工作状态,查看模块上的指示灯是否正常亮起 [^2]。 - **数据传输不稳定**:检查网络环境是否存在干扰,确保网络带宽足够,避免网络拥堵。 - **IP 地址冲突**:确保 PLC 和上位机的 IP 地址不在同一子网中,避免 IP 地址冲突。 ####
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值