Arduino,stm32的crc16校验计算源码,支持crc16/modbus,自定义等功能
撸代码的兄弟肯定都遇到过数据校验的问题,尤其是玩嵌入式开发的时候。注意那个异或操作——初始值0xFFFF是Modbus的特色,要是玩别的协议记得改初始值。那个0xA001其实是0x8005按位反转后的结果,别傻乎乎直接用标准多项式,会翻车。要是出问题,先检查字节顺序——Modbus是低位在前高位在后,别搞反了。Arduino,stm32的crc16校验计算源码,支持crc16/modbus,自定义
Arduino,stm32的crc16校验计算源码,支持crc16/modbus,自定义等功能。
撸代码的兄弟肯定都遇到过数据校验的问题,尤其是玩嵌入式开发的时候。今天咱们来聊聊CRC16校验在Arduino和STM32上的花式操作。别被那些复杂的数学公式吓到,直接上能跑的真代码。
先扔个查表法的实现镇场子:
const uint16_t crc16_table[] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
//...完整表太长,自己生成或找现成的
};
uint16_t crc16_calculate(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
while(len--) {
crc = (crc >> 8) ^ crc16_table[(crc ^ *data++) & 0xFF];
}
return crc;
}
这段代码的精髓在查表加速。注意那个异或操作——初始值0xFFFF是Modbus的特色,要是玩别的协议记得改初始值。每次处理一个字节直接查表,比硬算快十倍不止。
想要支持Modbus协议?加点料:
uint16_t crc16_modbus(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for(uint16_t i=0; i<len; i++){
crc ^= data[i];
for(int j=0; j<8; j++){
if(crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001; // 0x8005反转后的多项式
} else {
crc >>= 1;
}
}
}
return crc;
}
这里用了逐位计算的方式,注意多项式被反转了(Modbus标准操作)。那个0xA001其实是0x8005按位反转后的结果,别傻乎乎直接用标准多项式,会翻车。
Arduino,stm32的crc16校验计算源码,支持crc16/modbus,自定义等功能。
玩STM32的兄弟可以试试硬件CRC外设:
uint16_t stm32_crc16(uint8_t *data, uint32_t len) {
CRC->CR |= CRC_CR_RESET; // 复位寄存器
for(uint32_t i=0; i<len; i++){
*((__IO uint8_t *)&CRC->DR) = data[i]; // 字节写入
}
return (CRC->DR & 0xFFFF) ^ 0xFFFF; // Modbus需要异或
}
F4系列实测能用,但注意硬件CRC的多项式可能和标准不同。这里最后那个异或0xFFFF就是用来适配Modbus的特殊处理,不用硬件加速的话可以删掉。
自定义参数才是真需求:
typedef struct {
uint16_t poly;
uint16_t init;
bool refin;
bool refout;
uint16_t xorout;
} CRC16_Config;
uint16_t custom_crc16(uint8_t *data, uint16_t len, CRC16_Config cfg) {
uint16_t crc = cfg.init;
while(len--) {
uint8_t c = *data++;
if(cfg.refin) c = __RBIT(c) >> 24; // 位反转
crc ^= (c << 8);
for(int i=0; i<8; i++){
crc = (crc & 0x8000) ? (crc << 1) ^ cfg.poly : (crc << 1);
}
}
if(cfg.refout) crc = (crc << 8) | (crc >> 8); // 字节反转
return crc ^ cfg.xorout;
}
这个模板够你玩转各种魔改CRC了。RBIT是STM32的指令级位反转,其他平台可以自己实现。注意多项式方向——左移还是右移决定了计算方向。
实测数据验证很重要:
void test() {
uint8_t test_data[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02};
// Modbus CRC16应该返回0xC40B
uint16_t crc = crc16_modbus(test_data, sizeof(test_data));
Serial.print("CRC16: 0x");
Serial.println(crc, HEX);
}
跑这个测试用例,如果串口打印出C40B,恭喜你算法写对了。要是出问题,先检查字节顺序——Modbus是低位在前高位在后,别搞反了。
最后提醒:查表法在STM32上能起飞,但Arduino空间吃紧的话还是用逐位计算。遇到校验失败别慌,八成是多项式方向或初始值没设对。收藏这几个代码片段,够应付大多数嵌入式项目的校验需求了。

更多推荐
所有评论(0)