Modbus RTU 报文帧格式
| 组成部分 |
长度 |
描述 |
| 地址域 |
1 Byte |
从设备的地址。范围:1-247(0为广播地址,主设备用,从设备不回复) |
| 功能码 |
1 Byte |
指明要执行的操作类型(如读线圈、写寄存器) |
| 数据域 |
N Bytes |
报文的核心内容,长度和内容取决于功能码(例如,要读取的寄存器起始地址、数量等) |
| CRC校验 |
2 Bytes |
循环冗余校验,用于检测传输过程中是否出现错误 |
功能码
| 功能码 (十进制) |
名称 |
操作对象 |
操作类型 |
| 01 |
Read Coils |
线圈 |
读 |
| 02 |
Read Discrete Inputs |
离散输入 |
读 |
| 03 |
Read Holding Registers |
保持寄存器 |
读 |
| 04 |
Read Input Registers |
输入寄存器 |
读 |
| 05 |
Write Single Coil |
线圈 |
写单个 |
| 06 |
Write Single Register |
保持寄存器 |
写单个 |
| 15 (0x0F) |
Write Multiple Coils |
线圈 |
写多个 |
| 16 (0x10) |
Write Multiple Registers |
保持寄存器 |
写多个 |
读保持寄存器(0x03)
主设备请求报文
| 字段 |
值 (十六进制) |
说明 |
| 地址 |
01 |
查询地址为1的从站 |
| 功能码 |
03 |
读保持寄存器 |
| 起始地址高字节 |
00 |
起始地址 40001 -> 0x0000 |
| 起始地址低字节 |
00 |
|
| 寄存器数量高字节 |
00 |
读取2个寄存器 -> 0x0002 |
| 寄存器数量低字节 |
02 |
|
| CRC低字节 |
C4 |
对前面所有字节计算出的CRC校验码 |
| CRC高字节 |
0B |
|
从设备正常响应报文
| 字段 |
值 (十六进制) |
说明 |
| 地址 |
01 |
来自地址为1的从站 |
| 功能码 |
03 |
读保持寄存器 |
| 字节计数 |
04 |
后面跟随的数据字节数(2寄存器 * 2字节/寄存器 = 4字节) |
| 数据1(寄存器40001)高字节 |
00 |
寄存器40001的值,假设为 0x0016 (22) |
| 数据1(寄存器40001)低字节 |
16 |
|
| 数据2(寄存器40002)高字节 |
00 |
寄存器40002的值,假设为 0x0017 (23) |
| 数据2(寄存器40002)低字节 |
17 |
|
| CRC低字节 |
79 |
对前面所有字节计算出的CRC校验码 |
| CRC高字节 |
8A |
|
写单个保持寄存器(0x06)
主设备请求报文格式
| 字段 |
长度 |
示例值 (十六进制) |
说明 |
| 从站地址 |
1 Byte |
01 |
要写入的从设备地址(1) |
| 功能码 |
1 Byte |
06 |
写单个寄存器的功能码 |
| 寄存器地址 |
2 Bytes |
00 01 |
要写入的寄存器目标地址(例如:40002) |
| 寄存器值 |
2 Bytes |
00 03 |
要写入的数据(例如:3) |
| CRC校验 |
2 Bytes |
F8 4A |
错误校验码 |
从设备正常响应报文格式
从设备在成功执行后,会原样返回主设备的请求报文。这是一种确认机制。
| 字段 |
长度 |
示例值 (十六进制) |
说明 |
| 从站地址 |
1 Byte |
01 |
从设备地址(1) |
| 功能码 |
1 Byte |
06 |
回声功能码 |
| 寄存器地址 |
2 Bytes |
00 01 |
已写入的寄存器地址 |
| 寄存器值 |
2 Bytes |
00 03 |
已写入的寄存器值 |
| CRC校验 |
2 Bytes |
F8 4A |
错误校验码 |
写多个保持寄存器(0x10)
主设备请求报文格式
| 字段 |
长度 |
示例值 (十六进制) |
说明 |
| 从站地址 |
1 Byte |
01 |
要写入的从设备地址(1) |
| 功能码 |
1 Byte |
10 |
写多个寄存器的功能码 |
| 起始地址 |
2 Bytes |
00 00 |
要写入的第一个寄存器地址(例如:40001) |
| 寄存器数量 |
2 Bytes |
00 03 |
要写入的寄存器总数(例如:3个) |
| 字节计数 |
1 Byte |
06 |
后面紧跟的数据域的字节数(寄存器数量 × 2 = 3 × 2 = 6字节) |
| 寄存器值 |
N × 2 Bytes |
00 0A 00 0B 00 0C |
要写入的数据,每个寄存器2字节。这里依次是10, 11, 12 |
| CRC校验 |
2 Bytes |
26 C6 |
错误校验码 |
从设备正常响应报文格式
从设备的响应不包含写入的数据,只包含确认信息:起始地址和寄存器数量。
| 字段 |
长度 |
示例值 (十六进制) |
说明 |
| 从站地址 |
1 Byte |
01 |
从设备地址(1) |
| 功能码 |
1 Byte |
10 |
回声功能码 |
| 起始地址 |
2 Bytes |
00 00 |
已写入的起始寄存器地址 |
| 寄存器数量 |
2 Bytes |
00 03 |
已写入的寄存器总数 |
| CRC校验 |
2 Bytes |
01 C8 |
错误校验码 |
Modbus异常响应帧
当Modbus从站设备无法处理主站发来的请求时,它会返回一个异常响应(Exception Response)来告诉主站问题出在哪里
一个标准的Modbus异常响应帧主要包含以下四个部分
| 字段 | 长度 | 说明 |
| ----- | ------- | ---------- | ----------- |
| 从站地址 |
1 字节 |
返回响应的设备地址。 |
| 异常功能码 |
1 字节 |
原始请求功能码 + 0x80(即最高位设为1),例如请求03(读保持寄存器),异常响应则为0x83。 |
| 异常代码 |
1 字节 |
一个数字代码,用于指明具体的错误类型(详见下表)。 |
| 校验 |
2 字节 |
CRC校验,用于检查传输错误 |
最常见的异常代码
异常代码是理解错误原因的关键。下表汇总了最常用的几个代码,它们覆盖了绝大多数日常调试中遇到的问题
| 异常代码 |
名称 |
含义与常见原因 |
| 01 |
非法功能 (Illegal Function) |
从站不支持你请求的功能码。比如从站只支持03功能码,但你却发送了10功能码。 |
| 02 |
非法数据地址 (Illegal Data Address) |
请求的寄存器地址不存在、超出范围,或该地址只读但你尝试写入。 |
| 03 |
非法数据值 (Illegal Data Value) |
请求中的数据值不合法,比如写入的值超出了寄存器允许的范围。 |
| 04 |
从站设备故障 (Slave Device Failure) |
从站在尝试执行请求的操作时,发生了无法恢复的内部错误。 |
| 06 |
从站设备忙 (Slave Device Busy) |
从站正在处理一个耗时较长的命令,暂时无法响应,主站稍后重试即可 |