分享

怎样在VB、C、DELPHI、汇编语言中使用CRC算法

 一路看山 2011-04-22


在无线电通信中,为了保证数据在传输中的完整性,我们通常需要检查其内容,最愚蠢的办法不过是回滚数据咯,需要让主机逐字节检查,不过那种方法很占用通信的时间。CRC效验是一种更好的方法。这样不必每回都回滚数据,只需通过CRC码来检测其完整性。大大节省了时间

为方便解释其原理,总结了CRC所有操作:

1.装一个16位的寄存器,所有数位均为1
2.取被校验串的一个字节与16位寄存器的高位字节进行"异或"运算.运算结果放入这个16位寄存器.
3.把这个16位寄存器向右移一位.
4.若向右(标记位)移出的位数是1,则生成多项式1010 0000 0000 0001和这个寄存器进行"异或"运算;若向右移出的位数是0,则返回步骤3.
5.重复步骤3和4,直至移出8位.
6.取被校验串的下一个字节
7.重复步骤3~6,直至被校验串的所有字节均与16位寄存器进行"异或"运算,并移位8次.
8.这个16位寄存器的内容即2字节CRC错误校验码.
生成CRC的代码:

C语言:
////////////////////////////////////////////////////////////////////////////
// Deions: 计算指定数据的CRC值, 依据的是国家标准协议中所定义的算法 //
// Parameters: //
// BYTE * 要计算CRC的数据 //
// int 被计算CRC的数据的字节数 //
////////////////////////////////////////////////////////////////////////////
WORD __fastcall TGBAdapterListener::GetCRCWord(BYTE * Buf, int BufLen)
{
WORD wRet = 0xFFFF;

for (int iIndex = 0; iIndex < BufLen; iIndex ++)
{
wRet = (WORD)(HIBYTE(wRet) ^ Buf[iIndex]);

for (int iLooper = 0; iLooper < 8; iLooper ++)
{
if (wRet & 0x0001)
{
wRet = (wRet >> 1) ^ 0xA001;
}
else
wRet = (wRet >> 1);
}
}
return wRet;
}


DELPHI语言:
\\一
GetCRCWord(Buf:array of byte; BufLen:integer):WORD;
var
wRet:WORD;
iIndex:integer;
iLooper:integer;
begin
wRet := $FFFF;
for iIndex :=0 to BufLen-1 do
begin
wRet := WORD(Hi(wRet) xor Buf[iIndex]);
for iLooper := 0 to 7 do
begin
if (wRet and $0001) = 1 then
wRet := (wRet shr 1) xor $A001
else
wRet := wRet shr 1;
end;
end;
result := wRet;
end;
\\二
GetCRCWord_2(Buf:PChar; BufLen:integer):WORD;
var
wRet:WORD;
iIndex:integer;
iLooper:integer;
begin
wRet := $FFFF;
for iIndex :=0 to BufLen-1 do
begin
wRet := WORD(Hi(wRet) xor Ord(Buf[iIndex]));
for iLooper := 0 to 7 do
begin
if (wRet and $0001) = 1 then
wRet := (wRet shr 1) xor $A001
else
wRet := wRet shr 1;
end;
end;
result := wRet;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
s:string;
len:integer;
a:array of byte;

crc16:integer;
begin
s := 'asdasd';
len := length(s);
SetLength(a, len);
CopyMemory(a,Pchar(s),len);
crc16 := GetCRCWord(a,len);
ShowMessage(IntToHex(crc16,4));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
s:string;
len:integer;
crc16:integer;
begin
s := 'asdasd';     
len := length(s);
crc16 := GetCRCWord_2(Pchar(s),len);
ShowMessage(IntToHex(crc16,4));
end;
////////////////////////////////////////////////////////////////////////////

VB算法:


Public CRC16(data() As Byte) As Byte()
   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
   Dim ReturnData(1) As Byte
    
   CRC16Lo = &HFF
   CRC16Hi = &HFF
   CL = &H1
   CH = &HA0
   For Ii = 0 To UBound(data)
       CRC16Lo = CRC16Lo Xor data(Ii) '每一个数据与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 Ii
   ReturnData(0) = CRC16Lo               'CRC低位
   ReturnData(1) = CRC16Hi               'CRC高位
   CRC16 = ReturnData
End


C算法:
void crc16(unsigned char r_data[],unsigned int length)
{
     unsigned char cl,ch;
     unsigned char savehi,savelo;
     int ii,flag;
     crc16hi=0xFF;
     crc16lo=0xFF;
     cl=0x1;
     ch=0xA0;
     for (ii=0;ii<length;ii++)
     {
         crc16lo=(crc16lo ^ r_data[ii]);
         for (flag=0;flag<8;flag++)
         {
             savehi=crc16hi;
             savelo=crc16lo;
             crc16hi=(crc16hi>>1);
             crc16lo=(crc16lo>>1);
             if ((savehi & 0x01)==0x01)
                     crc16lo=(crc16lo | 0x80);
             if ((savelo & 0x01)==0x01)
             {
                     crc16hi = (crc16hi ^ ch);
                     crc16lo = (crc16lo ^ cl);
             }        
         }
     }
}


汇编算法 :


;**********************************************************
;CRC16校验子程序
;R1 需进行CRC校验数据起始地址
;CRC16_L CRC校验数据低字节 CRC16_H CRC校验数据高字节
;R7 需进行CRC校验的字节数
;**********************************************************
CRC16:   
         MOV CRC16_L,#0FFH
         MOV CRC16_H,#0FFH
CRC16_LOOP1:              
         MOVX A,@R1
         XRL CRC16_L,A
         MOV R6,#08H
CRC16_LOOP2:
         MOV R3,CRC16_L
         MOV R4,CRC16_H
         CLR C
         MOV A,CRC16_H
         RRC A
         MOV CRC16_H,A
         MOV A,CRC16_L
         RRC A
         MOV CRC16_L,A
         JNC CRC16_STEP
         XRL CRC16_L,#01H
         XRL CRC16_H,#0A0H
CRC16_STEP:
         DJNZ R6,CRC16_LOOP2
         INC R1
         DJNZ R7,CRC16_LOOP1
         RETI

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多