E32转E95-DTU的Modbus RTU传输异常:FB字节与CRC错误排查
E32转E95-DTU的Modbus RTU异常字节与CRC错误处理
一、前置字节FB的含义分析
你接收帧开头的FB字节不属于标准Modbus RTU协议内容,大概率是E95-DTU主动附加的状态标识字节:
FB(十进制251)通常对应DTU的接收信号强度(RSSI)等级、链路质量或工作状态码,具体定义需查阅E95-DTU官方手册。- 若不需要该前缀字节,可登录DTU配置界面,找到“数据转发前缀”或“状态输出”相关选项关闭即可。
二、Modbus RTU CRC错误的解决方法与正确数据包格式
1. 标准Modbus RTU请求帧结构(以功能码04读取输入寄存器为例)
完整请求帧必须包含以下部分(字节顺序):
- 从站地址(1字节):范围
0x01~0xF7,对应你的传感器地址0x01 - 功能码(1字节):
0x04(读取输入寄存器) - 数据段(4字节,大端格式):
- 起始寄存器地址高字节 + 起始寄存器地址低字节
- 寄存器数量高字节 + 寄存器数量低字节
- CRC校验(2字节,小端格式:低字节在前,高字节在后)
2. 你的错误帧分析
你发送的帧01 04 02 09 A1 7E D8存在结构问题:
- 数据段不完整:功能码04的请求需要4字节数据(起始地址+寄存器数量),但你的帧中仅包含
02 09两个字节,缺少寄存器数量的2字节。 - CRC计算错误:因帧结构错误,手动拼接的CRC自然不匹配,导致接收端返回CRC错误。
3. 正确数据包示例(读取从站01、起始地址0x0209的1个输入寄存器)
完整帧应为:01 04 02 09 00 01 [CRC低字节] [CRC高字节]
用Modbus CRC计算器计算前6字节01 04 02 09 00 01的CRC为0x8639,最终帧为:01 04 02 09 00 01 39 86
4. 解决CRC错误的具体步骤
- 用代码自动计算CRC:避免手动拼接CRC出错,建议实现Modbus CRC16算法或使用成熟库生成帧。示例代码:
// 实现Modbus CRC16计算 uint16_t modbusCRC(uint8_t *data, uint8_t len) { uint16_t crc = 0xFFFF; for (uint8_t i = 0; i < len; i++) { crc ^= data[i]; for (uint8_t j = 0; j < 8; j++) { crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1); } } return crc; } // 构造并发送请求帧 void sendModbusRequest() { uint8_t request[8] = {0x01, 0x04, 0x02, 0x09, 0x00, 0x01, 0x00, 0x00}; uint16_t crcVal = modbusCRC(request, 6); request[6] = crcVal & 0xFF; // CRC低字节 request[7] = crcVal >> 8; // CRC高字节 Serial.write(request, 8); // 假设用Serial发送到E32模块 }
- 匹配串口参数:确保E32、E95-DTU、传感器的串口参数完全一致:波特率(通常9600)、数据位8、停止位1、无奇偶校验。
- 检查透明传输配置:确认E32和E95-DTU都开启透明传输模式,不要开启协议转换功能,避免模块篡改Modbus帧结构。
- 硬件排查:确认串口接线为交叉连接(TX接RX,RX接TX),电源供电稳定,避免信号干扰导致帧损坏。
内容的提问来源于stack exchange,提问作者Mehmet
相关产品推荐
相关产品推荐

