CRC校验算法详解及代码实现
CRC校驗算法詳解及代碼實現
一、 CRC校驗算法前置知識
在學習CRC校驗算法之前,先復習一下CRC會涉及的主要幾個主要的算法。
1. 異或
異或,就是不同為1,相同為0,運算符號是^。
 0^0 = 0
 0^1 = 1
 1^1 = 0
 1^0 = 1
異或運算存在如下幾個規律,需要了解。
2. 模2加法
模2加法相對于普通的算術加法,主要的區別在模2加法,不做進位處理。具體結果如下。
 0+0 = 0
 0+1 = 1
 1+1 = 0
 1+0 = 1
 我們發現模2加法的計算結果,同異或運算結果一模一樣。進一步推演,我們會發現,異或運算的5個規律,同樣適合于模2加法。這里,就不在一一列舉了。
3. 模2減法
模2減法相對于普通的算術減法,主要的區別在模2減法,不做借位處理。具體結果如下。
 0-0 = 0
 0-1 = 1
 1-1 = 0
 1-0 = 1
 我們發現模2減法的計算結果,同模2加法,以及異或的運算結果一模一樣。進一步推演,我們會發現,異或運算的5個規律,同樣適合于模2減法。這里,就不在一一列舉了。
4. 模2除法
模2除法相對于普通的算術除法,主要的區別在模2除法,它既不向上位借位,也不比較除數和被除數的相同位數值的大小,只要以相同位數進行相除即可。下面是一個模2除法的示例。被除數是101001000,除數1101。
 
 選取被除數前面的1010模2除以除數1101,因最高為是1,所以,得到商1,余數通過1010和1101的模2減法獲得,根據前面的模2減法運算的介紹,其運算結果和異或運算一模一樣。因此,得到余數:1010 ^ 1101 = 0111。去掉最高位的0,得到111,再將上面被除數的下一位,即0拿下來,得到1110。1110模2除以1101,得到商1,余數1110 ^ 1101 = 0011。除掉最高為的0,拿下被除數的下一位,即1,得到0111。此時,因為最高位是0,所以得到商0,余數0111 ^ 0000 = 0111。去掉最高為的,再和被除數的下一位結合,繼續模2除法。按照上圖依次計算,可以得到最終的商110101,余數001。
 從上面的示例,我們看到一個規律:每循環一次模2計算,如果得到的被除數最高位是0,則一輪循環使用0000作為除數。如果得到的被除數最高位是1,則下一輪循環除數使用1101。這樣可以保證每一輪循環被除數都能向右平移一位,直到循環到被除數最后一位。
 根據之前章節中介紹的異或運算的幾條規律,我們可以很容易得到一個結論,如果我們將模2除法的余數和被除數的最后幾位(與余數的位數一下,本例中就是3)異或之后,得到一個新的數,這個新的數,再使用模2除法除以除數1101,即可整除,即余數為0。
二、 CRC校驗算法及實現
CRC校驗的根本思想就是先在要發送的幀后面附加一個數(這個就是用來校驗的校驗碼),生成一個新幀發送給接收端。當然,這個附加的數不是隨意的,它要使所生成的新幀能與發送端和接收端共同選定的某個特定數值整除(注意,這里不是直接采用二進制除法,而是采用 “模2除法”)。因為在發送端發送數據幀之前就已通過附加一個數,做了“去余”處理(也就已經能整除了),所以結果應該是沒有余數。如果有余數,則表明該幀在傳輸過程中出現了差錯。
具體來說,CRC校驗原理就是以下幾個步驟:
從上面可以看出,CRC校驗中有兩個關鍵點:
 一是要預先確定一個發送端和接收端都用來作為除數的二進制比特串(或多項式);
 二是把原始幀并追加k-1位"0"后得到的新幀與上面選定的除數進行模2除法運算,計算出CRC。
 前者可以隨機選擇,也可按國際上通行的標準選擇,但最高位和最低位必須均為“1”,如在IBM的SDLC(同步數據鏈路控制)規程中使用的CRC-16(也就是這個除數一共是17位,這樣的話,得到的余數的位數就是17-1=16)生成多項式g(x)= x16 + x15 + x2 +1(對應二進制比特串為:11000000000000101)。
理論上,使用上述CRC校驗步驟的第二步計算CRC的時候,需要將所有的二進制序列(包括后加的k-1個0)作為一個整體按照第一章節中模2除法的方法,除以選定的除數。但是,考慮模2除法中實際使用的運算其實一直都是按位異或,結合異或運算的結合律,我們逐個bit逐個bit地將作為被除數的二進制序列的每個bit依次引入,也可以逐個字節逐個字節的引入。下面是通過逐個字節引入方式計算CRC的代碼實現,假設校準使用的多項式為x8+x5+x4+1 (對應二進制為: 0b100110001,對應HEX值為0x131)。
/*************************************** *@DESCRIPTION: -- CRC8計算, * *@Parameters: -- *data_ptr:待計算CRC8的數據 * len:待計算CRC8數據的長度 * *@Return: --無 ****************************************/ unsigned char calculate_crc8(unsigned char *data_ptr, unsigned char len) {unsigned int i;unsigned char j;unsigned char crc = 0x00;for (i=0; i<len; i++){crc ^= *data_ptr;data_ptr++;for (j=8; j>0; j--){if (crc & 0x80){crc <<= 1;crc ^= 0x31; // 0x131最高位1去掉,只與低8bit的0x31異或即可。} // if (crc & 0x80)else{ crc <<= 1;/*當最高bit為0時,則crc與0按位異或,仍為crc,所以,沒有語句"crc ^= 0x31;”。*/} // else} // for (j=8; j>0; j--)} // for (i=0; i<len; i++)return crc; }總結
以上是生活随笔為你收集整理的CRC校验算法详解及代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: JAVA之CRC校验算法
- 下一篇: 高程(DEM) ASCII数据获取
