CRC相关

来源:互联网 发布:交大知行大厦九层 编辑:程序博客网 时间:2024/06/05 17:43

循环冗余校验码的软件实现  
   
   
    在远距离数据通信中,为确保高效而无差错地传送数据,必须对数据进行校验即差错控制。循环冗余校验CRC(Cyclic   Redundancy   Check)是对一个传送数据块进行校验,是一种高效的差错控制方法。  
   
  1 循环冗余校验码原理  
   
    CRC校验采用多项式编码方法,如一个8位二进制数(B7B6B5B4B3B2B1B0)可以用7阶二进制码多项式B7X7+B6X6+B5X5+B4X4+B3X3+B2X2+B1X1+B0X0表示。  
    例如11000001可表示为  
    1X7+1X6+0X5+0X4+0X3+0X2+0X1+0X0  
    一般说,n位二进制数可用(n-1)阶多项式表示。它把要发送的数据位串看成是系数只能为“1”或“0”的多项式。一个n位的数据块可以看成是从Xn-1到X0的n项多项式的系数序列,位于数据块左边的最高位是Xn-1项的系数,次高位是Xn-2项的系数,依此类推,位于数据块右边的最低位是X0项的系数,这个多项式的阶数为n-1。  
    多项式乘除法运算过程与普通代数多项式的乘除法相同。多项式的加减法运算以2为模,加减时不进、错位,如同逻辑异或运算。  
    采用CRC校验时,发送方和接收方事先约定一个生成多项式G(X),并且G(X)的最高项和最低项的系数必须为1。设m位数据块的多项式为M(X),生成多项式G(X)的阶数必需比M(X)的阶数低。CRC校验码的检错原理是:发送方先为数据块生成CRC校验码,使这个CRC校验码的多项式能被G(X)除尽,实际发送此CRC校验码;接收方用收到的CRC校验码除以G(X),如果能除尽,表明传输正确,否则,表示有传输错误,请求重发。  
    生成数据块的CRC校验码的方法是:  
    (1)   设G(X)为r阶,在数据块末尾添加r个0,使数据块为m+r位,则相应的多项式为XrM(X);  
    (2)   以2为模,用对应于G(X)的位串去除对应于XrM(X)的位串,求得余数位串;  
    (3)   以2为模,从对应于XrM(X)的位串中减去余数位串,结果就是为数据块生成的带足够校验信息的CRC校验码位串。  
    例如,设要发送的数据为1101011011,G(X)=X4+X+1,则首先在发送数据块的末尾加4个0,得到11010110110000,然后用G(X)的位串10011去除,再用11010110110000减去余数位串1110,得到的即为CRC位串11010110111110,将对应多项式称为T(X),显然,T(X)能被G(X)除尽。这样,一旦接收到的CRC位串不能被同样的G(X)的位串除尽,那么一定有传输错误。  
    当使用CRC校验码进行差错控制时,除了为G(X)的整数倍的差错多项式不能被检测外,其它差错均能被查出。CRC校验码的差错控制效果取决于G(X)的阶数,阶数越高,效果越好。目前,常用的有两种生成多项式G(X)的方法,分别是:  
    CRC-16  X16+X15+X2+1  
    CCITT  X16+X12+X5+1  
    CRC校验码实际上是一种线性码,将任意CRC校验码循环移位后仍然是一个CRC校验码。由于它有良好的结构,检错能力强,易于实现硬件编、译码,因此在数据通信系统中得到广泛的应用。  
   
  2 CRC校验码生成和校验程序  
   
    对于某些不宜用硬件实现CRC校验而又需要用CRC校验码进行差错控制的系统中,须用软件方法实现CRC校验,即实现编码、检错和译码功能。  
    从CRC校验码编码规则可以看出,CRC校验码实际上是由原始数据位串和紧跟其后的与G(X)位串等长的冗余位串组成,只要求出此冗余位串,发送方即可将原始数据和冗余位串装配成一CRC位串序列后再发送。CRC校验码译码非常简单,只需从接收到正确CRC校验码尾部截掉与G(X)位串等长冗余位串,余下的部分即为原始数据位串。CRC校验码错误检测按模2除法运算,用接收到的CRC位串除以G(X)位串,看是否能够除尽即可确定。  
    下面的C语言模块实现了CRC校验码编码和检错功能,程序中的G(X)使用CRC-16,相应的位串为1100000000000101,用十六进制表示为0xc005。函数CrcGen以待发送的原始数据缓冲区地址和缓冲区长度(字节数)为入口参数,产生并返回遵循CRC校验码编码规则的且与G(X)位串等长的2字节冗余位串。函数CrcErr以接收到的CRC校验码缓冲区地址和缓冲区长度(字节数)为入口参数,返回CRC校验结果,若有错,返回1(真),否则,返回0(假)。函数代码如下:  
    unsigned   short   crcgen(unsigned   char*   databuf,short   len)  
    {  
       register   unsigned   short   crc=0,ch,i;  
       unsigned   short   gx=0xc005;  
       while(--len>=0)  
       {  
        ch=*databuf++;ch<<=8;  
        for(i=0;i<8,i++)  
        {  
         crc<<=1;  
         if((ch&0x8000)!=0)crc|=1;  
         if(crc>=gx)crc∧=gx;  
         ch<<=1;  
        }  
      }  
      for(i=0;i<16;i++)  
      {  
        crc<<=1;  
        if(crc>=gx)crc∧=gx;  
       }  
      return(crc);  
      }  
      int   crcerr   (unsigned   char*crcbuf,short   len)  
      {  
       register   short   short   crc=0,ch,i;  
       unsigned   short   gx=0xc005;  
       while(--len>=0)  
       {  
        ch=*crcbuf++;ch<<=8;  
        for(i=0;i<8;i++)  
        {  
         crc<<=1;  
         if((ch&0x8000)!=0)crc|=1;  
         if(crc>=gx)crc∧=gx;  
         ch<<=1;  
        }  
       }  
       return((crc==0)?0∶1)  
      }  
    以上CRC编码和校验函数结构良好,调用接口清晰,执行效率很高,且具有良好的可移植性。需使用CRC校验码机制的通信软件,均可调用这两个函数高效地实现CRC校验码软件编码和校验功能。