赞
踩
如:多项式y=x4 + x3 + 1,计算数据10110011的CRC校验值为0100;
效果类似于:
uint16_t get_crc16(uint8_t* buffer, uint16_t length) { uint32_t data, crc_val = 0; uint8_t i; while (length--) { data = *buffer++; crc_val ^= (data << 16); //异或的具体原因不清楚。猜测是为了将上一个字节的crc校验码承接下去 for (i = 0; i < 8; i++) { if (crc_val & 0x800000) { crc_val = crc_val ^ ((poly | 0x10000) << 7); } else {} crc_val <<= 1; } } crc_val >>= 8; //结果在高16位,所以要右移8位 return crc_val; }
为什么变成了先左移一次?如果不先左移,其实会发现如果数据流最高bit为1,最终最高1bit在每轮计算中结果都是0。因此数据流的最高bit其实不需要进行计算,直接右移就行。并且,这个方式需要忽略多项式的最高bit,本来是17位的多项式,只需要16位来表示,那么16位的寄存器刚好可以放下多项式的值。
函数实现如下:
uint16_t get_crc16(uint8_t* buffer, uint16_t length) { uint32_t data, crc_val = 0; uint8_t i; while (length--) { data = *buffer++; crc_val ^= (data << 8); for (i = 0; i < 8; i++) { if (crc_val & 0x8000) { crc_val = (crc_val << 1) ^ poly; } else { crc_val <<= 1; } } } return crc_val; }
加入输入翻转、输出翻转、输出异或、初始值后的函数实现:
uint32_t get_ref(uint32_t num, uint8_t bit) { uint32_t ret = 0; for (uint8_t i = 0; i < bit; i++) { if (num & 0x01) { ret |= (0x01 << (bit - i - 1)); } else {} num >>= 1; } return ret; } uint16_t get_crc16(uint8_t* buffer, uint16_t length) { uint16_t data, crc_val = init; //初始值 while (length--) { data = *buffer++; if (ref_in) { data = get_ref(data, 8); //计算输入翻转 } else {} crc_val ^= (data << 8); for (uint8_t i = 0; i < 8; i++) { if (crc_val & 0x8000) { crc_val = (crc_val << 1) ^ poly; } else { crc_val <<= 1; } } } if (ref_out) { crc_val = get_ref(crc_val, 16); //计算输出翻转 } else {} crc_val ^= xor_out; //计算输出异或 return crc_val; }
部分内容参考于:
https://blog.csdn.net/ydyuse/article/details/105395368
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。