目录
ModBus RTU 协议
功能码不同,读写数据格式不同,具体的格式建议参考下面的实例。
所有功能码如下:
功能码 | 作用 | 长度 |
---|---|---|
0x01 | 读线圈寄存器 | 1bit |
0x02 | 读离散输入寄存器 | 1bit |
0x03 | 读保持寄存器 | 16bit |
0x04 | 读输入寄存器 | 16bit |
0x05 | 写单个线圈寄存器 | 1bit |
0x06 | 写单个保持寄存器 | 16bit |
0x0f | 写多个线圈寄存器 | 1bit |
0x10 | 写多个保持寄存器 | 16bit |
地址划分如下(5bit):
名称 | 读写 | 地址范围 |
---|---|---|
线圈 | 可读可写布尔量(1bit) | 00001-09999 |
离散量输入 | 只读布尔量(1bit) | 10001-19999 |
输入寄存器 | 只读寄存器(16bit) | 30001-39999 |
保持寄存器 | 可读可写寄存器(16bit) | 40001-49999 |
测试
从以下网站获取modubus模拟设备https://www.modbus.cn/25794.html
从以下网站获取UART虚拟设备https://www.hhdsoftware.com/virtual-serial-port-tools
我们将会使用virtual-serial-port-tools创建两个虚拟的连接起来的设备,在这两个设备上分别建立一个虚拟ModBUS主机,ModBUS从机,观察通信过程。
读取多个线圈0x01
下图中是设置完毕之后的通信情况。从站内持有10个线圈,其中第二,第六,第十个数据为1,其余为0。
0982-Txd : 01 01 00 00 00 0A BC 0D
0982-Rxd : 01 01 02 22 02 20 9D
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 数量 | CRC(16bit) |
---|---|---|---|---|
01 | 01 | 00 00 | 00 0A | BC 0D |
从机回复
从站地址(8bit) | 功能码 (8bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|
01 | 01 | 02 | 02 22 | 20 9D |
可以看出,对于线圈数据,modubus将这些1bit数据放到了字节中传输。达不到8倍数的要填充0。下面是填充过的从机数据,其中第二、第六、第十个数据为1,其余为0,转换为16进制就是0x02 22。modubus先发的低字节
0000 0010 0010 0010
写入单个线圈0x05
注意1,0在下面的表现形式
1103-Txd : 01 05 00 00 FF 00 8C 3A
1103-Rxd : 01 05 00 00 FF 00 8C 3A
1104-Txd : 01 05 00 00 00 00 CD CA
1104-Rxd : 01 05 00 00 00 00 CD CA
主机发送1
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 数据(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 05 | 00 00 | FF 00 | 8C 3A |
主机发送0
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 数据(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 05 | 00 00 | 00 00 | CD CA |
从机回复数据与主机发送相同
写入多个线圈0x0F
1459-Txd : 01 0F 00 00 00 03 01 02 0E 96
1459-Rxd : 01 0F 00 00 00 03 15 CA
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 线圈个数(16bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|---|---|
01 | 0F | 00 00 | 00 03 | 01 | 02 | 0E 96 |
从机回复
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 线圈个数(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 0F | 00 00 | 00 03 | 15 CA |
读取离散量0x02
离散量是只读的1位数据
0011-Txd : 01 02 00 00 00 0A F8 0D
0011-Rxd : 01 02 02 82 01 18 D8
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 离散量个数(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 02 | 00 00 | 00 0A | F8 0D |
从机回复
从站地址(8bit) | 功能码 (8bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|
01 | 02 | 02 | 82 01 | 18 D8 |
0000 0001 1000 0010
前6bit填充0, 先发送低字节0x82,再发送高字节0x01
读取保持寄存器0x03
寄存器都是16位的数据,占用两个字节
0021-Txd : 01 03 00 00 00 0A C5 CD
0021-Rxd : 01 03 14 00 01 00 02 00 03 00 04 00 04 00 05 00 06 00 06 00 07 00 08 06 19
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 保持寄存器个数(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 03 | 00 00 | 00 0A | C5 CD |
从机回复
从站地址(8bit) | 功能码 (8bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|
01 | 03 | 14 | 00 01 00 02 00 03 00 04 00 04 00 05 00 06 00 06 00 07 00 08 | 06 19 |
写入单个保持寄存器0x06
0085-Txd : 01 06 00 02 00 1B 68 01
0085-Rxd : 01 06 00 02 00 1B 68 01
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 数据(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 06 | 00 02 | 00 1B | 68 01 |
从机回复数据与主机发送相同
写入多个保持寄存器0x10
0189-Txd : 01 10 00 00 00 0A 14 00 00 00 04 00 00 00 05 00 00 00 08 00 00 00 06 00 00 00 09 11 FC
0189-Rxd : 01 10 00 00 00 0A 40 0E
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 保持寄存器个数(16bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|---|---|
01 | 10 | 00 00 | 00 0A | 14 | 00 00 00 04 00 00 00 05 00 00 00 08 00 00 00 06 00 00 00 09 | 11 FC |
从机回复
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 保持寄存器个数(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 10 | 00 00 | 00 0A | 40 0E |
读取多个输入寄存器0x04
0200-Txd : 01 04 00 00 00 0A 70 0D
0199-Rxd : 01 04 14 00 00 00 02 00 08 00 06 00 22 00 00 00 05 00 00 00 07 00 06 F1 9A
主机发送
从站地址(8bit) | 功能码 (8bit) | 起始地址(16bit) | 输入寄存器数量(16bit) | CRC(16bit) |
---|---|---|---|---|
01 | 04 | 00 00 | 00 0A | 70 0D |
从机回复
从站地址(8bit) | 功能码 (8bit) | 字节计数(8bit) | 数据 | CRC(16bit) |
---|---|---|---|---|
01 | 04 | 14 | 00 00 00 02 00 08 00 06 00 22 00 00 00 05 00 00 00 07 00 06 | F1 9A |
挖坑:
1, FreeModbus协议移植
2, 源码分析