Modbus协议介绍
Modbus协议是一种应用层通信协议,最初由Modicon(现为施耐德电气的一部分)在1979年开发,设计用于可编程逻辑控制器(PLC)之间的通信。它是一种工业标准协议,支持多种通信方式,如串行通信(RS-232/RS-485)和以太网通信(Modbus TCP/IP)。以下是对Modbus协议的详细介绍:
一、Modbus协议基本概念
- 通信模式:
- 主从模式(Master-Slave):单个主机(Master)可以与多个从设备(Slave)通信。
- 请求-响应模式:主设备发送请求,从设备返回响应。
- 数据表示:
- 数据以二进制字节流的形式传输。
- 支持以下基本数据类型:
- 单位数值:16位寄存器(通常为无符号整型)。
- 布尔值:单个位。
- 扩展数据:通过多个寄存器组合实现浮点数、长整型等。
- 地址范围:
- 每个从设备有一个唯一地址(通常为1-247)。
- 主机通过从设备地址定位通信对象。
二、Modbus协议的功能码(Function Codes)
Modbus协议通过功能码指定操作类型,常见功能码包括:
- 读操作:
01
:读取线圈(Coils)状态。02
:读取离散输入(Discrete Inputs)状态。03
:读取保持寄存器(Holding Registers)。04
:读取输入寄存器(Input Registers)。
- 写操作:
05
:写单个位(线圈)。06
:写单个寄存器。15
:写多个位(线圈)。16
:写多个寄存器。
- 诊断操作:
08
:诊断功能,如回环测试(Loopback Test)。
三、Modbus协议的帧结构
Modbus协议的帧结构根据通信方式不同,主要分为Modbus RTU和Modbus TCP/IP两种。
1. Modbus RTU帧结构
Modbus RTU是基于串行通信的方式,数据格式紧凑,高效。
- 帧结构:字段长度 (字节)描述从站地址1标识目标设备的地址。功能码1指示执行的操作类型。数据字段N操作相关的具体数据,长度由功能码决定。校验码(CRC)2用于错误检测的循环冗余校验码。
- 特点:
- 数据帧之间通过时间间隔区分。
- CRC校验增强了通信的可靠性。
2. Modbus TCP/IP帧结构
Modbus TCP/IP基于以太网通信,数据传输速度更快,适用于现代网络环境。
- 帧结构:字段长度 (字节)描述事务标识符2标识请求和响应的匹配关系。协议标识符2固定为
0x0000
,表示Modbus协议。长度字段2表示后续数据的总长度(字节数)。单元标识符1对应Modbus RTU中的从站地址。功能码1操作类型。数据字段N操作相关数据。 - 特点:
- 取消了CRC校验,依赖TCP/IP的错误检测机制。
- 可实现远程通信,无需传统串行网络限制。
四、Modbus寄存器与数据模型
Modbus协议将设备的内部数据分为以下四种数据类型,每种类型有独立的地址空间:
- 线圈(Coils):
- 类型:读写。
- 数据内容:单个位。
- 地址范围:
00001
–09999
。
- 离散输入(Discrete Inputs):
- 类型:只读。
- 数据内容:单个位。
- 地址范围:
10001
–19999
。
- 输入寄存器(Input Registers):
- 类型:只读。
- 数据内容:16位整数。
- 地址范围:
30001
–39999
。
- 保持寄存器(Holding Registers):
- 类型:读写。
- 数据内容:16位整数。
- 地址范围:
40001
–49999
。
五、Modbus的优缺点
1. 优点:
- 简单易用:结构清晰,易于实现和调试。
- 兼容性强:广泛支持于工业设备。
- 灵活性高:支持多种通信方式(RTU/ASCII/TCP)。
- 可靠性高:RTU模式通过CRC确保数据完整性。
2. 缺点:
- 无安全性:缺乏身份验证和加密,易受攻击。
- 带宽限制:Modbus RTU数据帧短,适合低速通信。
- 地址空间有限:支持的设备地址较少。
六、Modbus的应用场景
- 工业自动化:
- PLC与传感器之间的数据采集和控制。
- HMI与PLC之间的通信。
- 能源管理:
- 智能电表的远程抄表。
- 电力系统的状态监测。
- 楼宇自动化:
- 空调、照明系统的集中控制。
- 电梯运行状态监控。
- 远程监控:
- 石油管道压力监测。
- 农业灌溉系统自动化控制。
七、Modbus协议的扩展与改进
- Modbus Plus:
- 提高了通信速率,支持多主设备网络。
- Modbus TCP/IP:
- 扩展到以太网环境,支持Internet远程通信。
- Modbus Secure:
- 提供基于TLS/SSL的安全通信。
Modbus数据包完整解释示例
下面以**Modbus RTU协议读取保持寄存器(Holding Registers)**的请求和响应为例,完整解析数据包的各个部分。
场景假设
- 主设备请求从设备地址 1。
- 请求读取从地址
40001
对应的保持寄存器起始地址(实际地址0000
),读取 2 个寄存器(即 4 个字节)。 - 从设备返回对应的数据。
1. Modbus RTU 请求帧结构解析
请求数据包:
字段 | 数据 | 长度 (字节) | 说明 |
---|---|---|---|
从站地址 | 0x01 | 1 | 指定目标设备地址为 1。 |
功能码 | 0x03 | 1 | 表示读取保持寄存器的功能码。 |
起始地址高字节 | 0x00 | 1 | 寄存器起始地址的高字节(起始地址 0000 的高字节)。 |
起始地址低字节 | 0x00 | 1 | 寄存器起始地址的低字节(起始地址 0000 的低字节)。 |
寄存器数量高字节 | 0x00 | 1 | 请求读取寄存器数量的高字节(读取 2 个寄存器)。 |
寄存器数量低字节 | 0x02 | 1 | 请求读取寄存器数量的低字节(读取 2 个寄存器)。 |
CRC校验低字节 | 0xC4 | 1 | CRC16 校验码的低字节(自动计算)。 |
CRC校验高字节 | 0x0B | 1 | CRC16 校验码的高字节(自动计算)。 |
完整请求帧(十六进制表示):
复制编辑01 03 00 00 00 02 C4 0B
字段逐步解析:
- 从站地址(
0x01
):- 表示请求发送到地址为 1 的从设备。
- 功能码(
0x03
):- 表示读取保持寄存器(Holding Registers)的请求。
- 起始地址(
0x0000
):- 请求从寄存器地址
40001
开始(Modbus地址40001
的实际地址为0000
)。
- 请求从寄存器地址
- 寄存器数量(
0x0002
):- 请求读取 2 个寄存器的数据。
- CRC校验(
0xC40B
):- 用于错误检测的循环冗余校验码,由请求帧前面的所有字节计算得出。
2. Modbus RTU 响应帧结构解析
响应数据包(假设从设备返回两个寄存器的值分别为 0x1234
和 0x5678
):
字段 | 数据 | 长度 (字节) | 说明 |
---|---|---|---|
从站地址 | 0x01 | 1 | 表示响应来自地址为 1 的从设备。 |
功能码 | 0x03 | 1 | 表示读取保持寄存器的功能码。 |
数据字节计数 | 0x04 | 1 | 表示后续数据部分的字节数,共 4 个字节(2 个寄存器,每个 2 字节)。 |
数据1高字节 | 0x12 | 1 | 第一个寄存器(40001 )的高字节。 |
数据1低字节 | 0x34 | 1 | 第一个寄存器(40001 )的低字节。 |
数据2高字节 | 0x56 | 1 | 第二个寄存器(40002 )的高字节。 |
数据2低字节 | 0x78 | 1 | 第二个寄存器(40002 )的低字节。 |
CRC校验低字节 | 0x5D | 1 | CRC16 校验码的低字节(自动计算)。 |
CRC校验高字节 | 0xCA | 1 | CRC16 校验码的高字节(自动计算)。 |
完整响应帧(十六进制表示):
mathematica复制编辑01 03 04 12 34 56 78 5D CA
字段逐步解析:
- 从站地址(
0x01
):- 表示响应来自地址为 1 的从设备。
- 功能码(
0x03
):- 表示设备成功执行了读取保持寄存器的操作。
- 数据字节计数(
0x04
):- 表示返回的寄存器数据部分共有 4 个字节。
- 数据部分:
- 第一个寄存器(
40001
):高字节0x12
,低字节0x34
,合并后为0x1234
。 - 第二个寄存器(
40002
):高字节0x56
,低字节0x78
,合并后为0x5678
。
- 第一个寄存器(
- CRC校验(
0x5DCA
):- 用于检测响应数据的完整性和正确性。
3. CRC校验计算
CRC校验采用 Modbus CRC16算法 计算以下部分:
- 请求帧校验范围:
01 03 00 00 00 02
。 - 响应帧校验范围:
01 03 04 12 34 56 78
。
计算步骤:
- 初始值为
0xFFFF
。 - 逐字节计算,更新CRC值。
- 最终结果是 2 字节,分别存储为低字节和高字节。
4. 总结
- 请求帧结构清晰,从站地址、功能码、起始地址、寄存器数量、CRC校验组成。
- 响应帧包含返回数据和相关信息,如数据字节计数、寄存器值及CRC校验。
- 数据解析直接基于功能码和数据结构,适合实现灵活的工业自动化系统。
如果需要实际代码实现,可以进一步探索基于Python、C或其他语言的Modbus通信库,如 pymodbus
或 libmodbus
。
Modbus地址与寄存器地址
1. Modbus地址与寄存器地址的概念
- Modbus地址:
- 用户可读的逻辑地址,用于表示不同类型的数据,例如保持寄存器、输入寄存器、线圈、离散输入等。
- Modbus地址从1开始(例如40001),符合人类习惯的编号方式。
- 寄存器地址:
- 实际的数据存储地址,是从0开始的偏移量,表示寄存器在设备中的位置。
- 计算机内部存储从0起始,因此寄存器地址比Modbus地址少1。
2. Modbus地址与寄存器地址的关系
Modbus协议将设备的数据存储划分为以下四种区域,每种区域有对应的逻辑地址范围和寄存器地址范围:
数据类型 | Modbus地址范围 | 寄存器地址范围 | Modbus地址示例 | 实际地址 |
---|---|---|---|---|
线圈(Coils) | 00001 – 09999 | 0 – 9998 | 00001 | 0 |
离散输入 | 10001 – 19999 | 0 – 9998 | 10001 | 0 |
输入寄存器 | 30001 – 39999 | 0 – 9998 | 30001 | 0 |
保持寄存器 | 40001 – 49999 | 0 – 9998 | 40001 | 0 |
在Modbus协议中:
- Modbus地址 = 实际寄存器地址 + 起始偏移量。
- 对于保持寄存器,起始偏移量为
40001
。
3. 为什么“地址40001”的实际地址是“0000”?
按照上述关系,Modbus地址40001 对应的实际寄存器地址可以通过以下公式计算:实际地址=Modbus地址−起始偏移量实际地址 = Modbus地址 – 起始偏移量实际地址=Modbus地址−起始偏移量
对于保持寄存器:实际地址=40001−40001=0实际地址 = 40001 – 40001 = 0实际地址=40001−40001=0
因此,Modbus地址 40001
的实际寄存器地址为 0000
。
4. 历史原因与设计初衷
- 人类友好性:
- 逻辑地址从1开始(如40001)更符合人类习惯,而计算机内部通常从0开始。
- 数据类型区分:
- Modbus协议使用逻辑地址的第一个数字区分数据类型。例如:
- 4xxxx 表示保持寄存器。
- 3xxxx 表示输入寄存器。
- 这种设计在工业设备的配置和调试中具有很高的可读性。
- Modbus协议使用逻辑地址的第一个数字区分数据类型。例如:
5. 实际应用中的注意事项
- 寄存器地址与Modbus地址的转换:
- 编写Modbus客户端时,很多库(如
pymodbus
)要求输入的是实际寄存器地址,而非Modbus地址。 - 如果需要读取Modbus地址
40001
,应将其转换为寄存器地址0
。
- 编写Modbus客户端时,很多库(如
- 误解与问题:
- 用户有时会混淆两种地址,导致通信失败。例如:
- 请求地址
40001
时输入寄存器地址40000
,会引发错误。
- 请求地址
- 用户有时会混淆两种地址,导致通信失败。例如:
6. 总结
- Modbus地址40001的实际地址为0000 是由于 Modbus地址从1起始,而寄存器地址从0起始。
- 这种设计提高了数据类型区分的可读性,同时需要在实际实现中正确转换地址。
- 熟悉地址关系对于避免通信错误至关重要。