Modbus协议(TCP)
从今开始,会详细且陆续整理各类的通信协议,以便在需要且自身忘记的情况下,迅速复习。如有错误之处,还请批评指正。
一、Modbus协议的简述
Modbus协议作为应用层协议,基于主从设备模型,主设备负责请求消息,从设备进行消息的应答。
传输支持:
- 物理层:支持RS-232、RS-485等串行链路及以太网(TCP/IP)
- 协议版本:包括Modbus RTU(二进制高效传输)、Modbus ASCII(可读性高)、Modbus TCP(基于以太网)
本文重点叙述TCP的方式。
二、工作机制
- 请求-响应模式:主设备发送包含 功能码 和 数据地址 的请求帧,从设备返回操作结果或数据。例如:
- 功能码03H:读取保持寄存器(如读取温度设定值)
- 功能码06H:写入单个保持寄存器(如调整电机转速)
- 数据帧结构:
- Modbus RTU帧:地址 + 功能码 + 数据 + CRC校验
- Modbus TCP帧:MBAP头(事务ID、协议ID、后续报文的字节数、设备地址) + PDU(功能码 + 数据),注:事务ID,当需要进行并发请求的时候,就可使用不同的事务ID,避免匹配错误。 单元ID:多PLC通信的场景下,需要使用单元ID,以保证每条信息是专属的。
三、功能码
寄存器类型 | 功能码 | 操作类型 | 数据单位 | 典型应用 |
---|---|---|---|---|
线圈寄存器 | 01H | 读 | 位(Bit) | 监控继电器、电磁阀状态 |
05H | 写 | 单个位 | 控制单个执行机构 | |
0FH | 写 | 多个位 | 批量控制执行机构 | |
离散输入寄存器 | 02H | 读 | 位(Bit) | 监测外部传感器信号 |
输入寄存器 | 04H | 读 | 字(Word) | 获取传感器实时数据 |
保持寄存器 | 03H | 读 | 字(Word) | 读取设备配置参数 |
06H | 写 | 单个字 | 修改单个设备参数 | |
10H | 写 | 多个字 | 批量配置设备参数 |
四、寄存器类型
这里简要叙述下寄存器的类型,不同的寄存器它所占的空间大小和读写权限都是不同的
寄存器类型 | 功能码范围 | 读写权限 | 典型应用 |
---|---|---|---|
线圈寄存器 | 01H、05H、0FH | 读写 | 控制开关量输出(如继电器) |
离散输入寄存器 | 02H | 只读 | 监测开关量输入(如急停信号) |
输入寄存器 | 04H | 只读 | 读取模拟量输入(如传感器电压) |
保持寄存器 | 03H、06H、10H | 读写 | 存储设备参数或实时数据(如PID参数) |
五、异常码
在Modbus协议中,当从站设备(服务器)检测到请求错误时,会返回包含 异常功能码(Error Function Code) 和 异常码(Error Code) 的响应报文。
- 异常功能码:原功能码的最高位被置为1(即功能码 + 0x80)。例如:
- 原功能码
0x03
(读保持寄存器)→ 异常功能码0x83
。 - 原功能码
0x10
(写多个寄存器)→ 异常功能码0x90
。
- 原功能码
- 异常码:紧随异常功能码后,占1字节,表示具体错误类型(如非法地址、非法功能等)
- 以下列举出常用的异常码
异常码(十六进制) | 名称 | 含义 | 典型场景 |
---|---|---|---|
0x01 | 非法功能 (Illegal Function) | 请求的功能码不被支持或未实现。例如:向只读寄存器发送写操作。 | 主站发送功能码 0x05 (写线圈),但设备不支持该功能。 |
0x02 | 非法数据地址 (Illegal Data Address) | 寄存器地址超出设备允许范围。 | 请求读取地址 40010 ,但设备仅支持 40001-40005 。 |
0x03 | 非法数据值 (Illegal Data Value) | 写入的数据值不合法(如超出寄存器范围)。 | 试图向16位寄存器写入 0x10000 (最大值应为 0xFFFF )。 |
0x04 | 设备故障 (Slave Device Failure) | 从站设备内部错误(如硬件故障)。 | 从站设备因电源波动导致处理失败。 |
0x05 | 确认 (Acknowledge) | 从站已接收请求但需要更长时间处理(需主站轮询完成状态)。 | 主站请求写入大量数据,从站返回 0x05 表示正在处理。 |
0x0B | 目标设备未响应 (Target Device Failed to Respond) | 网关无法将请求转发到目标设备。 | 网络中断或目标设备离线。 |
六、举例
最后,我们来看三段报文
报文1:00 01 00 00 00 06 01 06 00 00 00 01
- MBAP头:
- Transaction ID:
00 01
(事务ID为1) - Protocol ID:
00 00
(Modbus协议) - Length:
00 06
(后续报文长度为6字节) - Unit ID:
01
(设备地址1)
- Transaction ID:
- PDU:
- 功能码:
06
(写单个保持寄存器) - 寄存器地址:
00 00
(地址0x0000) - 写入值:
00 01
(值为1)
- 功能码:
- 作用:向地址
0x0000
的保持寄存器写入值1
报文2:00 01 00 00 00 05 01 03 00 00 00 0A
- MBAP头:
- Transaction ID:
00 01
(事务ID为1) - Protocol ID:
00 00
(Modbus协议) - Length:
00 05
(后续报文长度为5字节) - Unit ID:
01
(设备地址1)
- Transaction ID:
- PDU:
- 功能码:
03
(读保持寄存器) - 寄存器起始地址:
00 00
(地址0x0000) - 读取数量:
00 0A
(读取10个寄存器)
- 功能码:
- 作用:从地址
0x0000
开始读取10个保持寄存器的值
报文3:
00 01 00 00 00 17 01 03 14 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A
- MBAP头:
- Transaction ID:
00 01
(事务ID为1) - Protocol ID:
00 00
(Modbus协议) - Length:
00 17
(后续报文长度为23字节) - Unit ID:
01
(设备地址1)
- Transaction ID:
- PDU:
- 功能码:
03
(读保持寄存器) - 字节数: 14(数据总字节20)
- 寄存器数据: 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A(10个寄存器的值)
- 功能码:
下面来一段错误报文的机制:
场景:主站尝试读取保持寄存器地址 400101(十进制地址100),但从站设备仅支持寄存器地址 400001-400050,导致地址越界错误
请求报文:00 01 00 00 00 06 01 03 00 64 00 01
字段 | 值(十六进制) | 说明 |
---|---|---|
事务ID | 00 01 | 事务标识符(自增值,用于匹配请求与响应)。 |
协议ID | 00 00 | Modbus TCP协议固定标识符(0x0000)。 |
长度 | 00 06 | 后续数据长度6字节(单元ID + PDU)。 |
单元ID | 01 | 从站地址(本例为1)。 |
功能码 | 03 | 读保持寄存器操作。 |
起始地址 | 00 64 | 十进制地址100(对应Modbus地址400101)。 |
寄存器数量 | 00 01 | 读取1个寄存器。 |
响应报文:00 01 00 00 00 03 01 83 02
字段 | 值(十六进制) | 说明 |
---|---|---|
事务ID | 00 01 | 与请求报文的事务ID一致,用于匹配请求与响应。 |
协议ID | 00 00 | 固定标识符(0x0000)。 |
长度 | 00 03 | 后续数据长度3字节(单元ID + 异常功能码 + 异常码)。 |
单元ID | 01 | 从站地址(与请求一致)。 |
异常功能码 | 83 | 原功能码 03 + 0x80(表示异常响应)。 |
异常码 | 02 | 错误类型为 非法数据地址(从站不支持地址400101)。 |