CRC8算法

CRC8算法

轉載至:https://blog.csdn.net/zjli321/article/details/52998468

1、 CRC8標準生成多項式

CRC-8       x8+x5+x4+1              0x31(0x131)
CRC-8       x8+x2+x1+1              0x07(0x107)
CRC-8       x8+x6+x4+x3+x2+x1       0x5E(0x15E)

注:由於多項式的最高爲都爲1,並且在代碼的crc8計算中,最高位也是不使用的, 
所以在多項式記錄時都去掉了最高位。

2、 CRC校驗算法,說白了,就是把需要校驗的數據與多項式進行循環異或(XOR), 
但進行XOR的方式與實際中數據傳輸時,是高位先傳、還是低位先傳有關。對於數據 
高位先傳的方式,XOR從數據的高位開始,我們就叫它順序異或吧;對於數據低位先 
傳的方式,XOR從數據的低位開始,我們就叫它反序異或吧。兩種不同的異或方式, 
即使對應相同的多項式,計算出來的結果也是不一樣的。 
下面以順序異或的例子說明一些計算的過程: 
使用多項式:x8+x5+x4+1(二進制爲:100110001) 
計算一個字節:0x11(二進制爲:00010001) 
計算步驟: 
A、 因爲採用順序異或,所以需要計算的數據左移8位, 
移位後數據爲:0001 0001 0000 000 
B、 先進行高9bit異或(多項式爲9bit),0001 0001 0000 0000,因爲高9bit的 
最高bit爲0,不需要進行異或,同理,接下來的兩bit也是0,也不需要進行進行異或。 
這樣處理後數據爲:1 0001 0000 0000; 
C、 接下來最高位爲1,需要進行異或操作了 
這裏寫圖片描述 
從上面的計算過程可以看到,多項式最高位爲1,遇到需要異或數據最高位爲1時, 
才進行異或計算,並且異或後,最高位就爲0了,最高位爲0,下次也不需要異或了, 
這樣需要採用代碼計算的方式,就可以把最高位去掉,不需要異或,最後結果也是一樣的。 
對於上面的計算過程,採用代碼實現的方式如下:

unsigned char cal_table_high_first(unsigned char value)
{
    unsigned char i, crc;

    crc = value;
    /* 數據往左移了8位,需要計算8次 */
    for (i=8; i>0; --i)
    { 
        if (crc & 0x80)  /* 判斷最高位是否爲1 */
        {
        /* 最高位爲1,不需要異或,往左移一位,然後與0x31異或 */
        /* 0x31(多項式:x8+x5+x4+1,100110001),最高位不需要異或,直接去掉 */
            crc = (crc << 1) ^ 0x31;        }
        else
        {
            /* 最高位爲0時,不需要異或,整體數據往左移一位 */
            crc = (crc << 1);
        }
    }

    return crc;
}
上面的代碼是計算一個字節數據的crc結果,如果是計算多個字節的crc結果,也是比較簡單

的,先計算第一個字節的crc結果,然後把第一個字節的crc結果與第二個字節進行異或, 
異或後的值再進行一次crc計算就可以了,多個字節也是反覆這過程就好,如下爲多個字節 
的crc校驗代碼:

unsigned char crc_high_first(unsigned char *ptr, unsigned char len)
{
    unsigned char i; 
    unsigned char crc=0x00; /* 計算的初始crc值 */ 

    while(len--)
    {
        crc ^= *ptr++;  /* 每次先與需要計算的數據異或,計算完指向下一數據 */  
        for (i=8; i>0; --i)   /* 下面這段計算過程與計算一個字節crc一樣 */  
        { 
            if (crc & 0x80)
                crc = (crc << 1) ^ 0x31;
            else
                crc = (crc << 1);
        }
    }

    return (crc); 
}
上面的crc計算是純採用邏輯運行的方式,可以看到,需要的運行量也是不少的,每一個字節

都需要進行8次判斷、移位、或異或操作。可以採用查表法,大大減少計算量,先計算出 
0x00~0xFF每一個字節的crc校驗結果,後面就可以通過表來查出每個字節的crc結果,大大 
減少計算量。 
下面是一個表生成程序: 
(生成表對應多項式:0x31(多項式:x8+x5+x4+1,100110001))

    void  create_crc_table(void)
    {
        unsigned short i;
        unsigned char j;

        for (i=0; i<=0xFF; i++)
        {
            if (0 == (i%16))
                printf("\n");

            j = i&0xFF;
            printf("0x%.2x, ", cal_table_high_first (j));  /*依次計算每個字節的crc校驗值*/
        }
    }

得到的表整理後如下:

static const unsigned char crc_table[] =
{
    0x00,0x31,0x62,0x53,0xc4,0xf5,0xa6,0x97,0xb9,0x88,0xdb,0xea,0x7d,0x4c,0x1f,0x2e,
    0x43,0x72,0x21,0x10,0x87,0xb6,0xe5,0xd4,0xfa,0xcb,0x98,0xa9,0x3e,0x0f,0x5c,0x6d,
    0x86,0xb7,0xe4,0xd5,0x42,0x73,0x20,0x11,0x3f,0x0e,0x5d,0x6c,0xfb,0xca,0x99,0xa8,
    0xc5,0xf4,0xa7,0x96,0x01,0x30,0x63,0x52,0x7c,0x4d,0x1e,0x2f,0xb8,0x89,0xda,0xeb,
    0x3d,0x0c,0x5f,0x6e,0xf9,0xc8,0x9b,0xaa,0x84,0xb5,0xe6,0xd7,0x40,0x71,0x22,0x13,
    0x7e,0x4f,0x1c,0x2d,0xba,0x8b,0xd8,0xe9,0xc7,0xf6,0xa5,0x94,0x03,0x32,0x61,0x50,
    0xbb,0x8a,0xd9,0xe8,0x7f,0x4e,0x1d,0x2c,0x02,0x33,0x60,0x51,0xc6,0xf7,0xa4,0x95,
    0xf8,0xc9,0x9a,0xab,0x3c,0x0d,0x5e,0x6f,0x41,0x70,0x23,0x12,0x85,0xb4,0xe7,0xd6,
    0x7a,0x4b,0x18,0x29,0xbe,0x8f,0xdc,0xed,0xc3,0xf2,0xa1,0x90,0x07,0x36,0x65,0x54,
    0x39,0x08,0x5b,0x6a,0xfd,0xcc,0x9f,0xae,0x80,0xb1,0xe2,0xd3,0x44,0x75,0x26,0x17,
    0xfc,0xcd,0x9e,0xaf,0x38,0x09,0x5a,0x6b,0x45,0x74,0x27,0x16,0x81,0xb0,0xe3,0xd2,
    0xbf,0x8e,0xdd,0xec,0x7b,0x4a,0x19,0x28,0x06,0x37,0x64,0x55,0xc2,0xf3,0xa0,0x91,
    0x47,0x76,0x25,0x14,0x83,0xb2,0xe1,0xd0,0xfe,0xcf,0x9c,0xad,0x3a,0x0b,0x58,0x69,
    0x04,0x35,0x66,0x57,0xc0,0xf1,0xa2,0x93,0xbd,0x8c,0xdf,0xee,0x79,0x48,0x1b,0x2a,
    0xc1,0xf0,0xa3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1a,0x2b,0xbc,0x8d,0xde,0xef,
    0x82,0xb3,0xe0,0xd1,0x46,0x77,0x24,0x15,0x3b,0x0a,0x59,0x68,0xff,0xce,0x9d,0xac
};
採用查表法計算crc代碼如下:
unsigned char cal_crc_table(unsigned char *ptr, unsigned char len) 
{
    unsigned char  crc = 0x00;

    while (len--)
    {
        crc = crc_table[crc ^ *ptr++];
    }
    return (crc);
}

3、 反序異或的計算 
反序異或與順序異或差異在數據先判斷最低位,並且數據是向右移 
的,並且多項式數據位需要高低位反轉一下。 
還是以多項式:x8+x5+x4+1(二進制爲:100110001)爲例: 
則計算一個字節的crc校驗代碼如下:

unsigned char cal_table_low_first(unsigned char value)
{
    unsigned char i, crc;

    crc = value;
/* 同樣需要計算8次 */
    for (i=8; i>0; --i)
    { 
        if (crc & 0x01)  /* 反序異或變成判斷最低位是否爲1 */
            /* 數據變成往右移位了 */
            /* 計算的多項式從0x31(0011 0001)變成了0x8C (1000 1100) */
/* 多項式值,原來的最高位變成了最低位,原來的最低位變成最高位,8位數據高低位交換一下位置 */
            crc = (crc >> 1) ^ 0x8C;
        else
            crc = (crc >> 1);
    }

    return crc;
}

至於多個字節的crc校驗及crc數據表的生成,只要把單個字節的計算方式替換一下順序的 
計算方式即可,這裏就不再列出。所以,只要明確了crc校驗使用的多項式,高位先校驗 
還是低位先校驗,計算crc的初始值是什麼,那crc的計算就變得很簡單了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章