PLC 地址与协议地址
手册里常见的 40001、30001 这类五位/六位编号是“PLC 地址”(Modicon 约定),首位表示数据区,后面是区内编号且从 1 开始。报文里实际传输的是从 0 开始的协议地址,所以 40101 对应保持寄存器、协议地址 100(0x0064),用功能码 03 读取。调试时“差一个地址”的问题,十有八九出在这里。
| 首位 | 数据区 | 读 | 写 |
|---|---|---|---|
| 0xxxx | 线圈 | 01 | 05 / 15 |
| 1xxxx | 离散输入 | 02 | 只读 |
| 3xxxx | 输入寄存器 | 04 | 只读 |
| 4xxxx | 保持寄存器 | 03 | 06 / 16 |
32 位数据的字节序
Modbus 一个寄存器只有 16 位,Float32 / Int32 要占两个连续寄存器。协议只规定了寄存器内部高字节在前,两个寄存器谁在前由厂家自定,于是出现 ABCD、CDAB、BADC、DCBA 四种排列。最快的判断方法:在仪表上找一个已知读数(如量程上限 100.0),把读回的 4 个字节填进“数据解析”,看哪一行 Float32 等于 100,就是这台设备的字节序。实际项目中 ABCD 与 CDAB(字交换)最常见。
RTU 与 TCP 帧结构
RTU 帧 = 从站地址 + 功能码 + 数据 + CRC16(多项式 0xA001,初值 0xFFFF,低字节在前)。Modbus TCP 去掉 CRC,在前面加 7 字节 MBAP 头:事务号(2) + 协议号 0000(2) + 长度(2) + 单元标识(1),其中长度 = 单元标识 + PDU 的字节数。网关做 RTU/TCP 转换时,单元标识一般就是串口侧的从站地址。
异常响应
从站拒绝请求时,把功能码最高位置 1 返回(03 → 83),后跟 1 字节异常码。现场最常见的是 02(地址越界,多为 PLC 地址减 1 没处理好)和 0B(网关后面的设备无响应,多为串口参数或从站地址不对)。