一、协议概述
Modbus 是一种串行通信协议,于 1979 年为可编程逻辑控制器(PLC)应用而推出,现已成为工业领域的业界标准通信协议,是工业电子设备间常用的连接方式。其广泛应用的核心优势包括:
- 协议公开发表,无版税使用要求,降低应用门槛;
- 工业网络部署相对简便,适配多种工业场景;
- 对供应商而言,修改原生位元或字节的限制较少,灵活性高。
Modbus RTU 作为 Modbus 协议的重要分支,采用二进制传输模式,通信过程中通过 RS-232、RS-485 等串行接口实现数据交互,支持主机与多个从机之间的通信架构,广泛应用于工业自动化控制系统中设备间的数据传输。
注:本说明中带前缀 0x 或后缀 H 的数据均为十六进制。
二、功能码简述
(一)功能码分类与核心信息
Modbus RTU 常用功能码分为位操作和字操作两类,位操作最小单位为 BIT,字操作最小单位为两个字节。各类功能码的核心信息如下表所示:
| 功能码 | 功能描述 | 对应寄存器 PLC 地址范围 | 操作类型 | 支持操作数量 |
|---|---|---|---|---|
| 01H | 读线圈状态 | 00001-09999 | 位操作(1 字节) | 单个或多个 |
| 02H | 读离散输入状态 | 10001-19999 | 位操作(1 字节) | 单个或多个 |
| 03H | 读保持寄存器 | 40001-49999 | 字操作(2 字节) | 单个或多个 |
| 04H | 读输入寄存器 | 30001-39999 | 字操作(2 字节) | 单个或多个 |
| 05H | 写单个线圈 | 00001-09999 | 位操作(1 字节) | 单个 |
| 06H | 写单个保持寄存器 | 40001-49999 | 字操作(2 字节) | 单个 |
| 0FH | 写多个线圈 | 00001-09999 | 位操作(1 字节) | 多个 |
| 10H | 写多个保持寄存器 | 40001-49999 | 字操作(2 字节) | 多个 |
(二)功能码分类说明
- 位操作指令:包括读线圈状态 01H、读离散输入状态 02H、写单个线圈 05H、写多个线圈 0FH,主要用于处理开关量类型的数据(如设备启停状态、传感器触发信号等)。
- 字操作指令:包括读保持寄存器 03H、写单个保持寄存器 06H、写多个保持寄存器 10H,主要用于处理模拟量或数值型数据(如传感器测量值、设备运行参数等)。
三、寄存器相关说明
(一)寄存器地址分配
寄存器的 PLC 地址、协议地址、对应功能码及操作属性如下表所示:
| 寄存器 PLC 地址范围 | 寄存器协议地址范围 | 对应功能码 | 寄存器类型 | 操作属性 |
|---|---|---|---|---|
| 00001-09999 | 0000H-FFFFH | 01H、05H、0FH | 线圈状态 | 可读可写 |
| 10001-19999 | 0000H-FFFFH | 02H | 离散输入状态 | 可读 |
| 30001-39999 | 0000H-FFFFH | 04H | 输入寄存器 | 可读 |
| 40001-49999 | 0000H-FFFFH | 03H、06H、10H | 保持寄存器 | 可读可写 |
(二)寄存器种类说明
不同类型寄存器的功能、PLC 类比及应用场景如下表所示:
| 寄存器种类 | 功能说明 | PLC 类比 | 应用举例 |
|---|---|---|---|
| 线圈状态 | 输出端口,可设定输出状态,也可读取该位输出状态 | DO(数字量输出) | 继电器输出、MOSFET(晶体管)输出等 |
| 离散输入状态 | 输入端口,通过外部设定改变输入状态,可读不可写 | DI(数字量输入) | 按钮开关、光电开关等触发信号 |
| 保持寄存器 | 输出参数或保持参数,控制器运行时被设定的某些参数,可读可写 | AO(模拟量输出) | 模拟量输出设定值、PID 运行参数、变量阀输出大小、传感器报警上下限等 |
| 输入寄存器 | 输入参数,控制器运行时从外部设备获得的参数,可读不可写 | AI(模拟量输入) | 模拟量传感器测量值(如温度、压力、流量等) |
(三)PLC 地址和协议地址区别
- 寄存器 PLC 地址:指存放于控制器(PLC、触摸屏、文本显示器等)中的地址,采用 10 进制 5 位描述,第一位数字标识寄存器类型。例如 40001、30002 等,在触摸屏和 PLC 编程中应用广泛。
- 寄存器协议地址:通信时使用的寄存器地址,采用 16 进制描述。映射关系如下:
-
- PLC 地址 40001 对应协议地址 0000H,40002 对应 0001H,40003 对应 0002H;
- PLC 地址 30003 对应协议地址 0002H。
需注意,不同类型寄存器可能对应相同的协议地址,但需通过不同功能码访问,因此不会产生通信冲突。
四、指令详细说明
(一)读线圈寄存器 01H
- 功能描述:读取线圈寄存器当前的开关状态(ON/OFF)。
- 查询格式(主机发送):
以从机地址 01H、线圈起始地址 0013H、结束地址 0037H(共 37 个线圈)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 01 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 13 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 25 |
| 7 | CRC 校验低字节 | 0C |
| 8 | CRC 校验高字节 | 14 |
3. 响应格式(从机返回):
响应数据中,每位对应一个线圈状态,1 代表 ON,0 代表 OFF;若线圈数非 8 的倍数,最后一个字节剩余位用 0 填充。示例返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 01 |
| 3 | 返回字节数 | 05 |
| 4 | 数据 1(线圈 0013H-001AH) | CD |
| 5 | 数据 2(线圈 001BH-0022H) | 6B |
| 6 | 数据 3(线圈 0023H-002AH) | B2 |
| 7 | 数据 4(线圈 002BH-0032H) | 0E |
| 8 | 数据 5(线圈 0033H-0037H) | 1B |
| 9 | CRC 校验低字节 | 44 |
| 10 | CRC 校验高字节 | EA |
4. 数据解析示例:
-
- 数据 1(CDH)二进制为 11001101,对应线圈 001AH-0013H,状态依次为 ON-ON-OFF-OFF-ON-ON-OFF-ON(最高位对应高地址线圈,最低位对应低地址线圈);
- 数据 5(1BH)二进制为 00011011,对应线圈 0037H-0033H,状态依次为 ON-ON-OFF-ON-ON,剩余 3 位填充 0。
(二)读离散输入寄存器 02H
- 功能描述:读取离散输入寄存器的开关状态(ON/OFF),该类寄存器状态由外部设备触发,仅支持读取。
- 查询格式(主机发送):
以从机地址 01H、离散输入起始地址 00C4H、结束地址 00D9H(共 22 个输入)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 02 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | C4 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 16 |
| 7 | CRC 校验低字节 | B8 |
| 8 | CRC 校验高字节 | 39 |
3. 响应格式(从机返回):
响应数据中,第一位数据字节的最低位对应查询起始地址寄存器状态,按地址递增顺序从低位到高位排列;非 8 的倍数时,最后字节剩余位填充 0。示例返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 02 |
| 3 | 返回字节数 | 03 |
| 4 | 数据 1(00C4H-00CBH) | AC |
| 5 | 数据 2(00CCH-00D3H) | DB |
| 6 | 数据 3(00D4H-00D9H) | 35 |
| 7 | CRC 校验低字节 | 22 |
| 8 | CRC 校验高字节 | 88 |
4. 数据解析示例:
-
- 数据 3(35H)二进制为 00110101,对应离散输入 00D9H-00D4H,状态依次为 ON-ON-OFF-ON-OFF-ON,00DBH、00DAH 填充 0。
(三)读保持寄存器 03H
- 功能描述:读取保持寄存器中的数值型数据,该类寄存器支持读写操作,常用于存储设备运行参数。
- 查询格式(主机发送):
以从机地址 01H、保持寄存器起始地址 006BH、结束地址 006DH(共 3 个寄存器)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 03 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 6B |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 03 |
| 7 | CRC 校验低字节 | 74 |
| 8 | CRC 校验高字节 | 17 |
3. 响应格式(从机返回):
每个保持寄存器占 2 字节,传输时高字节在前、低字节在后;寄存器间按地址递增顺序传输。示例返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 03 |
| 3 | 返回字节数 | 06 |
| 4 | 数据 1 高字节(006BH) | 00 |
| 5 | 数据 1 低字节(006BH) | 6B |
| 6 | 数据 2 高字节(006CH) | 00 |
| 7 | 数据 2 低字节(006CH) | 13 |
| 8 | 数据 3 高字节(006DH) | 00 |
| 9 | 数据 3 低字节(006DH) | 00 |
| 10 | CRC 校验低字节 | F5 |
| 11 | CRC 校验高字节 | 79 |
4. 数据解析:
寄存器 006BH 数值为 006BH(十进制 107),006CH 为 0013H(十进制 19),006DH 为 0000H(十进制 0)。
(四)读输入寄存器 04H
- 功能描述:读取输入寄存器中的模拟量或测量数据,该类寄存器仅支持读取,数据由外部传感器等设备提供。
- 查询格式(主机发送):
以从机地址 01H、输入寄存器起始地址 0008H、结束地址 0009H(共 2 个寄存器)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 04 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 08 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 02 |
| 7 | CRC 校验低字节 | F0 |
| 8 | CRC 校验高字节 | 09 |
3. 响应格式(从机返回):
每个输入寄存器占 2 字节,传输规则与保持寄存器一致(高字节在前、低字节在后,地址递增顺序传输)。示例返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 04 |
| 3 | 返回字节数 | 04 |
| 4 | 数据 1 高字节(0008H) | 00 |
| 5 | 数据 1 低字节(0008H) | 0A |
| 6 | 数据 2 高字节(0009H) | 00 |
| 7 | 数据 2 低字节(0009H) | 0B |
| 8 | CRC 校验低字节 | 9A |
| 9 | CRC 校验高字节 | 41 |
4. 数据解析:
寄存器 0008H 数值为 000AH(十进制 10),0009H 为 000BH(十进制 11)。
(五)写单个线圈寄存器 05H
- 功能描述:设置单个线圈的开关状态,FF00H 对应 ON 状态,0000H 对应 OFF 状态。
- 请求格式(主机发送):
以从机地址 01H、线圈地址 00ACH、设置为 ON 状态(数据 FF00H)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 05 |
| 3 | 寄存器地址高字节 | 00 |
| 4 | 寄存器地址低字节 | AC |
| 5 | 数据高字节 | FF |
| 6 | 数据低字节 | 00 |
| 7 | CRC 校验低字节 | 4C |
| 8 | CRC 校验高字节 | 1B |
3. 响应格式(从机返回):
从机返回与主机请求一致的数据,表明设置成功。返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 05 |
| 3 | 寄存器地址高字节 | 00 |
| 4 | 寄存器地址低字节 | AC |
| 5 | 数据高字节 | FF |
| 6 | 数据低字节 | 00 |
| 7 | CRC 校验低字节 | 4C |
| 8 | CRC 校验高字节 | 1B |
(六)写单个保持寄存器 06H
- 功能描述:设置单个保持寄存器的数值,仅支持单个寄存器操作。
- 请求格式(主机发送):
以从机地址 01H、保持寄存器地址 0000H、设置数值 0001H 为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 06 |
| 3 | 寄存器地址高字节 | 00 |
| 4 | 寄存器地址低字节 | 00 |
| 5 | 数据高字节 | 00 |
| 6 | 数据低字节 | 01 |
| 7 | CRC 校验低字节 | 48 |
| 8 | CRC 校验高字节 | 0A |
3. 响应格式(从机返回):
从机返回与主机请求一致的数据,表明设置成功。返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 06 |
| 3 | 寄存器地址高字节 | 00 |
| 4 | 寄存器地址低字节 | 00 |
| 5 | 数据高字节 | 00 |
| 6 | 数据低字节 | 01 |
| 7 | CRC 校验低字节 | 48 |
| 8 | CRC 校验高字节 | 0A |
(七)写多个线圈寄存器 0FH
- 功能描述:批量设置多个线圈的开关状态,数据区每位对应一个线圈(1=ON,0=OFF)。
- 请求格式(主机发送):
以从机地址 01H、线圈起始地址 0013H、结束地址 001CH(共 10 个线圈)为例,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 0F |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 13 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 0A |
| 7 | 字节数 | 02 |
| 8 | 数据 1(0013H-001AH) | CD |
| 9 | 数据 2(001BH-001CH) | 01 |
| 10 | CRC 校验低字节 | 72 |
| 11 | CRC 校验高字节 | CB |
3. 数据说明:
-
- 数据 1(CDH)对应线圈 0013H-001AH,最低位对应 0013H;
- 数据 2(01H)对应线圈 001BH-001CH,最低位对应 001BH,剩余位填充 0。
4. 响应格式(从机返回):
从机返回从机地址、功能码、起始地址及线圈数量,表明设置成功。返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 0F |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 13 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 0A |
| 7 | CRC 校验低字节 | (根据实际计算得出) |
| 8 | CRC 校验高字节 | (根据实际计算得出) |
(八)写多个保持寄存器 10H
- 功能描述:批量设置多个保持寄存器的数值,支持多个寄存器同时操作。
- 请求格式(主机发送):
以从机地址 01H、保持寄存器起始地址 0001H、结束地址 0002H(共 2 个寄存器)为例,0001H 设置为 000AH,0002H 设置为 0102H,发送数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 10 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 01 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 02 |
| 7 | 字节数 | 04 |
| 8 | 数据 1 高字节(0001H) | 00 |
| 9 | 数据 1 低字节(0001H) | 0A |
| 10 | 数据 2 高字节(0002H) | 01 |
| 11 | 数据 2 低字节(0002H) | 02 |
| 12 | CRC 校验低字节 | 92 |
| 13 | CRC 校验高字节 | 30 |
3. 响应格式(从机返回):
从机返回从机地址、功能码、起始地址及寄存器数量,表明设置成功。返回数据如下表:
| 字节序号 | 功能 | 十六进制数据 |
|---|---|---|
| 1 | 从机地址 | 01 |
| 2 | 功能码 | 10 |
| 3 | 寄存器起始地址高字节 | 00 |
| 4 | 寄存器起始地址低字节 | 01 |
| 5 | 寄存器数量高字节 | 00 |
| 6 | 寄存器数量低字节 | 02 |
| 7 | CRC 校验低字节 | 10 |
| 8 | CRC 校验高字节 | 08 |
五、CRC 计算
(一)CRC 校验原理
Modbus RTU 协议采用 16 位循环冗余校验码(CRC),由发送设备计算后附加在信息帧尾部,传输时低字节在前、高字节在后。接收设备对接收到的数据重新计算 CRC,若与接收到的 CRC 码不一致,则判定数据传输出错。