怎么用 Modbus 让两个设备互相通信*,包含硬件接线、协议原理、读写步骤,以及 C# 实操示例。
一、先搞懂:Modbus 通信的基本结构
Modbus 是 主从模式(Master-Slave):
- 主站(Master):电脑 / PLC / 网关 → 主动发指令
- 从站(Slave):仪表 / 传感器 / 继电器 → 只回复,不主动发
- 通信方式:
- Modbus RTU:串口 RS485(最常用)
- Modbus TCP:以太网(网线,IP 通信)
二、硬件怎么接?(以最常见的 Modbus RTU 为例)
-
电脑端
- USB 转 485 转换器(CH340 / FT232 等)
-
设备端
- 一般 3 根线:A / B / GND
-
接线规则
- A 接 A
- B 接 B
- GND 接 GND
- 千万不能接反,否则通信失败
-
串口参数(必须一致)
设备默认通常是:
- 波特率:9600
- 数据位:8
- 校验位:无
- 停止位:1
- 流控:无
三、Modbus 核心:4 种数据区(必须记住)
设备里的数据存在 4 个区域,用功能码区分:
| 功能码 | 名称 | 含义 | 常用叫法 |
|---|---|---|---|
| 01 | Read Coils | 读开关量输出 | DO / 线圈 |
| 02 | Read Discrete Inputs | 读开关量输入 | DI |
| 03 | Read Holding Registers | 读保持寄存器 | 最常用,读温度、电压、参数 |
| 04 | Read Input Registers | 读输入寄存器 | 只读传感器数据 |
写数据:
- 05:写单个线圈
- 06:写单个寄存器
- 15:写多个线圈
- 16:写多个寄存器
四、一次完整通信流程(以读温度为例)
-
主站发送报文(格式):
从站地址 + 功能码 + 起始地址 + 寄存器个数 + CRC校验 -
从站回复:
从站地址 + 功能码 + 数据长度 + 数据 + CRC
举个例子(读 1 号从站,地址 0 开始的 2 个寄存器):
发送:01 03 00 00 00 02 C4 0B
回复:01 03 04 01 23 45 67 ...
五、C# 实操:最简单的 Modbus 读写(用 NModbus)
这是你最常用的场景,直接复制可用。
1. 安装 NuGet 包
NModbus4
// 或 NModbus
2. Modbus RTU 读保持寄存器(功能码 03)
csharp
using System.IO.Ports;
using Modbus.Device;
// 1. 打开串口
SerialPort port = new SerialPort(
"COM3", // 你的串口号
9600, // 波特率
Parity.None,
8,
StopBits.One);
port.Open();
// 2. 创建 Modbus 主站
var master = ModbusSerialMaster.CreateRtu(port);
// 3. 读从站 1,起始地址 0,读 2 个寄存器
ushort[] values = master.ReadHoldingRegisters(
slaveId: 1,
startAddress: 0,
numberOfRegisters: 2);
// 输出结果
Console.WriteLine($"寄存器0:{values[0]}");
Console.WriteLine($"寄存器1:{values[1]}");
3. 写保持寄存器(功能码 06)
csharp
// 写 1 个值到从站1,地址 10
master.WriteSingleRegister(
slaveId: 1,
registerAddress: 10,
value: 1234);
4. Modbus TCP 版本(网线通信)
csharp
var tcpClient = new TcpClient("192.168.1.100", 502);
var master = ModbusIpMaster.CreateIp(tcpClient);
ushort[] values = master.ReadHoldingRegisters(1, 0, 2);
六、调试必用工具(非常重要)
- Modbus Poll:主站调试工具
- Modbus Slave:模拟从站
- 用这两个可以先测试通信是否正常,再写代码
七、常见问题
- 读不到数据
- 串口号错 / 波特率不对
- A B 接反
- 从站地址不对
- 数据乱码
- 校验位/停止位不匹配
- 没有共地(GND)
- CRC 错误
- 接线干扰、距离太长、没加终端电阻