Modbus-Tcp 通讯学习总结
一、项目概览
NuGet 依赖
xml
<PackageReference Include="NModbus" Version="3.0.83" />
<PackageReference Include="NModbus.Serial" Version="3.0.83" />
NModbus:实现 Modbus TCP / UDP 协议主从站NModbus.Serial:串口(RTU/ASCII)场景下使用,本项目未直接调用
二、Modbus-Tcp 业务流程图
+-----------------------------+
| 应用程序启动 |
| Form1_Load 设置默认参数 |
| IP=127.0.0.1 Port=502 |
+--------------+--------------+
|
v
+--------------------+---------------------+
| 用户操作界面 |
| [选择模式] [输入IP] [输入端口] |
+----+-------------+--------------+------+
| | |
v v v
+------+----+ +-----+------+ +---+--------+
| ModbusTCP| | ModbusUDP | |RTU Over TCP|
+------+----+ +-----+------+ +---+--------+
| | |
| | |
| | |
v v v
+--------------------------------------+
| 创建 ModbusFactory |
| var factory = new ModbusFactory(); |
+------------------+-------------------+
|
v
+--------------------------------------+
| 建立底层网络连接并创建 Master |
| TcpClient.ConnectAsync(...) |
| master = factory.CreateMaster(tcp) |
+------------------+-------------------+
|
v
+------------+------------+
| 连接成功 / 按钮切换 |
| btnStart.Text=断开 |
+------------+------------+
|
+------------------+------------------+
| |
v v
+--------+--------+ +----------+----------+
| 读取流程 | | 写入流程 |
+--------+--------+ +----------+----------+
| |
v v
+--------+--------+ +----------+----------+
| 创建CTS + 启动 | | 调用 master. |
| Task.Run 循环 | | WriteSingleRegister|
+--------+--------+ +----------+----------+
| |
v v
+--------+--------+ +----------+----------+
| master.Read- | | 功能码 0x06 |
| HoldingRegisters| | 写入单个寄存器 |
| (1, 0, 4) | +----------+----------+
+--------+--------+
|
v
+--------+--------+
| 功能码 0x03 |
| 读取 HR0 ~ HR3 |
+--------+--------+
|
v
+--------+--------+
| Control.Invoke |
| 更新 4 个文本框 |
+--------+--------+
|
v
+--------+--------+
| Task.Delay(1000)|
| 1 秒轮询周期 |
+--------+--------+
|
+<--------+ (循环直到 cts.Cancel)
|
v
+--------+--------+
| 退出读取循环 |
+-----------------+
|
v
+--------+--------+
| 用户点击断开 |
| cts.Cancel() |
| 清空数据显示 |
+-----------------+
|
v
+----+----+
| 结束 |
+---------+
三、核心关键字段
csharp
private IModbusMaster? master; // Modbus 主站接口,统一抽象 TCP/UDP/RTU
private CancellationTokenSource? cts; // 异步读取任务的取消令牌
要点:
IModbusMaster是 NModbus 的统一主站接口,屏蔽底层传输差异CancellationTokenSource用于优雅停止后台轮询任务
四、关键代码片段
4.1 创建 ModbusFactory 与 Master
csharp
var factory = new ModbusFactory();
TcpClient tcp = new TcpClient();
tcp.ConnectAsync(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text));
master = factory.CreateMaster(tcp);
ModbusFactory.CreateMaster接受TcpClient/UdpClient/Socket,返回的IModbusMaster屏蔽底层传输差异。
4.2 周期读取保持寄存器
csharp
cts = new CancellationTokenSource();
Task.Run(async () =>
{
while (!cts.IsCancellationRequested)
{
if (master == null) continue;
ushort[] data = master.ReadHoldingRegisters(1, 0, 4);
Invoke(new Action(() =>
{
txtData1.Text = data[0].ToString();
// txtData2 / txtData3 / txtData4 ...
}));
await Task.Delay(1000);
}
}, cts.Token);
调用:master.ReadHoldingRegisters(slaveAddress=1, startAddress=0, numberOfPoints=4)
对应 Modbus 功能码 0x03,读取从站 1 的保持寄存器 HR0 ~ HR3。
4.3 写入单个寄存器
csharp
if (master == null) return;
master.WriteSingleRegister(1, 0, 111);
对应 Modbus 功能码 0x06,向从站 1 的 HR0 写入值 111。
4.4 断开连接
csharp
cts?.Cancel();
txtData1.Text = "";
// 清空其余显示 ...
btnRead.Text = "实时读取";
五、NModbus 支持的传输模式对比
| 模式 | UI 控件 | 底层类型 | NModbus 创建方式 |
|---|---|---|---|
| Modbus TCP | rdbTCP |
TcpClient |
factory.CreateMaster(tcp) |
| Modbus UDP | rdbUDP |
UdpClient |
factory.CreateMaster(udp) |
| RTU Over TCP /UDP | rdbRTUOverTCP/UDP |
Socket (Stream/Tcp/Udp) |
factory.CreateMaster(socket) |
Modbus TCP 使用 MBAP Header + PDU 帧格式;RTU Over TCP 在 TCP 流上承载含 CRC 的 RTU 帧。切换传输模式时业务代码(
ReadHoldingRegisters等)无需改动。
六、NModbus 关键 API 速查
| API | 功能码 | 作用 |
|---|---|---|
ReadCoils |
0x01 | 读线圈(bit) |
ReadInputs |
0x02 | 读离散输入(bit,只读) |
ReadHoldingRegisters |
0x03 | 读保持寄存器(16 bit) |
ReadInputRegisters |
0x04 | 读输入寄存器(只读) |
WriteSingleCoil |
0x05 | 写单个线圈 |
WriteSingleRegister |
0x06 | 写单个保持寄存器 |
WriteMultipleCoils |
0x0F | 写多个线圈 |
WriteMultipleRegisters |
0x10 | 写多个保持寄存器 |