Modbus 报文解析与组包

把十六进制报文粘进来就能逐字段拆开看,反过来也能拼出可以直发的报文。现场调试串口设备时省掉来回翻协议手册。

按字节用空格分开,也接受连写、逗号或 0x 前缀。功能码 01 到 04 的请求是 4 字节负载, 位数据响应在字节数为 3 时也是 4 字节,这两种情况靠方向设置区分。

Modbus 的常见坑

RTU 的 CRC 是低字节在前。Modbus RTU 在帧尾附加 2 字节 CRC,而且是低字节先发。这和大多数协议「高位在前」的习惯相反,手写组包时最容易在这里出错,表现为从站一直不回或者回异常。收到疑似正确但校验不过的报文时,先把这两个字节对调试试。

地址有两套编号,差一。Modbus 协议报文里的地址是从 0 开始的,但很多设备手册和组态软件用「从 1 开始」的编号(比如 40001、10001 这种)。所以手册写着 40001 时,报文里填的地址其实是 0。这一位之差造成的「读了但数据不对」非常常见,接线前先确认手册用的是哪套编号。

写线圈只有两个合法值。功能码 05 写单个线圈时,合上必须是 0xFF00、断开必须是 0x0000,写 0x0001 会让从站返回异常 03(非法数据值)。这是为了让写操作有较强的容错性——只有精确的这两组比特才被接受,抄错位就能被立刻发现。

32 位数据的字节序没有标准。Modbus 只规定了寄存器是 16 位大端,两个寄存器拼成一个 32 位浮点或整数时用哪种字节序、哪个寄存器在前,协议本身没说,各家设备自己定。现场遇到「值看着像但又不对」基本都是这个原因,把四种排列都试一遍最快。

RTU 靠静默间隔分帧。RTU 没有帧头帧尾,是靠总线静默 3.5 个字符时间来判断一帧结束的。这意味着波特率越低、间隔时间越长,也意味着如果程序读取时机不对,很容易把两帧粘在一起。粘包时 CRC 一定不过,这也是为什么收发都要先校验再用。