CRC校验总结

CRC校验总结

一.CRC校验的介绍:

1.  CRC全称:Cyclic Redundancy Check(循环冗余校验)。

CRC简介:在发送端,先把数据划分为组,假定每组k个比特(发送端每次发送一个数据包,就是上面说的组,假设每个数据包长度为k个bit)。
现假定待传送的数据m=101001(k=6),CRC运算就是在数据m的后面添加供差错检测用的n位冗余码(R)(这n位冗余码是按着一定规则计算出来的校验码, 假设这个运算规则是表达式g(x)),然后构成帧发送出去,一共发送(k+n)位.在所要发送的数据后面增加n位的冗余码,虽然增大了数据传输的开销,但是可以进行差错检测。当传输可能出现差错时,付出这种代价是值得的。我们接收到数据后从数据中截取数据m和冗余码(校验码)。然后我们也对m按照运算规则(g(x))做运算,计算的结果和校验码相比较,若二者相同表示数据接收正确,否则接收的是错误数据。

冗余码的生成规则:

这n位冗余码可以用以下方法得出:

用二进制的模2运算进行2^n乘m的运算,这相当于在n后面添加n个0(也就是m<<n)。得到的(k+n)位的数除以收发双方事先商定的长度为(n+1)位的除数g(x),得出商是Q,而余数是R(正好n位,)而这个余数就作为冗余码拼接在数据M的后面发送出去。假设除数是g(x)的值是1101,则商就是Q=110101,而余数就是R=001。

除数g(x)介绍:

   g(x)是一个多项式,CRC校验常用的多项式有:

 CRC8=X8+X5+X4+1 (数字为X的幂,X8是8个X向乘)
  CRC-CCITT=X16+X12+X5+1
  CRC16=X16+X15+X5+1          
  CRC12=X12+X11+X3+X2+1
  CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1    
每个多项式都对应一个值,例如CRC8=1*X8+0*X7+0*X6+1*X5+1*X4+0*X3+0*X2+0*X+1*X0;所以CRC8所对应的值为:100110001(多项式的各个式的系数)。

3.计算实例:信息码(数据类似m)=1011,左移8位后:1011 0000 0000,g(x) X^8+X^5+X^4+1,对应值:1001 1000 1

扫描二维码关注公众号,回复: 1143837 查看本文章

1011 0000 0000   (异或)

1001 1000 1

  10 1000 100

  10 0110 001 

     1110 1010

校验码:11101010

发送数据:1011 1110 1010

查表运算:

很多资料上都写了查表法来计算,最常用的是CRC16的查表计算:

B(X)=Bn(X)*2^8n+Bn-1(X)*2^8(n-1)+....+B1(X)*2^8+B0(X)

CRC16时候,上式两端还要乘以2^16,即左移16位。把繁琐的计算过程省略,其实只要记住本字节的CRC码等于上一字节的余式的CRC码的低8位左移8位后,再加上上一字节CRC右移8位(也就是取高8位)和本字节之和(异或)所求的的CRC码。但是我们不可能这样每部就去计算,单片机是承受不了的,而且占据大量任务,给实时通信打折扣。所以一般我们会把8位二进制序列数从0~255的CRC全部计算出来,放在表里,扔到EEPROM或者FLASH中固存。

Char crc_ta[256]={                // X16+X12+X5+1  余式表
    0x0000, 0x1021,  0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
     0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
     0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0,      0x0cc1,    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
     0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

byte[] buff= new byte[1024];

/*

为buff赋值,我项目中是从通讯端接收的数据

*/

private void check() {

      int index =0;

      char crc = 0;

      while(index<len){

          char date = (char) (crc/256);  // 截取crc中的高八位

        crc<<=8;    //左移8位,去除移动前的高八位

        crc^=crc_table[date^buff[index]&0xff];

        index++;

      // 下面的计算也可/*crc=(char)(crc_table[(crc>>8^buff[index]&0xff)]^(crc<<8));           index++;*/

      }

      System.out.println(Integer.toHexString(crc));

}

附加:

一.    Java中^运算,&运算

(1)    ^(异或运算)

运算规则:1^1=0;1^0=1;0^1=1;0^0=0;(相同为0,不同为1)

(2)    &(与运算)

运算规则:1^1=1;1^0=0;0^1=0;0^0=0;(都是1为1,否则是0)

二.Java中移位运算

移位运算是二进制运算,如00110左移移位:01100,由移移位00011;

3>>1=1;3<<1=6(先把非二进制转换成二进制在运算);

猜你喜欢

转载自blog.csdn.net/chenyu201003/article/details/53099846