2. Modbus协议基础
Modbus 是工业自动化领域最广泛使用的现场总线协议之一,它的核心思想非常朴素:一台主站主动发起请求,多台从站被动响应。理解主从架构、功能码、寄存器类型、数据模型与地址映射,是后续做 RTU/TCP 网关映射、点表配置和故障排查的基础。很多现场问题并不是网络不通,而是对“寄存器地址从 0 还是从 1 开始”“功能码对应哪类数据”“网关该做透明转发还是地址重映射”理解不一致造成的。
一、主从架构:谁发起,谁响应
Modbus 采用典型的主从(Master/Slave)或客户端/服务器(Client/Server)模型。主站负责发起请求,从站只有在收到请求后才返回响应,从站之间不会主动通信。RTU 场景下通常一条 RS-485 总线上挂多台从站,通过从站地址区分设备;TCP 场景下通过 IP 和端口定位设备,再用单元标识符(Unit ID)区分同一网关后的多个从站。
- 主站:PLC、SCADA、上位机、网关的采集侧,负责轮询和写命令。
- 从站:仪表、变频器、电表、IO 模块,保存寄存器数据并响应请求。
- 请求帧:从站地址 + 功能码 + 数据区 + 校验(RTU 为 CRC,TCP 为 MBAP 头)。
- 响应帧:从站地址 + 功能码 + 数据/异常码 + 校验。
二、功能码:请求要做什么
功能码决定“这次操作读还是写、操作哪类寄存器”。工程中最常用的是 01、02、03、04、05、06、15、16。功能码最高位为 1 时表示异常响应,例如请求 03 返回 0x83,表示读保持寄存器出错。
| 功能码 | 名称 | 操作对象 | 典型用途 |
|---|---|---|---|
| 01 (0x01) | 读线圈 | 可读写位 | 读继电器、开关量输出状态 |
| 02 (0x02) | 读离散输入 | 只读位 | 读按钮、限位、DI 状态 |
| 03 (0x03) | 读保持寄存器 | 可读写 16 位 | 读参数、设定值、测量值 |
| 04 (0x04) | 读输入寄存器 | 只读 16 位 | 读温度、电量等实时采集值 |
| 05 (0x05) | 写单个线圈 | 可读写位 | 控制单路继电器 |
| 06 (0x06) | 写单个寄存器 | 可读写 16 位 | 修改单个设定参数 |
| 15 (0x0F) | 写多个线圈 | 可读写位 | 批量控制输出 |
| 16 (0x10) | 写多个寄存器 | 可读写 16 位 | 批量下发参数、配方 |
三、寄存器类型与数据模型
Modbus 把数据抽象成四类“表”,每类最多 65536 个条目。位数据以 1 bit 为单位,寄存器数据以 16 bit 为单位。需要特别注意:寄存器本身只定义 16 位无符号数,32 位整数、浮点数、字符串都需要占用连续两个或多个寄存器,并约定字节序和字序。
- 线圈(Coils):可读写位,功能码 01/05/15。
- 离散输入(Discrete Inputs):只读位,功能码 02。
- 输入寄存器(Input Registers):只读 16 位,功能码 04。
- 保持寄存器(Holding Registers):可读写 16 位,功能码 03/06/16。
对于 32 位数据,常见组合有 ABCD(大端)、CDAB(字交换)、BADC(字节交换)、DCBA(小端)。网关做协议转换时,必须和从站手册、上位机点表保持一致,否则会出现“数值对但量级差 65536 倍”或“高低字颠倒”的问题。
四、地址映射:0 基与 1 基的坑
Modbus 协议报文中的地址是从 0 开始的,称为 PDU 地址;而设备手册和组态软件常使用从 1 开始的寄存器编号,并带前缀区分类型,例如 40001 表示保持寄存器第 1 个。二者相差 1,这是现场最常见的地址错位来源。
协议地址(0基) 常用编号(1基) 类型
00000 00001 线圈
10000 10001 离散输入
30000 30001 输入寄存器
40000 40001 保持寄存器
示例:读保持寄存器第 1 个
请求地址 = 0x0000,数量 = 0x0001
若手册写 40001,则协议地址 = 40001 - 40001 = 0
五、案例:网关采集电表
某 Modbus RTU 电表,从站地址 1,波特率 9600 8N1。手册标注:电压为输入寄存器 30001,电流为 30002,有功功率为保持寄存器 40001(32 位浮点,CDAB)。网关作为 Modbus TCP 服务器,上位机通过 TCP 读取。
RTU 请求(读输入寄存器,电压):
01 04 00 00 00 01 31 CA
从站地址 01 | 功能码 04 | 起始地址 0000 | 数量 0001 | CRC 31 CA
TCP 请求(MBAP + PDU):
00 01 00 00 00 06 01 04 00 00 00 01
事务号 0001 | 协议号 0000 | 长度 0006 | 单元号 01 | 04 00 00 00 01
网关需要完成三件事:把 TCP 请求中的 Unit ID 映射为 RTU 从站地址;把 0 基协议地址原样转发或按点表重映射;把 RTU 响应封装回 MBAP 返回给上位机。若功率为 32 位 CDAB,网关还需按点表做字交换,否则上位机解析出的浮点值会明显异常。
六、常见误区与复盘
- 地址差 1:手册 40001 对应协议地址 0,不是 1。批量读取时起始地址和数量都要按 0 基计算。
- 功能码用错:只读输入寄存器用 04,保持寄存器用 03;用 03 读只读区可能返回异常码 0x83 或 0x02。
- 字节序/字序未确认:32 位数据必须确认 ABCD/CDAB/BADC/DCBA,最好用已知值(如 220.0V)反推验证。
- Unit ID 与从站地址混淆:TCP 网关后的 RTU 设备靠 Unit ID 区分,配置错误会导致“能连上但读不到数据”。
- 轮询过密:RTU 总线是共享介质,轮询间隔过短会造成超时和丢包,应结合波特率和从站数量估算。