4. 协议数据单元解析
在工业网关中,协议数据单元(PDU)是设备之间交换信息的最小完整单位。网关要做协议映射,第一步不是急着改数据,而是把收到的原始字节流“拆开看”:哪些字节属于帧头,哪些是地址,哪个字节是功能码,数据域从哪里开始,校验覆盖到哪一位,多字节数值按什么顺序解释。只有把 PDU 解析清楚,后续的点位映射、类型转换和转发才有可靠基础。
一、报文结构:从字节流到结构化字段
工业协议种类很多,但大多数 PDU 都可以抽象为“帧头 + 地址域 + 功能码 + 数据域 + 校验域”的分层结构。帧头用于同步和定界,地址域标识目标从站或源节点,功能码说明“要做什么”,数据域承载寄存器地址、数量、值或状态,校验域用于判断传输是否出错。解析的本质,就是按协议规定的偏移和长度,把连续字节切分成有语义的字段。
以常见的 Modbus RTU 为例,其帧格式为:从站地址(1 字节)+ 功能码(1 字节)+ 数据(N 字节)+ CRC 校验(2 字节)。而 Modbus TCP 则在前面增加 MBAP 报文头,包含事务标识、协议标识、长度和单元标识。两者虽然都叫 Modbus,但帧格式不同,网关必须分别处理。
二、地址域与功能码:谁在说话、要做什么
地址域决定“这条报文发给谁”。在 Modbus RTU 中,从站地址占 1 字节,范围 1~247,0 为广播地址;在 Modbus TCP 中,单元标识(Unit ID)承担类似角色,但真正定位设备的是 IP 地址和端口。网关做映射时,必须把“物理链路地址”和“协议逻辑地址”分开管理,否则容易出现多设备地址冲突或广播误转发。
功能码是 PDU 的“动词”。它告诉接收方本次操作是读线圈、读保持寄存器、写单个寄存器还是写多个寄存器。功能码通常占 1 字节,常见值有 0x01、0x03、0x06、0x10 等。网关在解析时,需要根据功能码判断数据域的长度和结构:读请求的数据域是“起始地址 + 数量”,读响应的数据域是“字节数 + 数据”,写请求则包含“地址 + 值”。如果功能码与数据域长度不匹配,应直接判定为非法报文。
三、数据域、校验方式与字节序
数据域是 PDU 中变化最大、也最容易出错的部分。它可能包含寄存器地址、寄存器数量、字节数、实际数值、状态位或字符串。解析数据域时,必须同时确认三件事:字段偏移、字段长度、数值编码方式。例如保持寄存器值通常为 16 位无符号整数,但温度、压力等工程量可能用有符号整数、32 位浮点数或 BCD 码表示。
校验方式决定报文是否可信。Modbus RTU 使用 CRC-16,校验范围覆盖从站地址到数据域末尾,低字节在前、高字节在后;Modbus ASCII 使用 LRC;部分电力协议使用累加和或 CRC-CCITT。网关在解析时,应先校验再映射,避免把错误数据转发到上层系统。
字节序是跨协议映射中最隐蔽的陷阱。同一个 32 位浮点数,在 Modbus 设备中可能按“高字在前、低字在前”或“字节交换”等方式存放。常见组合包括 ABCD、CDAB、BADC、DCBA。网关必须为每个点位配置正确的字节序,否则会出现数值巨大、符号反转或小数完全错误的问题。
| 字段 | 典型长度 | 作用 | 解析要点 |
|---|---|---|---|
| 帧头 / MBAP | 0~7 字节 | 同步、事务标识、长度定界 | TCP 下注意长度字段是否包含单元标识 |
| 地址域 | 1 字节 | 标识从站或单元 | 广播地址 0 不响应,需特殊处理 |
| 功能码 | 1 字节 | 说明操作类型 | 最高位为 1 表示异常响应 |
| 数据域 | N 字节 | 承载地址、数量、值、状态 | 长度和结构由功能码决定 |
| 校验域 | 1~2 字节 | 检测传输错误 | CRC 低字节在前,先校验后映射 |
四、案例:一条 Modbus RTU 读保持寄存器报文的解析
假设网关收到如下 RTU 请求帧:
01 03 00 00 00 02 C4 0B
按字段拆解:01 为从站地址,表示访问 1 号设备;03 为功能码,表示读保持寄存器;00 00 为起始地址 0;00 02 为读取数量 2;C4 0B 为 CRC 校验。若设备正常响应,返回帧可能为:
01 03 04 00 0A 00 14 9B 8F
其中 04 表示后续数据字节数为 4,00 0A 和 00 14 分别是两个寄存器的值,即 10 和 20。如果网关需要把这两个寄存器映射为 32 位整数,则要明确字节序:按 ABCD 解释为 0x000A0014,即 655380;按 CDAB 解释则为 0x0014000A,即 1310730。可见字节序配置错误会直接导致映射结果完全不同。
五、复盘:PDU 解析的检查清单
- 帧边界是否明确:RTU 依赖 3.5 字符间隔,TCP 依赖 MBAP 长度字段。
- 地址域是否越界:从站地址是否在 1~247 范围内,广播是否需要响应。
- 功能码是否支持:异常功能码是否被正确识别为错误响应。
- 数据域长度是否匹配:字节数、寄存器数量、起始地址是否自洽。
- 校验是否通过:CRC / LRC 计算范围和字节顺序是否正确。
- 字节序是否配置:16 位、32 位、浮点数的字序和字节序是否与设备一致。