Modbus 通过多条线在设备之间传输数据,其中最简单的设置是使用串行电缆连接主机和从机。数据以 0 或 1 的字符串传输,一个数字就是一个比特。0代表正电压,而1代表负电压。比特数据传输速度非常快,常见的传输速度为9600波特(即9600 bits/s)。
信息存储在从站的四个不同表中。两个表存储数字量,称为线圈;另外两个表存储模拟量,称为寄存器。对于线圈和寄存器,一个是只读的,一个是可读写的。每个表可以存储 9999 个值。线圈为一位,地址为0000~270E;寄存器为一个字(16 位,2 字节),地址也是从 0000 到 270E。
线圈/寄存器编号 | 数据地址 | 类型 | 表名 |
1-9999 | 0000 到 270E | 读写 | 离散输出线圈 |
10001-19999 | 0000 到 270E | 只读 | 离散输入触点 |
30001-39999 | 0000 到 270E | 只读 | 模拟输入寄存器 |
40001-49999 | 0000 到 270E | 读写 | 模拟输出保持寄存器 |
Coil/Register 的数量可以看作是地址的名称,它们不会出现在实际发送的消息中。数据地址在实际发送的消息中。
比如第一个Holding Register的编号是40001,它的数据地址是0000,这两个编号的区别是因为偏移量。
在网络中,每个从机都被分配了一个唯一的设备地址,范围从 1 到 247。当主机请求数据时,发送的消息的第一个字节是从机地址。这样,从机接收到第一个字节后,就知道是否需要忽略后续信息。
主机发送的第二个字节是功能码。该功能码告诉slave需要访问哪个表,是往表中写数据还是从表中读数据。
有趣的代码 | 行动 | 表名 |
01(01 十六进制) | 读 | 离散输出线圈 |
05(05 六角) | 写单 | 离散输出线圈 |
15(0F 十六进制) | 写多个 | 离散输出线圈 |
02(02 十六进制) | 读 | 离散输入触点 |
04(04 六角) | 读 | 模拟输入寄存器 |
03(03 六角) | 读 | 模拟输出保持寄存器 |
06(06 六角) | 写单 | 模拟输出保持寄存器 |
16(10 六角) | 写多个 | 模拟输出保持寄存器 |
CRC代表Cyclic Redundancy check,就是在每条消息发送后增加两个字节,以检查发送或接收是否有错误。消息的每个字节都用于计算 CRC。接收器在接收数据时计算 CRC。然后,它将计算结果与发送方计算的 CRC 进行比较。如果两者不同,则会发生错误。
数据地址 | 读 | 写单 | 写多个 |
离散输出线圈 0xxxx | FC01 | FC05 | FC15 |
离散输入触点 1xxxx | FC02 | 不适用 | 不适用 |
模拟输入寄存器 3xxxx | FC04 | 不适用 | 不适用 |
模拟输出保持寄存器 4xxxx | FC03 | FC06 | FC16 |
注:FC 代表功能代码
数据请求:
11 01 0013 0025 0E84
11:从机地址(0x11 = 17)
01:功能码01(读取线圈状态)
0013:线圈首地址(0x0013=19,+1偏移=#20线圈)
0025:要读取的线圈数(0x25 = 37, 20~56)
0E84:CRC
数据响应
11 01 05 CD6BB20E1B 45E6
11:从地址(0x11 = 17)
01:功能码01(读取线圈状态)
05:之后的字节数(37/8=5 字节)
CD:线圈 27-20 (1100 1101)
6B:线圈 35-28 (0110 1011)
B2:线圈 43-36 (1011 0010)
0E:线圈 51-44 (0000 1110)
1B:3个空格和线圈56-52 (0001 1011)
45E6:CRC