单片机上用C++做CRC校验的核心是规避C++高级特性,采用纯C风格函数接口、查表法和手动内存管理;CRC8查表法因耗时仅约1次查表+1次异或(

单片机上用 C++ 做 CRC 校验,核心不是“能不能用 C++”,而是“别被 C++ 语法带偏了硬件限制”——绝大多数单片机(尤其 Cortex-M0/M3、8051、AVR)没有 STL、不支持异常、不能动态分配内存,std::vector 和 std::string 基本是摆设。真正能落地的,是纯 C 风格的函数接口 + 查表法 + 手动内存管理。
CRC8 查表法:为什么必须用查表,而不是逐位计算
在资源紧张的单片机(比如 STM32F030、nRF52832、ESP32-C3)上,逐位计算 crc8 每字节要跑 8 轮移位+条件异或,耗时约 40–60 个周期;而查表法只要一次查表 + 一次异或,通常
- 查表数组必须声明为
static const uint8_t crc8_table[256],确保编译进 Flash,不占 RAM - 多项式选错会导致结果完全对不上协议:SMBus 用
0x07,1-Wire 用0x31,SD 卡命令校验用0x09,不能混用 - 输入是否反转(
refIn)直接影响查表逻辑:若协议要求输入字节反转(如某些 TI 传感器),你得先调reflect_byte(*data)再查表,否则表再准也没用
CRC16-Modbus:初始值、多项式、字节序三者缺一不可
crc16_modbus 最常出错的地方不是算法,而是参数组合错位。Modbus-RTU 明确规定:polynomial = 0x8005、init = 0xFFFF、refIn = true、refOut = true、xorOut = 0x0000。漏掉任意一个,和从设备通信就直接超时。
- 查表法需两个 256 项表:
crc16_hi_table[256]和crc16_lo_table[256](常见于老式实现),或更简洁的单表uint16_t crc16_table[256],后者查表时用crc = crc16_table[(crc >> 8) ^ *data] ^ (crc - 别信“高位在前/低位在前”的模糊说法——Modbus 要求的是“输入字节按位反转 + 输出结果按位反转”,不是“发送时高低字节交换”。交换字节是最后一步封装,不是 CRC 计算逻辑
- 测试向量必须用标准串
"123456789":正确结果是0x4B37(高位字节 0x4B,低位 0x37),如果得到0x374B,说明你忘了反转输出或字节序颠倒
CRC32 硬件校验:STM32 的 CRC 外设只认一种模式
STM32F4/F7/H7 的硬件 CRC 外设(CRC_HandleTypeDef)默认只支持 IEEE 802.3 模式:polynomial = 0x04C11DB7、init = 0xFFFFFFFF、refIn = false、refOut = false、xorOut = 0xFFFFFFFF。它**不支持 Modbus 或 ZIP 那套参数**,强行配会返回错误值。
立即学习“C++免费学习笔记(深入)”;
- 启用前必须调
__HAL_RCC_CRC_CLK_ENABLE(),否则寄存器读写全为 0 - 硬件 CRC 输入是 32 位字,但你的数据通常是字节数组:需手动按 4 字节对齐填充,末尾不足补 0,并记录真实长度,否则校验值错
- 如果协议要求的是反向多项式(如
0xEDB88320),硬件外设无解,只能切回软件查表——别试图用 HAL 函数硬改,底层寄存器不开放这些位
最易被忽略的一点:CRC 计算前后,数据缓冲区是否被意外修改?尤其用指针遍历 + 自增(data++)时,若传入的是栈上临时数组地址,而函数内又做了越界读(比如没检查 length == 0),结果会随机波动。建议所有 CRC 函数入口加 assert(data != nullptr && length > 0),哪怕只是调试时打开。


















