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;
}
上一篇:CSS(1)导入方式


下一篇:CSS :root 声明全局变量,var()函数