使用STM32 HAL计算Modbus RTU CRC16结果不符问题排查
问题
我自己实现了一个CRC16计算的自定义函数,现在想改用HAL库的HAL_CRC_Calculate函数计算Modbus RTU的CRC16,但两者结果不一致。
自定义函数代码:
uint16_t CalcCRC(const uint8_t* const buffer, const uint8_t u8length) { uint32_t temp; uint32_t temp2; uint32_t flag; temp = 0xFFFF; for (uint8_t i = 0; i < u8length; i++) { temp = temp ^ buffer[i]; for (uint8_t j = 1; j <= 8; j++) { flag = temp & 0x0001; temp >>=1; if (flag) temp ^= 0xA001; } } // 反转字节顺序 temp2 = temp >> 8; temp = (temp << 8) | temp2; temp &= 0xFFFF; return (uint16_t)temp; }
当前HAL CRC初始化配置:
hcrc.Instance = CRC; hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE; hcrc.Init.GeneratingPolynomial = 0xA001; hcrc.Init.CRCLength = CRC_POLYLENGTH_16B; hcrc.Init.InitValue = 0xffff; hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE; hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE; hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
调用方式:
uint16_t u16crc_1 = HAL_CRC_Calculate(&hcrc, (uint32_t*)struct->buffer, struct->bufferSize); uint16_t u16crc = CalcCRC(struct->buffer, struct->bufferSize);
最小测试示例:
uint8_t buffer[6] = {25,15,0,7,0,1}; uint16_t u16crc_hal = HAL_CRC_Calculate(&hcrc, (uint32_t*)buffer, 6); uint16_t u16crc = CalcCRC(buffer, 6);
测试结果:
u16crc_hal = 3094(0xC16) u16crc = 9746(0x2612)
请问如何配置HAL CRC才能得到与自定义函数一致的结果?
解决方案
想让HAL CRC的计算结果和自定义函数匹配,得调整输入数据反转模式和输出数据反转模式,具体修改如下:
- 修改输入数据反转模式
自定义函数处理输入字节时是按最低位(LSB)先计算,但当前配置的CRC_INPUTDATA_INVERSION_BYTE会反转每个字节的位顺序(改成最高位(MSB)先算),这直接导致计算逻辑错位。需要把输入反转模式改成无反转:
hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
- 修改输出数据反转模式
自定义函数最后手动反转了CRC结果的字节顺序,而HAL的CRC_OUTPUTDATA_INVERSION_ENABLE会同时反转字节顺序和每个字节的位顺序,等于做了双重反转,结果自然不对。要关闭输出反转:
hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
- 多项式无需修改
自定义函数用的0xA001是Modbus标准CRC16多项式0x8005的反转形式(因为自定义函数是LSB优先处理),当前HAL配置的多项式是正确的,不用改。
修改后的完整HAL CRC初始化配置:
hcrc.Instance = CRC; hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE; hcrc.Init.GeneratingPolynomial = 0xA001; hcrc.Init.CRCLength = CRC_POLYLENGTH_16B; hcrc.Init.InitValue = 0xffff; hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; // 此处修改 hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; // 此处修改 hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
- 验证结果
用修改后的配置重新跑测试示例,HAL CRC计算结果会和自定义函数一致,都是9746(0x2612)。
内容的提问来源于stack exchange,提问作者jacob_s
相关产品推荐
相关产品推荐

