1、CRC简介
CRC 是Cyclic Redundancy Check的缩写,循环冗余校验,用于校验数据传输的完整性。 一般情况下在数据发送前计算CRC校验值,附在发送数据之后,数据接收方也按照同样方法计算CRC,然后对比计算结果,如果一致说明数据数据传输无误,否则数据传输出错。
2、什么是模二运算
CRC计算采用二进制模二除法,来解释一下模二运算,模二运算忽略进位和借位,下面一一解释。
1)模二加法,类似异或运算
1+1=0 0+0=0
1+0=1 0+1=1
2)模二减法,类似异或运算
1-1=0 0-0=0
1-0=1 0-1=1
3)模二乘法
1×1=1 0×0=0
1×0=0 0×1=0
4)模二除法
模二除法和十进制除法类似,运用了模二乘法和模二减法,直接举例说明。
3、常见CRC模型如下:
不同的多项式计算方法不同,下面以CRC-5/EPC举例说明:
多项式公式 :x5 + x3 + 1
完整写出来是x5 + 0x4 + x3 + 0x2 + 0*x + 1
多项式 :取以上多项式中的系数101001为多项式,一般最高位不写出来,所以多项式是01001,即0x09
初始值 :运算的初始值,EPC要求是0x09
结果异或值 :所有数据计算完的结果与其异或,EPC这里是0
输入反转 :输入数据每字节高低位是否翻转,EPC不翻转。
输出反转 :输出结果高低位是否翻转,EPC不翻转。
4、手撕CRC
仍然以CRC-5/EPC举例,计算字节0xAA的CRC值,这是一个5位的CRC,使用模二除法,最终计算出5位CRC校验值。 被除数是0xAA,二进制10101010,除数是多项式,即101001。 计算过程如下图所示,为了表明计算过程把商为0的计算过程也写出来了。 这是5位CRC,只取最后5位,即10000。 输出结果不需要异或也不需要反转,所以10000就是计算结果。
两个字节AA55的CRC计算过程,同样为了表明计算过程把商为0的计算过程也写出来了。 这是5位CRC,只取最后5位,即01000。 输出结果不需要异或也不需要反转,所以01000就是计算结果。
再举一个例子,仍然计算0xAA的CRC。 这次采用模型CRC-5/USB,多项式:x5+x2+1,输入输出数据都反转,多项式0x05,初始值为0x1F,输出异或值为0x1F。 最终计算结果00111。
5、C语言实现
以下是CRC-5/EPC的C语言实现代码:
/*
* Name: CRC-5/EPC x5+x3+1
* Poly: 0x09
* Init: 0x09
* Refin: False
* Refout: False
* Xorout: 0x00
* Note:
*/
uint8_t crc5_epc(uint8_t *data, uint16_t length)
{
uint8_t i;
//初始值是0x09的低5位,要和输入数据的高五位异或
//所以0x09左移三位,00001001<<3 = 01001000 = 0x48
uint8_t crc = 0x48;
while(length--)
{
crc ^= *data++; //异或第一个字节
for ( i = 0; i < 8; i++ )
{
if ( crc & 0x80 )
{
//最高位是1,需要异或多项式,多项式是最高位为1的6bit
//多项式异或后最高位为0,所以这里不异或最高位了,他肯定是0
//直接把crc左移1位,去掉最高位,然后异或多项式的低5bit
//多项式是0x09<<3 = 00001001<<3 = 01001000 = 0x48
crc = (crc << 1) ^ 0x48; // 0x48 = 0x09<<(8-5)
}
else
{
//最高位是0,所以商为0,可以省去运算,见上面图表,因为和0异或值不变。
crc <<= 1;
}
}
}
return crc >> 3; //计算完成后结果在高5位,右移动3位。
}
全部0条评论
快来发表一下你的评论吧 !