CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则(例如是CRC-4、CRC-8、CRC-16、CRC-CCITT、CRC-32等标准)产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。 表1 下表中列出了一些见于标准的CRC资料:
* 生成多项式的最高幂次项系数是固定的1,故在简记式中,将最高的1统一去掉了,如04C11DB7实际上是104C11DB7。** 前称CRC-CCITT。ITU的前身是CCITT。 先举个简单的例子,以CRC-4标准为例,说明CRC编码过程。 设待发送的数据t(x)为12位的二进制数据100100011100;CRC-4的生成多项式为g(x)=x^4+x+1,阶数r为4,即10011(生成多项式中x用1表示)。首先在t(x)的末尾添加4个0构成x^4*t(x),即是左移4位(CRC-16就是左移16位),此后,待发送的数据块变为1001000111000000。然后用g(x)(其值为10011)去除x^4*t(x)(左移4位后的待发送数据)【实际是XOR异或运算,不是除法】,不管商是多少,只需要求得余数y(x),即为待发送数据对应的CRC值。 下表为给出的除法过程:
最后的4位的余数就是待发送数据对应的CRC-4编码。从上面表中可以看出,CRC 编码实际上是一个循环移位的模 2 运算。对 CRC-4,我们假设有一个 5 bits 的寄存器,通过反复的移位和进行 CRC的除法,那么最终该寄存器中的值去掉最高一位就是我们所要求的余数。所以可以将上述步骤用下面的流程描述: //reg 是一个 5 bits 的寄存器 常见的CRC校验法有3种,直接计算法,查表法,半查表法。下面是几种CRC16的C语言代码,自己理解分析一下 首先是WINAVR中的crc16.h中的库函数(路径在C:\WinAVR-20090313\avr\include\util\crc16.h) //Optimized CRC-XMODEM calculation. //Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)<br> //This is the CRC used by the Xmodem-CRC protocol. //code crc = crc ^ ((uint16_t)data << 8); return crc; 但我觉得WINAVR中的Xmodem-CRC标准与很多文章说的CRC-CCITT好像是一致的, //Optimized CRC-CCITT calculation. //Polynomial: x^16 + x^12 + x^5 + 1 (0x8408)<br>
//This is the CRC used by PPP and IrDA. //See RFC1171 (PPP protocol) and IrDA IrLAP 1.1 // \note Although the CCITT polynomial is the same as that used by the Xmodem //以上一段话说明了CCITT与Xmodem 的CRC校验的不同点。 // The following is the equivalent functionality written in C. \code return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4) 不知道上面哪个才是我们说的CRC-CCITT,不过我个人认为其实是哪种CRC校验没所谓,关键是发送端与接收端用同一种CRC校验就可以了。 下面是网上比较多见的CRC-CCITT校验源码。 typedef unsigned char uchar; uint crc16l(uchar *ptr,uchar len) // ptr 为数据指针,len 为数据长度
具体应用的编程思路: 另外,其实应用CRC校验,关键的是编写发送端的计算CRC码,及在待发送数据后添加CRC码的函数。至于用哪种CRC标准,是CRC-CCITT,还是CRC-8等要看具体的应用,另外高效的代码也是要考虑的,毕竟用在单片机系统中,是用计算法、查表法、半查表法,需要兼顾代码运行时间或程序空间两方面。 |
联系客服