迴圈冗餘校驗CRC演算法

2021-08-19 22:21:39 字數 3910 閱讀 7897

本文參考自:

crc校驗(迴圈冗餘校驗)是資料通訊中最常採用的校驗方式。在嵌入式軟體開發中,經常要用到crc 演算法對各種資料進行校驗。因此,掌握基本的crc演算法應是嵌入式程式設計師的基本技能。

其實,在網上有一篇介紹crc 演算法的非常好的文章,作者是ross williams,題目叫:「a painless guide to crc error detection algorithms」。

一、奇偶校驗

所謂通訊過程的校驗是指在通訊資料後加上一些附加資訊,通過這些附加資訊來判斷接收到的資料是否和傳送出的資料相同。比如說rs232序列通訊可以設定奇偶校驗位,所謂奇偶校驗就是在傳送的每乙個位元組後都加上一位,使得每個位元組中1的個數為奇數個或偶數個。比如我們要傳送的位元組是0x1a,二進位制表示為0001 1010。

採用奇校驗,則在資料後補上個0,資料變為0001 1010 0,資料中1的個數為奇數個(3個)

採用偶校驗,則在資料後補上個1,資料變為0001 1010 1,資料中1的個數為偶數個(4個)

接收方通過計算資料中1個數是否滿足奇偶性來確定資料是否有錯。

奇偶校驗的缺點也很明顯,首先,它對錯誤的檢測概率大約只有50%。也就是只有一半的錯誤它能夠檢測出來。另外,每傳輸乙個位元組都要附加一位校驗位,對傳輸效率的影響很大。因此,在高速資料通訊中很少採用奇偶校驗。奇偶校驗優點也很明顯,它很簡單,因此可以用硬體來實現,這樣可以減少軟體的負擔。因此,奇偶校驗也被廣泛的應用著。

奇偶校驗就先介紹到這來,之所以從奇偶校驗說起,是因為這種校驗方式最簡單,而且後面將會知道奇偶校驗其實就是crc 校驗的一種(crc-1)。

二、累加和校驗

另一種常見的校驗方式是累加和校驗。所謂累加和校驗實現方式有很多種,最常用的一種是在一次通訊資料報的最後加入乙個位元組的校驗資料。這個位元組內容為前面資料報中全部資料的忽略進製的按位元組累加和。比如下面的例子:

我們要傳輸的資訊為: 6、23、2

加上校驗和後的資料報:6、23、4、31

這裡 31 為前三個位元組的校驗和。接收方收到全部資料後對前三個資料進行同樣的累加計算,如果累加和與最後乙個位元組相同的話就認為傳輸的資料沒有錯誤。

累加和校驗由於實現起來非常簡單,也被廣泛的採用。但是這種校驗方式的檢錯能力也比較一般,對於單位元組的校驗和大概有1/256 的概率將原本是錯誤的通訊資料誤判為正確資料。之所以這裡介紹這種校驗,是因為crc校驗在傳輸資料的形式上與累加和校驗是相同的,都可以表示為:通訊資料 校驗位元組(也可能是多個位元組)

三、crc 演算法

crc 演算法的基本思想是將傳輸的資料當做乙個位數很長的數。將這個數除以另乙個數。得到的餘數作為校驗資料附加到原資料後面。

最常用的幾種生成多項式如下:

crc8=x8+x5+x4+x0

crc-ccitt=x16+x12+x5+x0

crc16=x16+x15+x2+x0

crc12=x12+x11+x3+x2+x0

crc32=x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+x0

有一點要特別注意,文獻中提到的生成多項式經常會說到多項式的位寬(width,簡記為w),這個位寬不是多項式對應的二進位制數的位數,而是位數減1。比如crc8中用到的位寬為8的生成多項式,其實對應得二進位制數有九位:100110001。另外一點,多項式表示和二進位制表示都很繁瑣,交流起來不方便,因此,文獻中多用16進製制簡寫法來表示,因為生成多項式的最高位肯定為1,最高位的位置由位寬可知,故在簡記式中,將最高的1統一去掉了,如crc32的生成多項式簡記為04c11db7實際上表示的是104c11db7。當然,這樣簡記除了方便外,在程式設計計算時也有它的用處。

對於上面的例子,位寬為4(w=4),按照crc演算法的要求,計算前要在原始資料後填上w個0,也就是4個0。

四、crc演算法的程式設計實現

假設我們的生成多項式為:100110001(簡記為0x31),也就是crc-8

則計算步驟如下:

(1) 將crc暫存器(8-bits,比生成多項式少1bit)賦初值0

(2) 在待傳輸資訊流後面加入8個0

(3) while (資料未處理完)

(4) begin

(5) if (crc暫存器首位是1)

(6) reg = reg xor 0x31

(7) crc暫存器左移一位,讀入乙個新的資料於crc暫存器的0 bit的位置。

(8) end

(9) crc暫存器就是我們所要求的餘數。

實際上,真正的crc 計算通常與上面描述的還有些出入。這是因為這種最基本的crc除法有個很明顯的缺陷,就是資料流的開頭新增一些0並不影響最後校驗字的結果。這個問題很讓人惱火啊,因此真正應用的crc 演算法基本都在原始的crc演算法的基礎上做了些小的改動。

所謂的改動,也就是增加了兩個概念,第乙個是「餘數初始值」,第二個是「結果異或值」。

所謂的「餘數初始值」就是在計算crc值的開始,給crc暫存器乙個初始值。「結果異或值」是在其餘計算完成後將crc暫存器的值在與這個值進行一下異或操作作為最後的校驗值。

常見的三種crc 標準用到個各個引數如下表。

加入這些變形後,常見的演算法描述形式就成了這個樣子了:

(1) 設定crc暫存器,並給其賦值為「餘數初始值」。

(2) 將資料的第乙個8-bit字元與crc暫存器進行異或,並把結果存入crc暫存器。

(3) crc暫存器向右移一位,msb補零,移出並檢查lsb。

(4) 如果lsb為0,重複第三步;若lsb為1,crc暫存器與0x31相異或。

(5) 重複第3與第4步直到8次移位全部完成。此時乙個8-bit資料處理完畢。

(6) 重複第2至第5步直到所有資料全部處理完成。

(7) 最終crc暫存器的內容與「結果異或值」進行或非操作後即為crc值。

示例性的c**如下所示,因為效率很低,專案中如對計算時間有要求應該避免採用這樣的**。

#include 

#include

#include

#include

#include

#include

#include

#define poly 0x1021

/** * calculating crc-16 in 'c'

* @para addr, start of data

* @para num, length of data

* @para crc, incoming crc

*/uint16_t crc16(unsigned

char *addr, int num, uint16_t crc)

/* loop for 8 bits */

crc &= 0xffff; /* ensure crc remains 16-bit value */

} /* loop until num=0 */

return(crc); /* return updated crc */

}int main (int argc , char* argv)

; unsigned

char data2 = ;

unsigned

short c1, c2;

c1 = crc16(data1, 9, 0xffff);

c2 = crc16(data1, 4, 0xffff);

c2 = crc16(data2, 5, c2);

printf("%04x\n", c1);

printf("%04x\n", c2);

}

演算法 迴圈冗餘校驗(CRC)

迴圈冗餘校驗 cyclic redundancy check,crc 是一種根據網路資料報或電腦檔案等資料產生簡短固定位數校驗碼的一種雜湊函式,主要用來檢測或校驗資料傳輸或者儲存後可能出現的錯誤。它是利用除法及餘數的原理來作錯誤偵測的。工作原理 在對資訊的處理過程中,我們可以將要被處理的資料塊m看成...

迴圈冗餘校驗 CRC校驗

一 crc校驗概念 即迴圈冗餘校驗碼 cyclic redundancy check 是資料通訊領域中最常用的一種查錯校驗碼,迴圈冗餘檢查 crc 是一種資料傳輸檢錯功能,對資料進行多項式計算,並將得到的結果附在幀的後面,接收裝置也執行類似的演算法,以保證資料傳輸的正確性和完整性。其特徵是資訊字段和...

迴圈冗餘校驗CRC

網上搜到的內容不全面,維基百科講的比較好,原理很清楚傳送門 其實對於程式設計師來講,不用太在意它的數學原理,另外生成碼的選擇不是隨意的,這可能影響到校驗的效能。注意其中的加法不進製,減法不借位,類似是異或邏輯。關於怎樣產生crc,有這樣乙個演算法 下面為crc的計算過程 1 設定crc暫存器,並給其...