大家好,欢迎来到IT知识分享网。
一、定义
- CRC(Cyclic Redundancy Check):循环冗余检验;
- 多项式:例如有多项式y=x16+x12+x5+1,可用二进制表达为y=1 0001 0000 0010 0001;
- 模二除法:类似于“算数除法”,但无借位;如除以1110,结果得到商为11,余数为1,如图:
二、计算原理
- 确定多项式y;
- 将需要计算的数据x左移k-1位,得出x1;(k=多项式y的位数)
- 用模二除法,将数据x1除以多项式y;
- 计算的k-1位的余数即为数据x的CRC校验值;(计算的次数为数据x的位数)
如:多项式y=x4 + x3 + 1,计算数据的CRC校验值为0100;
三、基本算法(手算)
- 假设需要对3个字节的数据流(byte[0]、byte[1]、byte[2])做crc16计算;
- 数据流左移16位,变成:byte[0]、byte[1]、byte[2]、crc[0]、crc[1];
- 对40位数据做模二除法;
- 所得的16位余数为crc16的校验码;
效果类似于:
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 & 0x) {
crc_val = crc_val ^ ((poly | 0x10000) << 7); } else {
} crc_val <<= 1; } } crc_val >>= 8; //结果在高16位,所以要右移8位 return crc_val; }
四、计算机算法(比特型算法)
- 假设需要对3个字节的数据流(byte[0]、byte[1]、byte[2])做crc16计算;
- 数据流左移16位,变成:byte[0]、byte[1]、byte[2]、crc[0]、crc[1];
- 取数据流高16位数据(byte[0]、byte[1]),放到16位的寄存器中;
- 如果寄存器的最高位为1,则寄存器先左移一次(寄存器低位的值从下一个字节获得),再对寄存器和多项式做一次异或计算。否则则寄存器直接左移一次(寄存器低位的值从下一个字节获得);
为什么变成了先左移一次?如果不先左移,其实会发现如果数据流最高bit为1,最终最高1bit在每轮计算中结果都是0。因此数据流的最高bit其实不需要进行计算,直接右移就行。并且,这个方式需要忽略多项式的最高bit,本来是17位的多项式,只需要16位来表示,那么16位的寄存器刚好可以放下多项式的值。
- 如果数据流没有全部都移到寄存器,重复上一步;
- 最后得到的寄存器的值为crc16的校验码;
函数实现如下:
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/
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/123236.html