2. Modbus 协议栈详解:物理层、数据链路层与应用层
Modbus 协议栈遵循 OSI 参考模型的分层思想,但在实际工业应用中只涉及物理层、数据链路层和应用层。理解这三层的职责与配合,是掌握 Modbus 数据采集的基础。
2.1 物理层:RS-232、RS-485 与 TCP
物理层定义了设备之间传输原始比特流的电气特性、机械接口和传输介质。Modbus 支持三种主流物理层实现:
| 特性 | RS-232 | RS-485 | TCP (Ethernet) |
|---|---|---|---|
| 传输方式 | 单端不平衡 | 差分平衡 | 基带/交换 |
| 最大距离 | 约 15 m | 约 1200 m | 100 m(UTP) |
| 节点数量 | 1 对 1 | 最多 32 节点(标准) | 理论无限制 |
| 拓扑结构 | 点对点 | 总线型 | 星型 |
| 抗干扰能力 | 弱 | 强 | 中(依赖交换机) |
| 典型应用 | 短距离调试 | 工厂现场总线 | 上位机/云平台 |
选型建议: 现场设备分散、距离远、干扰大时优先选用 RS-485;上位机与 PLC 或网关之间推荐使用 TCP;RS-232 仅用于近距离调试或老旧设备对接。
2.2 数据链路层:主从架构与报文帧
Modbus 数据链路层采用严格的主从(Master/Slave)架构。在同一总线上,同一时刻只能有一个主站发起请求,从站只能响应主站的请求,不能主动发送数据。
主从通信规则
- 主站(Master): 唯一能发起通信的节点,通常为 PLC、上位机或网关。
- 从站(Slave): 被动响应,每个从站拥有唯一的地址(1~247)。
- 轮询机制: 主站依次向各从站发送请求帧,从站回复响应帧。
- 广播: 主站可向地址 0 发送广播帧,所有从站接收但不回复。
报文帧结构(RTU 模式)
| 字段 | 长度 | 说明 |
|---|---|---|
| 从站地址 | 1 字节 | 目标从站 ID(1~247) |
| 功能码 | 1 字节 | 指定操作类型(读/写) |
| 数据区 | N 字节 | 寄存器地址、数量、数值等 |
| CRC 校验 | 2 字节 | 循环冗余校验(低字节在前) |
注意: RTU 模式要求帧内字符间隔小于 1.5 个字符时间,帧间间隔大于 3.5 个字符时间,否则从站可能误判帧边界。
2.3 应用层:功能码详解
应用层通过功能码(Function Code)定义具体的读写操作。功能码是 Modbus 协议的核心,决定了主站与从站之间交换的数据类型和操作方式。
常用功能码分类
| 类别 | 功能码 | 名称 | 操作对象 | 说明 |
|---|---|---|---|---|
| 位操作 | 0x01 | 读线圈 | DO(数字输出) | 读取 1~2000 个线圈状态 |
| 0x02 | 读离散输入 | DI(数字输入) | 读取 1~2000 个输入状态 | |
| 字操作 | 0x03 | 读保持寄存器 | AO(模拟输出) | 最常用,读取 1~125 个寄存器 |
| 0x04 | 读输入寄存器 | AI(模拟输入) | 读取 1~125 个寄存器 | |
| 0x06 | 写单个寄存器 | AO | 写入 1 个 16 位寄存器 | |
| 0x10 | 写多个寄存器 | AO | 写入 1~123 个寄存器 |
常见误区: 功能码 0x03 和 0x04 都用于读取寄存器,但 0x03 对应保持寄存器(可读可写),0x04 对应输入寄存器(只读)。混淆两者会导致通信失败或数据错误。
功能码与数据模型对应关系
Modbus 定义了四种基本数据对象,每种对象由不同的功能码访问:
- 线圈(Coil): 1 位,可读可写,对应功能码 0x01、0x05、0x0F。
- 离散输入(Discrete Input): 1 位,只读,对应功能码 0x02。
- 输入寄存器(Input Register): 16 位,只读,对应功能码 0x04。
- 保持寄存器(Holding Register): 16 位,可读可写,对应功能码 0x03、0x06、0x10。
2.4 协议栈分层协作示例
以下是一个完整的 Modbus RTU 读取保持寄存器请求帧示例,展示三层如何协作:
从站地址: 0x11 (17) ← 数据链路层:目标从站
功能码: 0x03 ← 应用层:读保持寄存器
起始地址: 0x00 0x6B ← 应用层:寄存器地址 107
寄存器数: 0x00 0x03 ← 应用层:读取 3 个寄存器
CRC 校验: 0x76 0x87 ← 数据链路层:帧校验
物理层负责将上述字节流转换为 RS-485 差分信号或 TCP 数据包,通过总线传输到目标从站。从站解析后返回对应数据。
实战要点: 在编写采集程序时,只需关注应用层的功能码和寄存器地址,物理层和数据链路层的细节通常由串口库或 Modbus 协议栈库封装。但理解底层机制有助于排查通信故障,例如 CRC 校验错误、地址冲突、波特率不匹配等。