Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

6.0 KiB

Modbus RTU 0x14 收发 ADU 示例

1. 示例条件

本示例使用功能码 0x14 读取文件记录,按照当前工程只处理一个子请求的格式编写。

从站地址:        1
引用类型:        0x06
文件号:          0
起始记录号:      0
读取数量:        2个寄存器
第一个寄存器值:  0x1234
第二个寄存器值:  0x5678

2. 请求帧

2.1 完整请求 ADU

以下内容可以直接复制到十六进制串口助手发送:

01 14 07 06 00 00 00 00 00 02 78 E5

请求帧长度为:

12字节

2.2 请求帧解析

字节 含义 说明
01 从站地址 从站地址为1
14 功能码 读取文件记录
07 后续字节数 一个子请求固定占7字节
06 引用类型 Modbus文件记录规定为0x06
00 00 文件号 文件0
00 00 起始记录号 从记录0开始
00 02 记录长度 读取2个16位寄存器
78 E5 CRC16 CRC低字节78在前,高字节E5在后

请求帧中参与CRC计算的是:

01 14 07 06 00 00 00 00 00 02

计算得到:

CRC16 = 0xE578

Modbus RTU发送CRC时低字节在前,因此帧尾为:

78 E5

3. 正常响应帧

假设文件0的记录0和记录1分别保存:

记录0 = 0x1234
记录1 = 0x5678

3.1 完整响应 ADU

01 14 06 05 06 12 34 56 78 92 FE

响应帧长度为:

11字节

3.2 响应帧解析

字节 含义 说明
01 从站地址 响应来自从站1
14 功能码 读取文件记录
06 响应数据总字节数 后续子响应共6字节
05 子响应长度 引用类型1字节加寄存器数据4字节
06 引用类型 固定为0x06
12 34 第一个寄存器 值为0x1234
56 78 第二个寄存器 值为0x5678
92 FE CRC16 CRC低字节92在前,高字节FE在后

响应帧中参与CRC计算的是:

01 14 06 05 06 12 34 56 78

计算得到:

CRC16 = 0xFE92

因此响应帧尾发送:

92 FE

4. 长度计算

读取数量为 quantity 时,单子请求的请求帧长度固定为:

12字节

正常响应中的字段为:

子响应长度 = 1 + quantity × 2
响应数据总字节数 = 2 + quantity × 2
完整响应ADU长度 = 7 + quantity × 2

本例读取2个寄存器:

子响应长度 = 1 + 2 × 2 = 5字节
响应数据总字节数 = 2 + 2 × 2 = 6字节
完整响应ADU长度 = 7 + 2 × 2 = 11字节

5. 与当前代码的对应关系

请求帧中的参数由以下代码解析:

fileNumber = ModbusGetU16Be(&request[4]);
recordNumber = ModbusGetU16Be(&request[6]);
quantity = ModbusGetU16Be(&request[8]);

响应帧字段对应:

ModbusTxFrame[0] = ModbusSlaveAddress;
ModbusTxFrame[1] = 0x14U;
ModbusTxFrame[2] = (uint8_t)(2U + quantity * 2U);
ModbusTxFrame[3] = (uint8_t)(1U + quantity * 2U);
ModbusTxFrame[4] = 0x06U;

如果后续将文件号改为标准的一基编号,即文件号使用 1~16,测试请求中的文件号需要由:

00 00

改为:

00 01

同时重新计算请求帧CRC。

6. 读取124个寄存器的示例

6.1 请求条件

从站地址:    1
引用类型:    0x06
文件号:      0
起始记录号:  0
读取数量:    124个寄存器,即0x007C

6.2 完整请求ADU

以下请求可以直接复制到十六进制串口助手发送:

01 14 07 06 00 00 00 00 00 7C F8 C5

请求帧长度为:

12字节

请求帧解析如下:

字节 含义
01 从站地址为1
14 读取文件记录功能码
07 当前子请求包含7个字节
06 引用类型
00 00 文件号0
00 00 从记录0开始读取
00 7C 读取124个寄存器
F8 C5 CRC低字节、CRC高字节

参与CRC计算的内容为:

01 14 07 06 00 00 00 00 00 7C

计算结果为:

CRC16 = 0xC5F8

因此请求帧末尾按照低字节在前的顺序发送:

F8 C5

6.3 正常响应格式

读取124个寄存器时,寄存器数据占用:

124 × 2 = 248字节 = 0xF8字节

子响应长度为:

引用类型1字节 + 寄存器数据248字节
= 249字节
= 0xF9字节

响应数据总字节数为:

子响应长度字段1字节 + 子响应249字节
= 250字节
= 0xFA字节

所以正常响应格式为:

01 14 FA F9 06 [248字节寄存器数据] CRC低 CRC高

完整响应ADU长度为:

从站地址1字节
+ 功能码1字节
+ 响应数据总字节数字段1字节
+ 子响应长度字段1字节
+ 引用类型1字节
+ 寄存器数据248字节
+ CRC 2字节
= 255字节

该响应可以放入当前工程的256字节发送缓冲区:

static uint8_t ModbusTxFrame[256];

6.4 所有寄存器值均为0时的响应

假设读取的124个寄存器全部为 0x0000,响应帧的开头为:

01 14 FA F9 06

随后是248个 00 数据字节,帧尾CRC为:

6C 45

即:

01 14 FA F9 06 [248个00] 6C 45

该响应的CRC计算值为:

CRC16 = 0x456C

Modbus RTU按照低字节在前发送,因此CRC字段为:

6C 45

6.5 对应的代码限制

发送缓冲区长度为256字节时,单个0x14子请求最多读取124个寄存器,因此数量检查应为:

if ((quantity == 0U) || (quantity > 124U))
{
    ModbusSlaveStatistics.illegalValueCount++;
    return ModbusBuildException(
        request[1],
        MODBUS_EX_ILLEGAL_VALUE);
}

如果每个 MODBUS_HISTORY_ITEM 为520字节,即260个16位寄存器,还必须保证本次读取不超过当前文件:

if (((uint32_t)recordNumber + quantity) > 260UL)
{
    ModbusSlaveStatistics.illegalAddressCount++;
    return ModbusBuildException(
        request[1],
        MODBUS_EX_ILLEGAL_ADDRESS);
}