CRC-16原理及通用的16位CRC校验算法代码

 

循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC。它是利用除法及余数的原理来作错误侦测(Error Detecting)的。实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的数据重新计算CRC并与收到的CRC相比较,若两个CRC值不同,则说明数据通讯出现错误。

 

根据应用环境与习惯的不同,CRC常用的一些标准如下:

CRC-4/ITU  

CRC-5/EPC CRC-5/ITU CRC-5/USB

CRC-6/ITU

CRC-7/MMC

CRC-8 CRC-8/ITU CRC-8/ROHC CRC-8/MAXIM

CRC-16/IBM CRC-16/MAXIM CRC-16/USB CRC-16/MODBUS CRC-16/CCITT CRC-16/CCITT-FALSE 

CRC-16/X25 CRC-16/XMODEM CRC-16/DNP

CRC-32 CRC-32/MPEG-2等

 

CRC-16及CRC-CCITT码则用是来传送8-bit字符,其中CRC-16为美国采用,而CRC-CCITT为欧洲国家所采用。CRC-32码大都被采用在一种称为Point-to-Point的同步传输中。

 

CRC-16检验码的生成过程描述

 

CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码进行异或,否则如果 LSB为零,则无需进行异或。重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。

任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。常用的CRC16-CCITT多项式为x16+x12+x5+1,0x1021二进制为10001000000100001。生成多项式的最高位固定的1,故在简记式中忽略最高位1了,如0x1021实际是0x11021。多项式需要满足:

  • 最高位和最低位都是1

  • 当被传送信息任何一位发生错误时,P(X)不被T(X)整除

  • 不同位发生错误时,余数应该不同

  • 对余数继续做模二除法时,应该使余数循环

标准CRC生成多项式见文末附表。

I、基本算法(人工笔算):

 

   以CRC16-CCITT为例进行说明,CRC校验码为16位,生成多项式17位。假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];

数据流左移16位,相当于扩大256×256倍,再除以生成多项式0x11021,做不借位的除法运算(相当于按位异或),所得的余数就是CRC校验码。

发送时的数据流为6字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0]、CRC[1]、CRC[0];

 

II、计算机算法1(比特型算法):

 

1)将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;

2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;

    否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);

3)重复第2步,直到数据流(6字节)全部移入寄存器;

4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。

 

III、计算机算法2(字节型算法):256^n表示256的n次方

 

    把按字节排列的数据流表示成数学多项式,设数据流为BYTE[n]BYTE[n-1]BYTE[n-2]、、、BYTE[1]BYTE[0],表示成数学表达式为BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]*256+BYTE[0],在这里+表示为异或运算。设生成多项式为G17(17bit),CRC码为CRC16。

    则,CRC16=(BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]×256+BYTE[0])×256^2/G17,即数据流左移16位,再除以生成多项式G17。

    先变换BYTE[n-1]、BYTE[n-1]扩大后的形式,

    CRC16=BYTE[n]×256^n×256^2/G17+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

         =(Z[n]+Y[n]/G17)×256^n+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

         =Z[n]×256^n+{Y[n]×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

         =Z[n]×256^n+{(YH8[n]×256+YHL[n])×256/G17+BYTE[n-1]×256^2/G17}×256^(n-  1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

         =Z[n]×256^n+{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

    这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y[n]的高8位(YH8[n])与本字节BYTE[n-1]异或,

 

     该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y[n]的低8位(YL8[n])乘以256(即左移8位)异或。然后依次逐个字节求出CRC,直到BYTE[0]。

 

    字节型算法的一般描述为:本字节的CRC码,等于上一字节CRC码的低8位左移8位,与上一字节CRC右移8位同本字节异或后所得的CRC码异或。  

    字节型算法过程如下:

       1)CRC寄存器组初始化为全"0"(0x0000)。(注意:CRC寄存器组初始化全为1时,最后CRC应取反。)

       2)CRC寄存器组向左移8位,并保存到CRC寄存器组。

       3)原CRC寄存器组高8位(右移8位)与数据字节进行异或运算,得出一个指向值表的索引。

       4)索引所指的表值与CRC寄存器组做异或运算。

       5)数据指针加1,如果数据没有全部处理完,则重复步骤2)。

       6)得出CRC。

查表算法代码示例:

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

/***********************************************************
CRC16 Coding & Decoding G(X) = X^16+X^12+X^5+1
***********************************************************/
quint16 CRC_Calculate::CRC16_cal(quint8 *ptr, quint32 len, quint16 crc_init)
{
    quint16 crc,   oldcrc16;
    quint8  temp;
    crc = crc_init;
    while (len--!=0)
    {
        temp=(crc>>8)&0xff;
        oldcrc16=crc16_tab[*ptr^temp];
        crc=(crc<<8)^oldcrc16;
        ptr++;


    }

    return(crc);
}

通用的16位CRC校验算法

   CRC16标准算法很多,一般不同多项式对应不同表,不同的算法有不同的函数,这样不太方便,下面给出一个通用函数

quint16 CRC_Normal::calculate_crc16(quint16 wCRCin,quint16 wCPoly,quint16 wResultXOR,bool input_invert,bool ouput_invert,const char *puchMsg, int usDataLen)
{
    quint8 wChar = 0;
    while (usDataLen--)
    {
        wChar = *(puchMsg++);
        if(input_invert)//输入值反转
        {
            quint8 temp_char = wChar;
            wChar=0;
            for(int i=0;i<8;++i)
            {
                if(temp_char&0x01)
                    wChar|=0x01<<(7-i);
                temp_char>>=1;
            }
        }
        wCRCin ^= (wChar << 8);
        for (int i = 0; i < 8; i++)
        {
            if (wCRCin & 0x8000)
                wCRCin = (wCRCin << 1) ^ wCPoly;
            else
                wCRCin = wCRCin << 1;
        }
    }
    if(ouput_invert)
    {
        quint16 temp_short = wCRCin;
        wCRCin=0;
        for(int i=0;i<16;++i)
        {
            if(temp_short&0x01)
                wCRCin|=0x01<<(15-i);
            temp_short>>=1;
        }
    }
    return (wCRCin^wResultXOR);
}

 

使用示例

CRC-16/CCITT由本函数实现则填充参数如下:

      calculate_crc(0,0x1021,0,true,true,puchMsg,usDataLen)

其它使用情况参数参考下表

比如计算CRC-16/MODBUS:

    calculate_crc(0xffff,0x8005,0,true,true,puchMsg,usDataLen)

上述查表算法对应的调用是:

   calculate_crc(0,0x1021,0,false,false,puchMsg,usDataLen)

CRC算法名称多项式公式宽度多项式初始值结果异或值输入反转输出反转
CRC-4/ITUx4 + x + 14030000truetrue
CRC-5/EPCx5 + x3 + 15090900falsefalse
CRC-5/ITUx5 + x4 + x2 + 15150000truetrue
CRC-5/USBx5 + x2 + 15051F1Ftruetrue
CRC-6/ITUx6 + x + 16030000truetrue
CRC-7/MMCx7 + x3 + 17090000falsefalse
CRC-8x8 + x2 + x + 18070000falsefalse
CRC-8/ITUx8 + x2 + x + 18070055falsefalse
CRC-8/ROHCx8 + x2 + x + 1807FF00truetrue
CRC-8/MAXIMx8 + x5 + x4 + 18310000truetrue
CRC-16/IBMx16 + x15 + x2 + 116800500000000truetrue
CRC-16/MAXIMx16 + x15 + x2 + 11680050000FFFFtruetrue
CRC-16/USBx16 + x15 + x2 + 1168005FFFFFFFFtruetrue
CRC-16/MODBUSx16 + x15 + x2 + 1168005FFFF0000truetrue
CRC-16/CCITTx16 + x12 + x5 + 116102100000000truetrue
CRC-16/CCITT-FALSEx16 + x12 + x5 + 1161021FFFF0000falsefalse
CRC-16/X25x16 + x12 + x5 + 1161021FFFFFFFFtruetrue
CRC-16/XMODEMx16 + x12 + x5 + 116102100000000falsefalse
CRC-16/DNPx16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1163D650000FFFFtruetrue
CRC-32x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFFFFFFFFFFtruetrue
CRC-32/MPEG-2x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 13204C11DB7FFFFFFFF00000000falsefalse

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐