crc校验原理
CRC 校验(Cyclic Redundancy Check),又被称为循环几余校验是一种常见的数据校验技术。它是一种利用数学算法检查数据传输或存储是否被破坏的方法。
CRC 校验能够检测出发生在传输过程中的错误,包括位级错误,比如漏发或乱序,以及字节级错误,比如丢失或添加字节等。这种技术可以检测出大多数传输错误,但无法检测出所有的错误。
CRC 校验的工作原理是: 首先,对要发送的数据进行编码,将其转换成一组多项式;然后,在发送的数据中添加一个校验码,也就是CRC 码;最后,在接收方收到数据后,校验收到的 CRC 码是否正确。如果收到的 CRC 码和发送方计算出来的结果一致,则说明数据没有被破坏;如果不一致,则说明数据错误,可能已经损坏。
CRC 校验是一种非常有效的数据校验技术,它可以检测出大多数的传输错误,同时又不会消耗太多的计算资源。因此,它被广泛应用到各种需要传输或存储数据的系统中,可以大大提高数据传输的稳定性和安全性。
crc8与crc16、crc32的区别
crc8就是8位校验,多项式的最高位为8,与crc16、crc32最大的不同就是多项式最高位不同,也就是说,在校验的本质就是除以多项式。本文重点介绍crc8校验。
多项式
上文所说,校验的本质就是做除法,实际运算过程中,就是把数据与多项式就是异或(xor),异或的运算是相同为0,不同为1。
多项式的可以自定义,也可以用标准的,所谓的标准就是某些公司,或者大厂通常使用的一种校验多项式,但是crc8多项式必须遵循一个标准,最高位必须为1,即x8为1,还有最低为1也就是x0为1。在遵循上面的条件下,多项式是可以自定义。
有些时候我么们会遇到某些文档中多项式表达为0x131,那x8+x5+x4+1为什么可以表示为0x131或者为(0x31)?两者是怎么换算的呢?
我们可以这样看:
比如0x131,换成二进制数为0001 0011 0001 四位二进制数表示一个16进制数,所以就是0x131
如果给出为x8+x5+x4+1,我们可以这样换算,x8就是最高位为1,x5第5位位1,同理第四位为1,最后一位1,即是表示x的0位为1,我们从高到低排出,即为1 0011 0001,所以用16进制表示就是0x131
那为什么0x131可表示为0x31
这个是因为在crc8运算过程中,多项式的最高为都为 1,并且在代码的 crc8 计算中,最高位也是不使用的, 所以在多项式记录时都去掉了最高位。
顺序异或与反序异或
1、对于数据高位先传的方式,XOR 从数据的高位开始,我们就叫它顺序异或;
2、对于数据低位先传的方式,XOR 从数据的低位开始,我们就叫它反序异或。
3、两种不同的异或方式, 即使对应相同的多项式,计算出来的结果也是不一样的。
计算步骤
下面讲顺序异或
使用多项式:x8+x5+x4+1(二进制为:100110001)
1、计算一个字节
:0x11(二进制为:00010001), 因为采用顺序异或,所以需要计算的数据左移 8
位, 移位后数据为:0001 0001 0000 000 ;
先进行高 9bit 异或(多项式为 9bit),0001 0001 0000 0000,因为高 9bit 的 最高 bit 为 0,不需要进行异或,同理,接下来的两 bit 也是 0,也不需要进行异或, 这样处理后数据为:1 0001 0000 0000;接下来最高位为1,需要进行异或!
(bit7 以前的位数为 0 了,异或结束,所以结果为 0x72)
从上面的计算过程可以看到,多项式最高位为 1,遇到需要异或数据最高位为 1 时,才进行异或计算,
并且异或后,最高位就为 0 了,最高位为 0,下次也不需要异或了,这样需要采用代码计算的方式,
就可以把最高位去掉,不需要异或,最后结果也是一样的。
代码实现过程
同样我们可以利用在线工具:http://www.ip33.com/crc.html计算一下:
同样结果是0x72,所以计算正确!
对于上面的计算过程,采用代码实现的方式如下:
unsigned char cal_table_high_first(unsigned char value){
unsigned char i, crc;
crc = value;
/* 数据往左移了 8 位,需要计算 8 次 */
for (i=8; i>0; --i) {
/* 判断最高位是否为 1 */
if (crc & 0x80) {
/* 最高位为 1,不需要异或,往左移一位,然后与 0x31 异或 */
/* 0x31(多项式:x8+x5+x4+1,100110001),最高位不需要异或,直接去掉 */
crc = (crc << 1) ^ 0x31;
} else {
crc = (crc << 1); /* 最高位为 0 时,不需要异或,整体数据往左移一位 */
}
}
return (crc);
}
2、多字节 CRC 校验代码
上面的代码是计算一个字节数据的 crc 结果,如果是计算多个字节的 crc 结果,先计算第一个字节的crc 结果,然后把第一个字节的 crc 结果与第二个字节进行异或, 异或后的值再进行一次 crc 计算就可以了,多个字节也是循环计算;
多个字节的 crc 校验代码:
unsigned char crc_high_first(unsigned char *ptr, unsigned char len)