1. 程式人生 > 其它 >BCC、CRC、LRC校驗演算法

BCC、CRC、LRC校驗演算法

BCC、CRC、LRC校驗演算法

一、校驗演算法

BCC(Block Check Character/資訊組校驗碼),好像也是常說的異或校驗方法
CRC(Cyclic Redundancy Check/迴圈冗餘校驗)
LRC(Longitudinal Redundancy Check/縱向冗餘校驗)

二、BCC(Block Check Character/資訊組校驗符號)

非接觸卡讀卡器與PC機的通訊格式如下:
STX(02H)+ 6個位元組的卡號+VERH+VERL+EOT(04H)
STX(02H)起始位元組
EOT(04H)結束位元組
6個位元組的卡號為六個十六進位制的ASCII字元,6個位元組的傳送,高位元組在前,低位元組在後。例如:
卡號: 8 D E F 9 E
傳輸的資料格式:38 44 45 46 39 45 (十六進位制)
在校驗時採用目前最通用的BCC校驗方式:
具體的方法是:
將有效的卡號接位元組作異或(XOR)校驗:
38H (XOR)44H (XOR)45H (XOR)46H (XOR)39H(XOR)45H =03H
然後將接收到的資料VERH+VERL合成一個位元組資料,30H(HEX)=0,33H(HEX)=3
合成數據為03H,接收到的資料與我們收到的卡號的校驗資料一致,則接收到
的卡號為正確卡號。
再比如現有卡號為:
卡號: 0 5 8 E 4 2
傳輸的資料格式:30 35 38 45 34 32 (十六進位制)
在校驗時採用目前最通用的BCC校驗方式:
具體的方法是:
將有效的卡號接位元組作異或(XOR)校驗:
30H (XOR)35H (XOR)38H (XOR)45H (XOR)34H(XOR)32H =7EH
然後將接收到的資料VERH+VERL合成一個位元組資料,37H(HEX)=7,45H(HEX)=E
合成數據為7EH,接收到的資料與我們收到的卡號的校驗資料一致,則接收到
的卡號為正確卡號。
在編寫程式時,可以先將所有資料都接收到計算機的記憶體中,然後計算BCC校驗值VALUE1,再將接收的BCC值
拼成一個十六進位制數VALUE2,然後比較這兩個值,如果相等,則接收到的卡號為合法卡號,然後按您的系統
作相應的處理。

三、CRC(Cyclic Redundancy Check/迴圈冗餘校驗)

它是利用除法及餘數的原理來作錯誤偵測(Error Detecting)的。實際應用時,傳送裝置計算出CRC值並隨資料一同傳送給接收裝置,接收裝置對收到的資料重新計算CRC並與收到的CRC相比較,若兩個CRC值不同,則說明資料通訊出現錯誤。
  根據應用環境與習慣的不同,CRC又可分為以下幾種標準:
  ①CRC-12碼;
  ②CRC-16碼;
  ③CRC-CCITT碼;
  ④CRC-32碼。
  CRC-12碼通常用來傳送6-bit字串。
  CRC-16及CRC-CCITT碼則用是來傳送8-bit字元,其中CRC-16為美國採用,而CRC-CCITT為歐洲國家所採用。
  CRC-32碼大都被採用在一種稱為Point-to-Point的同步傳輸中。
  下面為 CRC計算過程:
  1.設定CRC暫存器,並給其賦值FFFF(hex)。
  2.將資料的第一個8-bit字元與16位CRC暫存器的低8位進行異或,並把結果存入CRC暫存器。
  3.CRC暫存器向右移一位,MSB補零,移出並檢查LSB。
  4.如果LSB為0,重複第三步;若LSB為1,CRC暫存器與多項式碼相異或。
  5.重複第3與第4步直到8次移位全部完成。此時一個8-bit資料處理完畢。
  6.重複第2至第5步直到所有資料全部處理完成。
  7.最終CRC暫存器的內容即為CRC值。
  常用的CRC迴圈冗餘校驗標準多項式如下:
  CRC(16位) = X16+X15+X2+1
  CRC(CCITT) = X16+X12 +X5+1
  CRC(32位) = X32+X26+X23+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1
  以CRC(16位)多項式為例,其對應校驗二進位制位列為1 1000 0000 0000 0101。
   CRC基本原理是:在K位資訊碼後再拼接R位的校驗碼,整個編碼長度為N位,因此,這種編碼又叫(N,K)碼。對於一個給定的(N,K)碼,可以證明存在一個最高次冪為N-K=R的多項式G(x),根據G(x)可以生成K位資訊的校驗碼,而G(x)叫做這個CRC碼的生成多項式。
校驗碼的具體生成過程為:假設傳送資訊用資訊多項式C(X)表示,將C(x)左移R位,則可表示成C(x)2R,這樣C(x)的右邊就會空出R位,這就是校驗碼的位置。通過C(x)

2R除以生成多項式G(x)得到的餘數就是校驗碼。
  幾個基本概念
  1、 多項式與二進位制數碼
  多項式和二進位制數有直接對應關係:x的最高冪次對應二進位制數的最高位,以下各位對應多項式的各冪次,有此冪次項對應1,無此冪次項對應0。可以看出:x的最高冪次為R,轉換成對應的二進位制數有R+1位。
  多項式包括生成多項式G(x)和資訊多項式C(x)。
  如生成多項式為G(x)=x4+x3+x+1, 可轉換為二進位制數碼11011。
  而傳送資訊位 1111,可轉換為資料多項式為C(x)=x3+x2+x+1。
  2、 生成多項式
  是接受方和傳送方的一個約定,也就是一個二進位制數,在整個傳輸過程中,這個數始終保持不變。
  在傳送方,利用生成多項式對資訊多項式做模2除生成校驗碼。在接受方利用生成多項式對收到的編碼多項式做模2除檢測和確定錯誤位置。
  應滿足以下條件:
  a、生成多項式的最高位和最低位必須為1。
  b、當被傳送資訊(CRC碼)任何一位發生錯誤時,被生成多項式做模2除後應該使餘數不為0。
  c、不同位發生錯誤時,應該使餘數不同。
  d、對餘數繼續做模2除,應使餘數迴圈。
  將這些要求反映為數學關係是比較複雜的。但可以從有關資料查到常用的對應於不同碼制的生成多項式如圖9所示:

  N          K          碼距d     G(x)多項式                             G(x)
  7          4          3          x3+x+1                             1011
  7          4          3          x3+x2+1                            1101
  7          3          4          x4+x3+x2+1                         11101
  7          3          4          x4+x2+x+1                          10111
  15         11          3         x4+x+1                             10011
  15         7          5          x8+x7+x6+x4+1                    111010001
  31         26          3         x5+x2+1                            100101
  31         21          5         x10+x9+x8+x6+x5+x3+1            11101101001
  63         57          3         x6+x+1                             1000011
  63         51          5         x12+x10+x5+x4+x2+1       	  1010000110101
  1041       1024                 x16+x15+x2+1                11000000000000101

  3、模2除(按位除)
  模2除做法與算術除法類似,但每一位除(減)的結果不影響其它位,即不向上一位借位。所以實際上就是異或。然後再移位移位做下一位的模2減。步驟如下:
  a、用除數對被除數最高几位做模2減,沒有借位。
  b、除數右移一位,若餘數最高位為1,商為1,並對餘數做模2減。若餘數最高位為0,商為0,除數繼續右移一位。
  c、一直做到餘數的位數小於除數時,該餘數就是最終餘數。
   CRC校驗程式編寫:
  編寫CRC校驗程式有兩種辦法:一種為計演算法,一種為查表法。下面對兩種方法分別討論。
①計演算法
計演算法就是依據CRC校驗碼的產生原理來設計程式。其優點是模組程式碼少,修改靈活,可移植性好。其缺點為計算量大。為了便於理解,這裡假定了三位資料,而多項式碼為A001(hex)。
在窗體上放置一命令按鈕Command1,並新增如下程式碼:

Private Sub Command1_Click()
    Dim CRC() As Byte
    Dim d() As Byte '待傳輸資料
    ReDim d(2) As Byte
    d(0) = 123
    d(1) = 112
    d(2) = 135
    CRC = CRC16(d) '呼叫CRC16計算函式
    'CRC(0)為高位
    'CRC(1)為低位
End Sub

注意:在資料傳輸時CRC的低位可能在前,而高位在後。

Function CRC16(data() As Byte) As String
    Dim CRC16Lo As Byte, CRC16Hi As Byte      'CRC暫存器
    Dim CL As Byte, CH As Byte                '多項式碼&HA001
    Dim SaveHi As Byte, SaveLo As Byte
    Dim i As Integer
    Dim Flag As Integer
    CRC16Lo = &HFF  
    CRC16Hi = &HFF
    CL = &H1    '多項式碼低位&H01
    CH = &HA0 '多項式碼高位&HA0
    For i = 0 To UBound(data)
        CRC16Lo = CRC16Lo Xor data(i) '每一個數據與CRC暫存器進行異或
        For Flag = 0 To 7
            SaveHi = CRC16Hi
            SaveLo = CRC16Lo
            CRC16Hi = CRC16Hi / 2            '高位右移一位
            CRC16Lo = CRC16Lo / 2            '低位右移一位
            If ((SaveHi And &H1) = &H1) Then '如果高位位元組最後一位為1
                CRC16Lo = CRC16Lo Or &H80      '則低位位元組右移後前面補1
            End If                           '否則自動補0
            If ((SaveLo And &H1) = &H1) Then '如果LSB為1,則與多項式碼進行異或
                CRC16Hi = CRC16Hi Xor CH
                CRC16Lo = CRC16Lo Xor CL
            End If
        Next Flag
    Next i
    Dim ReturnData(1) As Byte
    ReturnData(0) = CRC16Hi              'CRC高位
    ReturnData(1) = CRC16Lo              'CRC低位
    CRC16 = ReturnData
End Function

②查表法
  查表法的優缺點與計演算法的正好相反。為了便於比較,這裡所有的假定與計演算法的完全相同,都而在窗體上放置一個Command1的按鈕,其程式碼部分與上面的也完全一致。下面只介紹CRC函式的編寫原始碼。

Private Function CRC16(data() As Byte) As String
    Dim CRC16Hi As Byte
    Dim CRC16Lo As Byte
    CRC16Hi = &HFF
    CRC16Lo = &HFF
    Dim i As Integer
    Dim iIndex As Long
    For i = 0 To UBound(data)
        iIndex = CRC16Lo Xor data(i)
        CRC16Lo = CRC16Hi Xor GetCRCLo(iIndex)        '低位處理
        CRC16Hi = GetCRCHi(iIndex)                    '高位處理
    Next i
    Dim ReturnData(1) As Byte
    ReturnData(0) = CRC16Hi        'CRC高位
    ReturnData(1) = CRC16Lo        'CRC低位
    CRC16 = ReturnData
End Function

'CRC低位位元組值表

Function GetCRCLo(Ind As Long) As Byte
GetCRCLo = Choose(Ind + 1, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, _
&H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40, &H1, &HC0, &H80, &H41, &H1, &HC0, &H80, &H41, &H0, &HC1, &H81, &H40)
End Function

'CRC高位位元組值表

Function GetCRCHi(Ind As Long) As Byte
GetCRCHi = Choose(Ind + 1, &H0, &HC0, &HC1, &H1, &HC3, &H3, &H2, &HC2, &HC6, &H6, &H7, &HC7, &H5, &HC5, &HC4, &H4, &HCC, &HC, &HD, &HCD, &HF, &HCF, &HCE, &HE, &HA, &HCA, &HCB, &HB, &HC9, &H9, &H8, &HC8, &HD8, &H18, &H19, &HD9, &H1B, &HDB, &HDA, &H1A, &H1E, &HDE, &HDF, &H1F, &HDD, &H1D, &H1C, &HDC, &H14, &HD4, &HD5, &H15, &HD7, &H17, &H16, &HD6, &HD2, &H12, &H13, &HD3, &H11, &HD1, &HD0, &H10, &HF0, &H30, &H31, &HF1, &H33, &HF3, &HF2, &H32, &H36, &HF6, &HF7, &H37, &HF5, &H35, &H34, &HF4, &H3C, &HFC, &HFD, &H3D, &HFF, &H3F, &H3E, &HFE, &HFA, &H3A, &H3B, &HFB, &H39, &HF9, &HF8, &H38, &H28, &HE8, &HE9, &H29, &HEB, &H2B, &H2A, &HEA, &HEE, &H2E, &H2F, &HEF, &H2D, &HED, &HEC, &H2C, &HE4, &H24, &H25, &HE5, &H27, &HE7, &HE6, &H26, &H22, &HE2, &HE3, &H23, &HE1, &H21, &H20, &HE0, &HA0, &H60, _
&H61, &HA1, &H63, &HA3, &HA2, &H62, &H66, &HA6, &HA7, &H67, &HA5, &H65, &H64, &HA4, &H6C, &HAC, &HAD, &H6D, &HAF, &H6F, &H6E, &HAE, &HAA, &H6A, &H6B, &HAB, &H69, &HA9, &HA8, &H68, &H78, &HB8, &HB9, &H79, &HBB, &H7B, &H7A, &HBA, &HBE, &H7E, &H7F, &HBF, &H7D, &HBD, &HBC, &H7C, &HB4, &H74, &H75, &HB5, &H77, &HB7, &HB6, &H76, &H72, &HB2, &HB3, &H73, &HB1, &H71, &H70, &HB0, &H50, &H90, &H91, &H51, &H93, &H53, &H52, &H92, &H96, &H56, &H57, &H97, &H55, &H95, &H94, &H54, &H9C, &H5C, &H5D, &H9D, &H5F, &H9F, &H9E, &H5E, &H5A, &H9A, &H9B, &H5B, &H99, &H59, &H58, &H98, &H88, &H48, &H49, &H89, &H4B, &H8B, &H8A, &H4A, &H4E, &H8E, &H8F, &H4F, &H8D, &H4D, &H4C, &H8C, &H44, &H84, &H85, &H45, &H87, &H47, &H46, &H86, &H82, &H42, &H43, &H83, &H41, &H81, &H80, &H40)
End Function

四、LRC(Longitudinal Redundancy Check/縱向冗餘校驗)

方法一:
buf[]傳入位元組,index起始位,bytetotal要校驗的長度。

int xor16(unsigned char buf[], int index, long bytetotal)
{
//  unsigned char buff = 0;
    int buff=0;
  int i;
  for (i = index; i <bytetotal; i++) {
  buff = buff^(int)buf[i];
  }
  retu

rn buff;
}
方法二:

unsigned char calc_lrc2(unsigned char* data, int data_len)
{
    unsigned char lrc = 0;
    for (int i = 0; i < data_len; i++)
    {
     lrc ^=  data[i];
     printf("%02X\n",lrc);
    }
    return lrc;
}

本文來自部落格園,作者:{臧佳耀},轉載請註明原文連結:{https://www.cnblogs.com/xxxxxz/p/15169845.html#/c/subject/p/15169845.html}