CRC校驗原理

jacksong2021發表於2021-01-05

原文:https://blog.csdn.net/qq_26652069/article/details/100578942

線性分組碼中有一種重要的碼稱為迴圈碼(Cyclic code),這種碼編碼和解碼都不太複雜,而且檢(糾)錯能力較強。迴圈碼除了具有線性分組碼的一般性質外,還具有迴圈性。迴圈性是指任一碼組迴圈一位以後(即將最右端的一個碼元移至左端,或反之)以後,仍然為該碼中的一個碼組

什麼是CRC校驗?

CRC即迴圈冗餘校驗碼:

  • 是資料通訊領域中最常用的一種查錯校驗碼;
  • 其特徵是資訊欄位校驗欄位的長度可以任意選定。

迴圈冗餘檢查(CRC, Cyclic Redundancy Check)是一種資料傳輸檢錯功能,對資料進行多項式計算(利用多項式,對資料進行模2除法),並將得到的結果附在幀的後面傳輸,接收裝置接收後也執行類似的演算法(依舊利用同一個多項式,對接收的資料進行模2除法,但是這裡要求沒有餘數才算是正確傳輸),以保證資料傳輸的正確性和完整性。CRC利用除法及餘數的原理,實現錯誤偵測的功能,具有原理清晰、實現簡單等優點。

相比於奇偶校驗(PCC)只能校驗一位錯誤,迴圈冗餘校驗碼的檢錯能力要更強,能夠檢出多位錯誤。

CRC校驗原理

      其根本思想就是先在要傳送的幀後面附加一個數(即用來校驗的校驗碼,但要注意,這裡的數也是二進位制序列的,下同),生成一個新幀傳送給接收端。當然,這個附加的數不是隨意的,它要使所生成的新幀能與傳送端和接收端共同選定的某個特定數整除(注意,這裡不是直接採用二進位制除法,而是採用一種稱之為“模2除法”)。到達接收端後,再把接收到的新幀除以(同樣採用“模2除法”)這個選定的除數。因為在傳送端傳送資料幀之前就已通過附加一個數,做了“去餘”處理(也就已經能整除了),所以結果應該是沒有餘數。如果有餘數,則表明該幀在傳輸過程中出現了差錯

【百科】

迴圈冗餘校驗演算法將是否除盡,作為資料資訊的校驗規則。對於能被多項式除盡的資料而言,其資料程式碼的誤位元速率就較低;對於那些不能被多項式除盡的資料,需要對資料出錯的地方進行分析,並將產生的餘數進行減去。,如果讓被校驗資料減去餘數,勢必能為生成多項式所除盡,但網路通訊中減法操作存在複雜的數學計算,無法使用拼裝的方式進行資料編碼。

基於此種情況,網路通訊中引入模2運算的計算方式,模2運算包括:模2加、模2減、模2乘、模2除等四種二進位制運算。模2運算不考慮進位和借位,即模2加法是不帶進位的二進位制加法運算,模2減法是不帶借位的二進位制減法運算。兩個序列模二相加,即兩個序列中對應位,相加不進位,相同為0不同為1。在兩個二進位制位相運算時,這兩個位的值能確定最終的運算結果,而不受前一次運算的影響,因此模2運算的加減乘除屬於異或運算。

 

模2除法:模2除法與算術除法類似,但每一位除的結果不影響其它位,即不向上一位借位,所以實際上就是異或。在迴圈冗餘校驗碼(CRC)的計算中有應用到模2除法。模2加法運算為:1+1=0,0+1=1,0+0=0,無進位,也無借位;模2減法運算為:1-1=0,0-1=1,1-0=1,0-0=0,也無進位,無借位。

模2除法/乘法:

 

 

CRC校驗步驟

CRC校驗中有兩個關鍵點:

(1)預先確定一個傳送送端和接收端都用來作為除數的二進位制位元串(或多項式G(x)),可以隨機選擇,也可以使用國際標準,但是最高位和最低位必須為1即生成多項式G(x)要求次數大於0,並且要求0次冪的係數為1。;

       G(x)為傳送端和接收端預先約好的生成多項式。G(x)的選取對校驗效果起著關鍵的作用,使用較多的生成多項式G(x)有CRC-16、CRC-CCITT、CRC-32等;

CRC16的生成多項式為:G(x)= X16+X10+X2+1

CRC32的生成多項式為:G(x)= X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1

 

(2)把原始幀(假設為k位, 對應資訊多項式)與上面計算出的除數(二進位制位元串或生成多項式 G(x),假設為m位)進行模2除法運算,餘數作為CRC校驗碼。

        CRC校驗碼計算示例:現假設選擇的CRC生成多項式為G(X) = X4 + X3 + 1,要求出二進位制序列10110011的CRC校驗碼。

設要傳送的資料碼有k位,則該資料碼對應的多項式F(x)有k項,k的每一位取值只能為0或1,即F(x)中每項X^n的係數只能是0或1。

R(x)為生成的 r 階冗餘碼多項式,R(x)的項數比G(x)要少一項。R(x)的計算方法為:以F(x)作為被除數,先將F(x)乘x′即左移r位,再以G(x)作為除數作模2運算。

EX:選定CRC校驗的生成多項式G(x)=x^4+x^3+1,待傳輸二進位制序列1011 0011,求出其傳送端的CRC校驗碼以及接收端的校驗過程。

答:下面是具體的計算過程:

傳送端:

① 將選定的多項式轉化為二進位制序列:由G(X) = X4 + X3 + 1可知二進位制一種有五位,第4位、第三位和第零位分別為1,則序列為11001

② 多項式的位數位5,則在資料幀的後面加上5-1位0,資料幀變為101100110000,然後使用模2除法除以除數11001,得到餘數0100即為CRC校驗碼。

③ 將計算出來的CRC校驗碼0100新增在原始幀的後面,真正的資料幀為10110011 0100,再把這個資料幀傳送到接收端。

④ 接收端收到資料幀10110011 0100後,依3舊 用上預先選定的除數11001,用模2除法除去,驗證餘數是否為0,如果為0,則說明資料幀沒有出錯。


傳送端:

接收端:


Verilog設計

分析:CRC碼由傳送端計算,放置於傳送資訊報文的尾部。接收資訊的裝置再重新計算接收到資訊報文的CRC,比較計算得到的CRC是否與接收到的相符,如果兩者不相符,則表明出錯。
校驗碼的計算多項式為(X16 + X15 + X2 + 1,1 1000 0000 0000 0101)。具體CRC16碼的計算方法是:
        1.預置1個16位的暫存器為十六進位制FFFF(即全為1);稱此暫存器為CRC暫存器;
        2.把第一個8位二進位制資料 (既通訊資訊幀的第一個位元組)與16位的CRC暫存器的低8位相異或,把結果放於CRC暫存器;
        3.把CRC暫存器的內容右移一 位(朝低位)用0填補最高位,並檢查右移後的移出位;
        4.如果移出位為0:重複第3步(再次右移一位);
             如果移出位為1:CRC暫存器與多項式A001(1010 0000 0000 0001)進行異或;(Modbus)
        5.重複步驟3和4,直到右移8次,這樣整個8位資料全部進行了處理;
        6.重複步驟2到步驟5,進行通訊資訊幀下一個位元組的處理;
        7.將該通訊資訊幀所有位元組按上述步驟計算完成後,得到的16位CRC暫存器的高、低位元組進行交換;
        8.最後得到的CRC暫存器內容即為:CRC碼。

 

下面舉例說明CRC校驗碼的求法:(此例子摘自百度百科:CRC校驗碼)


資訊欄位程式碼為: 1011001;對應m(x)=x6+x4+x3+1
假設生成多項式為:g(x)=x4+x3+1;則對應g(x)的程式碼為: 11001
m(x)=x10+x8+x7+x4 對應的程式碼記為:10110010000;
採用多項式除法: 得餘數為: 1010 (即CRC校驗欄位為:1010)
傳送方:發出的傳輸欄位為: 1 0 1 1 0 0 1 1010
給出餘數(1010)的計算步驟:
除法沒有數學上的含義,而是採用計算機的模二除法,即,除數和被除數做異或運算。進行異或運算時除數和被除數最高位對齊,按位異或。
10110010000
^

11001
--------------------------
01111010000
1111010000
^11001
-------------------------
0011110000
11110000
^11001
--------------------------
00111000
111000
^11001
-------------------
001010
則四位CRC校驗碼就為:1010。
 

 

補充:

CRC16常見的標準有以下幾種,被用在各個規範中,其演算法原理基本一致,就是在資料的輸入和輸出有所差異,下邊把這些標準的差異列出,並給出C語言的演算法實現。

CRC16_CCITT:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在後,結果與0x0000異或

CRC16_CCITT_FALSE:多項式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在後,高位在前,結果與0x0000異或

CRC16_XMODEM:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在後,高位在前,結果與0x0000異或

CRC16_X25:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在後,結果與0xFFFF異或

CRC16_MODBUS:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在後,結果與0x0000異或

CRC16_IBM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在後,結果與0x0000異或

CRC16_MAXIM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在後,結果與0xFFFF異或

CRC16_USB:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在後,結果與0xFFFF異或

 

————————————————
原文連結:https://blog.csdn.net/li200503028/article/details/26591243

下面給出CRC校驗碼的verilog實現方式:
本例中實現了求得8bit資訊序列的CRC校驗碼,生成多項式取g(x)=X^16+X^12+X^5+1,對應的生成序列為1_0001_0000_0010_0001,輸入的8bit序列data左移16位後得到stemp={data,16‘b0000_0000_0000_0000} ,每次非同步復位訊號rst_n復位時將crc的值清零並把線型變數stemp的值打入暫存器temp中,然後通過時序電路將temp與生成多項式對應的序列進行多次按位異或,最終得到一個小於生成序列的temp後,temp[15:0]的值即為CRC校驗序列,並把它賦給輸出crc。
 下面是code:

 
  1.  
  2. //資訊碼 : 8bit

  3. //生成多項式 :1_0001_0000_0010_0001

  4. //附加位 :0000 0000 0000 0000

  5. //傳輸的碼 : data+0000 0000 0000 0000 =24位

  6. module crc(

  7. clk ,

  8. data ,

  9. rst_n ,

  10. crc  

  11. );

  12. input      [7:0] data ;

  13. input             clk ;

  14. input             rst_n ;

  15. output reg [15:0] crc=0 ;

  16. wire [23:0] stemp ; 

  17. reg [23:0] temp=0 ;

  18. parameter polynomial=17'b1_0001_0000_0010_0001;

  19. assign stemp={data,16'b0000000000000000};

  20.  
  21. always @ (posedge clk or negedge rst_n)

  22.  begin 

  23.     if(!rst_n)

  24.           begin

  25.               crc <= 0 ;

  26.               temp <= stemp ; 

  27.               end

  28.     else 

  29.         begin

  30.           if(temp[23]) temp[23:7]<=temp[23:7]^polynomial;

  31.           else if(temp[22]) temp[22:6]<=temp[22:6]^polynomial;

  32.           else if(temp[21]) temp[21:5]<=temp[21:5]^polynomial;

  33.          else if(temp[20]) temp[20:4]<=temp[20:4]^polynomial;

  34.           else if(temp[19]) temp[19:3]<=temp[19:3]^polynomial;

  35.           else if(temp[18]) temp[18:2]<=temp[18:2]^polynomial;

  36.           else if(temp[17]) temp[17:1]<=temp[17:1]^polynomial;

  37.           else if(temp[16]) temp[16:0]<=temp[16:0]^polynomial;

  38.           else   crc<=temp[15:0];    

  39.           end

  40.  end  

  41. endmodule


testbench:

 
  1. module testbench;

  2. // Inputs

  3. reg clk;

  4. reg [7:0] data;

  5. reg rst_n;

  6.  
  7. // Outputs

  8. wire [15:0] crc;

  9.  
  10. // Instantiate the Unit Under Test (UUT)

  11. crc uut (

  12. .clk(clk), 

  13. .data(data), 

  14. .rst_n(rst_n), 

  15. .crc(crc)

  16. );

  17. initial begin

  18. // Initialize Inputs

  19.  
  20. clk=0;

  21. data=0;

  22. rst_n=0;

  23. #100

  24.  
  25. data =8'b10110110;

  26. rst_n = 1;

  27.  
  28. // Wait 100 ns for global reset to finish

  29. #50;

  30. rst_n =0;

  31. #50

  32. rst_n =1;

  33.                 #1000

  34.  
  35. data =8'b01001100;

  36. rst_n = 1;

  37. #50;

  38. rst_n =0;

  39. #50

  40. rst_n =1;

  41. #1000

  42.  
  43. data =8'b10110011;

  44. rst_n = 1;

  45. #50;

  46. rst_n =0;

  47. #50

  48. rst_n =1;

  49. #1000

  50.  
  51. data =8'b10010110;

  52. rst_n = 1;

  53. #50;

  54. rst_n =0;

  55. #50

  56. rst_n =1;

  57. #1000

  58.  
  59. data =8'b10100101;

  60. rst_n = 1;

  61. #50;

  62. rst_n =0;

  63. #50

  64. rst_n =1;

  65. // Add stimulus here

  66. end

  67.       always #10 clk=~clk;

  68. endmodule


下面是模擬結果:
testbench中加了5組輸入的data值,模擬結果已通過軟體《CRC計算器》驗證,全部正確。

 

相關文章