Modbus RTU CRC计算异常:PIC程序结果与在线模拟器不符
排查Modbus CRC计算结果不符的问题
我帮你梳理下这段代码里的问题,你现在遇到的CRC结果和在线模拟器对不上的情况,大概率是核心逻辑缺失和细节处理不到位导致的,咱们一步步来修正:
原代码里的关键问题
- 核心移位判断逻辑未完成:你代码里的
if...后面没写完,这是Modbus CRC计算的核心步骤——每次移位后如果最低位是1,必须异或多项式,这部分缺失肯定会导致结果错误。 - 固定循环次数为14:Modbus CRC是根据传入的消息长度来计算的,硬写14次只会适配特定长度的帧,大部分场景下结果都会错。
- 冗余变量干扰:代码里定义了
data[14]但没用到,容易混淆逻辑,建议删掉。 - 字节序处理缺失:最后输出CRC时没考虑Modbus协议的字节序要求(低字节在前),这也是很多人和在线工具对不上的常见原因。
修正后的完整代码
void CalculateModbusCRC(unsigned char *msg, unsigned int msgLen, unsigned char *out) { unsigned int crc = 0xFFFF; // Modbus CRC-16的固定初始值 const unsigned int poly = 0xA001; // 标准Modbus CRC多项式(0x8005的位反转) // 遍历消息的每个字节 for (unsigned int i = 0; i < msgLen; i++) { crc ^= msg[i]; // 当前字节与CRC寄存器先异或 // 处理当前字节的每一位 for (unsigned int j = 0; j < 8; j++) { // 检查CRC寄存器的最低位是否为1 if (crc & 0x0001) { crc >>= 1; // 右移一位 crc ^= poly; // 最低位为1时,异或多项式 } else { crc >>= 1; // 最低位为0时,直接右移 } } } // Modbus协议要求CRC低字节在前,高字节在后 out[0] = (unsigned char)(crc & 0xFF); // 提取CRC的低8位 out[1] = (unsigned char)(crc >> 8); // 提取CRC的高8位 }
关键细节说明
- 消息长度传入:现在函数需要你传入消息的实际长度
msgLen,这样不管是6字节的读寄存器帧还是更长的帧,都能正确计算。 - 多项式选择:
0xA001是Modbus专用的CRC-16多项式,它是标准CRC多项式0x8005的位反转,因为Modbus采用反向CRC算法,必须用这个值才能和在线工具匹配。 - 字节序处理:在线模拟器输出的CRC通常是低字节在前的格式(比如测试帧
0x01 0x03 0x00 0x00 0x00 0x01的正确CRC是0x84 0x0A),所以我们把CRC的低8位放在输出数组的第一个位置,高8位放第二个位置。
你可以用上面的测试帧来验证修正后的代码,应该就能和在线模拟器的结果一致了。
内容的提问来源于stack exchange,提问作者user7331387
相关产品推荐
相关产品推荐

