4. 数据帧结构:起始符、地址域、功能码、数据域、校验域、结束符详解
在 Stream 4 Function 1 协议中,设备参数读写的底层通信完全依赖 数据帧 进行。一个完整的数据帧由六个固定域按顺序组成:起始符、地址域、功能码、数据域、校验域、结束符。理解每一域的字节长度、取值范围和功能,是正确解析报文、避免通信故障的前提。
核心原则: 数据帧是“一问一答”的基础单元。主机发送请求帧,从机回复响应帧。两帧的结构完全一致,但数据域内容不同。
4.1 数据帧总体结构
下表展示了标准数据帧的字节布局(以十六进制表示):
| 域名称 | 字节数 | 固定值 / 范围 | 说明 |
|---|---|---|---|
| 起始符 | 1 字节 | 0xAA |
帧起始标记,接收方以此判断报文开始 |
| 地址域 | 1 字节 | 0x01 ~ 0xF7 |
目标从机设备地址(广播地址 0x00 保留) |
| 功能码 | 1 字节 | 0x03 / 0x06 / 0x10 |
指示操作类型:读、写单寄存器、写多寄存器 |
| 数据域 | N 字节 | 变长(0 ~ 252 字节) | 包含寄存器地址、数量、数据值等核心信息 |
| 校验域 | 2 字节 | CRC-16 (Modbus) | 对整个帧(起始符之后、校验域之前)进行循环冗余校验 |
| 结束符 | 1 字节 | 0x55 |
帧结束标记,接收方以此判断报文结束 |
提示: 起始符
0xAA 和结束符 0x55 是二进制互补模式(10101010 ↔ 01010101),这种设计有助于硬件级帧同步和抗干扰。
4.2 各域详解
4.2.1 起始符(Start Byte)
固定为 0xAA。接收设备在空闲状态持续监听总线,一旦检测到 0xAA,立即启动帧接收流程。如果起始符错误,整帧将被丢弃。
4.2.2 地址域(Address Field)
- 范围:
0x01~0xF7(1 ~ 247),对应 247 个可能的从机地址。 - 广播地址:
0x00保留用于主机向所有从机发送广播命令,从机不应答。 - 地址冲突: 同一总线上不允许两个从机使用相同地址,否则会导致数据碰撞和通信异常。
4.2.3 功能码(Function Code)
功能码决定了本次通信的操作类型。Stream 4 Function 1 协议主要使用以下三种:
| 功能码 | 名称 | 操作 | 数据域典型结构 |
|---|---|---|---|
0x03 |
读保持寄存器 | 读取从机 1 个或多个连续参数 | 起始地址(2B) + 寄存器数量(2B) |
0x06 |
写单个寄存器 | 写入单个参数值 | 寄存器地址(2B) + 数据值(2B) |
0x10 |
写多个寄存器 | 批量写入连续参数 | 起始地址(2B) + 数量(2B) + 字节数(1B) + 数据(NB) |
4.2.4 数据域(Data Field)
数据域是帧的“有效载荷”,长度可变。根据功能码不同,数据域包含:
- 寄存器地址: 2 字节,高字节在前(Big-Endian),范围
0x0000~0xFFFF。 - 寄存器数量: 2 字节,表示连续读/写的寄存器个数。
- 数据值: 每个寄存器占 2 字节,高字节在前。
- 字节计数: 仅写多寄存器命令(
0x10)包含,表示后续数据的总字节数。
4.2.5 校验域(CRC Field)
采用 CRC-16 (Modbus) 算法,校验范围从地址域开始到数据域结束(不包含起始符和结束符)。生成多项式为 0x8005,初始值为 0xFFFF。校验码低字节在前,高字节在后。
常见错误: 很多初学者将 CRC 计算范围误包含起始符或结束符,导致校验失败。请牢记:CRC 只校验 地址域 + 功能码 + 数据域。
4.2.6 结束符(End Byte)
固定为 0x55。接收方在收到 0x55 后,立即对已接收数据进行 CRC 校验,并判断帧是否完整。如果结束符错误,帧将被丢弃并触发超时重传。
4.3 数据帧结构示意图
下图以图形方式展示了完整数据帧的字节排列和每个域的作用:
4.4 完整帧示例
以下是一个实际读参数请求帧的逐字节解析:
请求帧(主机 → 从机,读取地址 0x0002 开始的 3 个寄存器):
AA 01 03 00 02 00 03 CRC_L CRC_H 55
字节分解:
AA → 起始符
01 → 地址域(从机地址 1)
03 → 功能码(读保持寄存器)
00 02 → 数据域:起始寄存器地址(高字节 0x00,低字节 0x02)
00 03 → 数据域:寄存器数量(3 个)
CRC_L CRC_H → 校验域(低字节在前,高字节在后)
55 → 结束符
响应帧(从机 → 主机,返回 3 个寄存器的值):
AA 01 03 06 00 1A 00 2B 00 3C CRC_L CRC_H 55
字节分解:
AA → 起始符
01 → 地址域(从机地址 1)
03 → 功能码(读保持寄存器)
06 → 数据域:后续数据字节数(3 个寄存器 × 2 字节 = 6 字节)
00 1A → 数据域:寄存器 0x0002 的值(0x001A = 26)
00 2B → 数据域:寄存器 0x0003 的值(0x002B = 43)
00 3C → 数据域:寄存器 0x0004 的值(0x003C = 60)
CRC_L CRC_H → 校验域
55 → 结束符
实战建议: 使用串口调试工具抓取报文时,先确认起始符
0xAA 和结束符 0x55 是否正确,再解析中间部分。如果 CRC 校验失败,优先检查地址域和功能码是否被错误修改。
4.5 常见错误与避坑指南
| 错误类型 | 现象 | 原因 | 解决方案 |
|---|---|---|---|
| 起始符错误 | 从机无响应 | 总线干扰导致 0xAA 被篡改 |
增加硬件滤波,检查总线终端电阻 |
| 地址不匹配 | 从机无响应 | 请求帧地址域与从机配置地址不一致 | 核对从机拨码开关或软件地址设置 |
| 功能码不支持 | 从机返回异常码 0x01 |
使用了协议未定义的功能码 | 仅使用 0x03、0x06、0x10 |
| CRC 计算错误 | 从机无响应或返回异常码 0x04 |
校验范围错误或算法实现有误 | 确认 CRC 只覆盖地址域+功能码+数据域 |
| 结束符错误 | 帧被丢弃,超时重传 | 总线噪声或字节丢失导致 0x55 错误 |
增加帧超时时间,检查通信线缆屏蔽 |
重要提醒: 在编写通信程序时,务必对接收到的每一帧进行 起始符验证、地址匹配、CRC 校验 和 结束符验证。任何一步失败都应立即丢弃该帧,避免错误数据写入设备参数。