本节摘要:Modbus 报文在传输层之上叫 PDU(协议数据单元),就两个部分:功能码 + 数据。本节把 PDU 骨架拆开,讲清功能码的分类逻辑与"数据长度随功能码变化"的规则。位置:第 2 章知道了"读什么",本章回答"用什么功能码、报文长什么样"。
无论走串口还是 TCP,Modbus 的数据部分都遵循同一套 PDU 结构:
PDU = 功能码(1字节) + 数据(N字节,随功能码而定) 完整 ADU(应用数据单元): 串口 RTU:地址(1) + PDU + CRC16(2) TCP :MBAP头(7) + PDU
功能码按用途分三大类:位操作(01 读线圈、02 读离散输入、05 写单线圈、15 写多线圈)、寄存器操作(03 读保持、04 读输入、06 写单寄存器、16 写多寄存器)、诊断与扩展(07 读异常状态、08 诊断、43 封装接口等,100-110 留给用户自定义)。
| 功能码 | 含义 | 请求数据 | 响应数据 |
|---|---|---|---|
| 01 | 读线圈 | 起始地址(2)+数量(2) | 字节数(1)+位打包数据 |
| 03 | 读保持寄存器 | 起始地址(2)+数量(2) | 字节数(1)+寄存器字节 |
| 05 | 写单线圈 | 地址(2)+值(2, 0xFF00/0x0000) | 原样回显请求 |
| 06 | 写单寄存器 | 地址(2)+值(2) | 原样回显请求 |
| 15 | 写多线圈 | 地址(2)+数量(2)+字节数(1)+数据 | 地址(2)+数量(2) |
| 16 | 写多寄存器 | 地址(2)+数量(2)+字节数(1)+数据 | 地址(2)+数量(2) |
读操作响应里有个容易看漏的字段:字节数——它告诉接收方"后面跟着多少数据字节",比如读 10 个寄存器返回 20 字节,这个"20"就是给解析器对齐用的。写单点(05/06)的响应是原样回显,主站拿回显与请求比对即可确认执行;写多点(15/16)响应只回地址与数量,不回数据。
请求:01 03 00 00 00 02 C4 0B 01=从站地址 03=读保持 0000=起始偏移 0002=读2个寄存器 C40B=CRC16 应答:01 03 04 0B B8 00 00 6B 91 01=从站地址 03=功能码 04=数据字节数 0BB8=3000 0000=0 6B91=CRC16
这个例子能对上第 2 章的点表:读偏移 0 的两个保持寄存器,一个回了 3000,一个回了 0。逐字节对着点表读一遍,胜过背十遍规范。
同一功能码在 RTU、ASCII、TCP 三种载体下的 PDU 完全一致——这正是 Modbus 设计的精髓:PDU 与传输层解耦。差异只在包裹层:RTU 用 2 字节 CRC16 做校验、ASCII 用 LRC(1 字节)并把字节转成可见 ASCII、TCP 用 MBAP 头(无校验,靠 TCP 保证)。功能码、数据段、异常机制三者在三种模式下共享同一套实现,这是 Modbus 生态能同时覆盖串口与以太网的架构原因。
同一 PDU(读保持 40001,1 个寄存器)的三种形态: RTU : 01 03 00 00 00 01 84 0A ASCII : :010300000001F8\r\n (LRC=F8) TCP : 00 01 00 00 00 06 01 03 00 00 00 01 [事务][协议][长度][单元][PDU 原样]
| 维度 | 位操作(01/02/05/15) | 寄存器操作(03/04/06/16) |
|---|---|---|
| 单位 | 1 位 | 1 字(16 位) |
| 数据打包 | 8 位/字节,LSB 优先 | 2 字节/字,大端 |
| 单次上限 | 读 2000 位/写 1968 位 | 读 125 字/写 123 字 |
| 写值表示 | 0xFF00/0x0000 | 0x0000-0xFFFF |
解析 Modbus 报文是基本功,训练方法:拿一串原始 hex,先找地址与功能码,再按功能码查规范定长度,最后把数据解出来对照点表。
练习:解析以下 RTU 响应(从站 3,功能 03) 01 03 06 00 C8 01 90 00 0A 2F 9E 拆解: 地址=01 功能=03 字节数=06(3 个寄存器) 寄存器1=00C8=200 寄存器2=0190=400 寄存器3=000A=10 校验=2F9E(可离线验证)
把这类练习做十遍,抓包时一眼就能看出报文结构对不对,排障速度会明显提升。
要点回顾:PDU=功能码+数据;读操作响应带字节数、写单点回显、写多点回地址数量;逐字节对照点表是理解报文的最佳路径。骨架清楚了,下一节把读写功能码逐条实战一遍。
初学阶段手拼报文能加深理解,生产代码则应该用成熟库(libmodbus、pymodbus、Modbus Poll 等)。原因有三:库处理了边界(数量上限、字节数计算、超长帧分割);库处理了校验(CRC 计算与验证、异常帧识别);库处理了重试(超时、重发、从站忙的退避)。但用库不等于黑盒——理解 PDU 结构能帮你读库的日志与抓包,排障时能判断"是库的问题还是设备的问题"。
做报文解析训练时,按"找地址 → 找功能码 → 按功能码定长度 → 解数据 → 对照点表"的顺序,不要跳步。训练素材建议用真实抓包:把串口助手或 Wireshark 抓到的一帧帧保存下来,先自己解一遍再对照工具解析结果。练到"看到 01 03 00 00 00 02 C4 0B 能直接念出含义"的程度,现场排障的效率会有质的提升。
小结:PDU 与传输层解耦是 Modbus 跨载体通用的架构基础;按功能码查规范、逐字节解析训练是基本功。
