最好是8位的

解决方案 »

  1.   

    以下包括crc的8位、16位、32位的算法,结帖吧,老兄!!
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls;type
      TForm1 = class(TForm)
        Memo1: TMemo;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        GenPoly8Edit: TEdit;
        GenPoly16Edit: TEdit;
        GenPoly32Edit: TEdit;
        TestCRC8Btn: TButton;
        TestCRC16Btn: TButton;
        TestCRC32Btn: TButton;
        CalCRC8Btn: TButton;
        CalCRC16Btn: TButton;
        CalCRC32Btn: TButton;
        CRC8ResultEdit: TEdit;
        CRC16ResultEdit: TEdit;
        CRC32ResultEdit: TEdit;
        procedure FormCreate(Sender: TObject);
        procedure TestCRC16BtnClick(Sender: TObject);
        procedure TestCRC8BtnClick(Sender: TObject);
        procedure TestCRC32BtnClick(Sender: TObject);
        procedure CalCRC16BtnClick(Sender: TObject);
        procedure CalCRC8BtnClick(Sender: TObject);
        procedure CalCRC32BtnClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;  // 生成多项式的值(多项式因子)
      // 注意:CRC16是数据流的高位先计算,多项式因子不变
      //   而CRC32和CRC8都是数据流的低位先计算,所以多项式因子的高/低位对调
      //   比如CRC32由$04C11DB7变为$EDB88320,CRC8由$31变为$8C
      GenPoly32: DWord; // CRC-32 = X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1
                        // 00000100 11000001 00011101 10110111($04C11DB7) 低位先行($EDB88320)
      GenPoly16: Word;  // CRC-CCITT16 = X16+X12+X5+1, 00010000 00100001($1021) 高位先行
                        // CRC-16      = X16+X15+X2+1, 10000000 00000101($8005) 高位先行
      GenPoly8:  Byte;  // CRC-8 = X8+X5+X4+1, 00110001($31) 低位先行($8C)
      GenPoly4:  Byte;  // CRC-4 = X4+X1+1, 0011($03)  CRC32Tab: array [0..255] of DWord; // CRC32快速计算查表
      CRC16Tab: array [0..255] of Word;  // CRC16快速计算查表
      CRC8Tab : array [0..255] of Byte;  // CRC8 快速计算查表implementation{$R *.DFM}///////////////////////////////////////////////////////////
    // 16位CRC:按位计算,速度最慢,占用空间最少
    // 注:数据流是高位先行
    ///////////////////////////////////////////////////////////
    function CalCRC16(data, crc, genpoly: Word): Word;
    var i: Integer;
    begin
      // 方法1:摘自XMODEM协议
      crc := crc xor (data shl 8);
      for i:=0 to 7 do
        if (crc and $8000) <> 0 then // 只测试最高位
          crc := (crc shl 1) xor genpoly // 最高位为1,移位和异或处理
        else crc := crc shl 1;           // 否则只移位(乘2)
      Result := crc;
    {
      // 方法2:算法有些不同,但结果相同
      data := data shl 8; // 移到高字节
      for i:=7 downto 0 do
      begin
        if ((data xor crc) and $8000) <> 0 then // 只测试最高位
          crc := (crc shl 1) xor genpoly // 最高位为1,移位和异或处理
        else crc := crc shl 1;           // 否则只移位(乘2)
        data := data shl 1; // 处理下一位
      end;
      Result := crc;  // 方法3:摘自<<CRC算法原理及C语言实现>>
      for i:=7 downto 0 do
      begin
        if (crc and $8000) <> 0 then
          crc := (crc*2) xor genpoly // 余式CRC乘以2再求CRC
        else crc := crc*2;
        if (data and (1 shl i)) <> 0 then
          crc := crc xor genpoly; // 再加上本位的CRC
      end;
      Result := crc;
    }
    {
    ; MCS51的CRC-16计算函数(多项式因子为$1021, 高位先行)
    ; 调用:CRC16H/CRC16L=原CRC16值(16位,初始值为0000h),A=待计算数据(8位)
    ; 结果:CRC16H/CRC16L=计算后的CRC16值(16位)
    CalCRC16:
            push  00h          ; Save R0
            push  acc          ; Save Acc
            mov   r0,#08       ; 8 Bits In A Byte
            xrl   CRC16H,a     ; CRC16H ^= Data
    lp1:    clr   c            ; 0 Into Low Bit
            mov   a,CRC16L     ; CRC16H/CRC16L <<= 1
            rlc   a
            mov   CRC16L,a
            mov   a,CRC16H
            rlc   a
            mov   CRC16H,a
            jnc   lp2          ; Skip If Bit 15 Wasn't Set
            xrl   CRC16H,#10h  ; CRC16H/CRC16L ^= $1021
            xrl   CRC16L,#21h
    lp2:    djnz  r0,lp1       ; Repeat R0 More Times
            pop   acc          ; Recover Acc
            pop   00h          ; Recover R0
            ret
    }
    end;///////////////////////////////////////////////////////////
    // 16位CRC:生成CRC16表(256项),用于快速查表计算
    // 在程序初始化时就先调用,预先生成CRC16Tab[256]查表数据
    ///////////////////////////////////////////////////////////
    procedure InitCRC16Tab(genpoly: DWord);
    var i: Integer;
    begin
      for i:=0 to 255 do
        CRC16Tab[i] := CalCRC16(i,0,genpoly);
    end;///////////////////////////////////////////////////////////
    // 16位CRC:通过查表快速计算,速度快,占用空间多
    // 要预先生成CRCTab[256]查表数据
    ///////////////////////////////////////////////////////////
    function QuickCRC16(data, crc: Word): Word;
    begin
      // 方法1:按字节计算CRC,通过查表(256项)快速计算
      //        速度最快,占用空间最多,需要256项数据的表格空间
      crc := CRC16Tab[(crc shr 8) xor data] xor (crc shl 8);
      Result := crc;
    {
      // 方法2:按半字节计算CRC,通过查表(16项)快速计算
      //        速度比较快,占用空间也比较少,只需要表格的前16项数据
      crc := CRCTab[(crc shr 12) xor (data shr 4)] xor (crc shl 4);
      crc := CRCTab[(crc shr 12) xor (data and $0F)] xor (crc shl 4);
      Result := crc;
    }
    {
    ; MCS51的CRC-16快速查表计算函数
    ; 要预先生成CRC16查表数据,起始地址CRC16Tab,按高/低字节顺序存放(512字节)
    ; 调用:CRC16H/CRC16L=原CRC16值(16位,初始值为0000h),A=待计算数据(8位)
    ; 结果:CRC16H/CRC16L=计算后的CRC16值(16位)
    QuickCRC16:
            push  dph             ; Save DPH
            push  dpl             ; Save DPL
            push  acc             ; Save Acc
            mov   dptr,#CRC16Tab  ; Point To Table
            xrl   a,CRC16H        ; XOR High Of CRC With Character
            call  UTIL_ADCAD      ; Add 'A' To 'DPTR'
            call  UTIL_ADCAD      ; Add 'A' To 'DPTR' (Yes, Twice)
            clr   a               ; Get High Byte From Table Entry
            movc  a,@a+dptr
            xrl   a,CRC16L        ; XOR With Low
            mov   CRC16H,a        ; Store To High Of CRC
            clr   a               ; Get Low Byte From Table Entry
            inc   dptr
            movc  a,@a+dptr
            mov   CRC16L,a        ; Store To Low Of CRC
            pop   acc             ; Recover Acc
            pop   dpl             ; Recover DPL
            pop   dph             ; Recover DPH
            ret
    }
    end;
      

  2.   

    ///////////////////////////////////////////////////////////
    // 8位CRC:按位计算,速度最慢,占用空间最少
    // 注:数据流是低位先行,与16位CRC相反
    ///////////////////////////////////////////////////////////
    function CalCRC8(data, crc, genpoly: Byte): Byte;
    var i: Integer;
    begin
      // 方法1:摘自XMODEM协议, 模仿CRC16计算方法, 但是低位先行
      crc := crc xor data;
      for i:=0 to 7 do
        if (crc and $01) <> 0 then // 只测试最低位
          crc := (crc shr 1) xor genpoly // 最低位为1,移位和异或处理
        else crc := crc shr 1;           // 否则只移位(除2)
      Result := crc;
    {
      // 方法2:算法有些不同,但结果相同
      for i:=0 to 7 do
      begin
        if ((data xor crc) and $01) <> 0 then // 只测试最低位
          crc := (crc shr 1) xor genpoly // 最低位为1,移位和异或处理
        else crc := crc shr 1;           // 否则只移位(除2)
        data := data shr 1; // 处理下一位
      end;
      Result := crc;
    }
    {
    ; MCS51的CRC-8计算函数(多项式因子为$8C, 低位先行)
    ; 调用:B=原CRC8值(8位,初始值为00h),A=待计算数据(8位)
    ; 结果:B=计算后的CRC8值(8位)
    CalCRC8:
            push  00h          ; Save R0
            push  acc          ; Save Acc
            mov   r0,#08       ; 8 Bits In A Byte
            xrl   b,a          ; CRC8 ^= Data
    lp1:    clr   c            ; 0 Into High Bit
            mov   a,b          ; CRC8 >>= 1
            rrc   a
            mov   b,a
            jnc   lp2          ; Skip If Bit 0 Wasn't Set
            xrl   b,#8Ch       ; CRC8 ^= $8C
    lp2:    djnz  r0,lp1       ; Repeat R0 More Times
            pop   acc          ; Recover Acc
            pop   00h          ; Recover R0
            ret
    }
    end;///////////////////////////////////////////////////////////
    // 8位CRC:生成CRC8表(256项),用于快速查表计算
    // 在程序初始化时就先调用,预先生成CRC8Tab[256]查表数据
    ///////////////////////////////////////////////////////////
    procedure InitCRC8Tab(genpoly: DWord);
    var i: Integer;
    begin
      for i:=0 to 255 do
        CRC8Tab[i] := CalCRC8(i,0,genpoly);
    end;///////////////////////////////////////////////////////////
    // 8位CRC:通过查表快速计算,速度快,占用空间多
    // 注:数据流是低位先行,与16位CRC相反
    // 要预先生成CRC8Tab[256]查表数据
    ///////////////////////////////////////////////////////////
    function QuickCRC8(data, crc: Byte): Word;
    begin
      crc := CRC8Tab[crc xor data];
      Result := crc;
    {
    ; MCS51的CRC-8快速查表计算函数
    ; 要预先生成CRC8查表数据,起始地址CRC8Tab,按顺序存放(256字节)
    ; 调用:B=原CRC8值(8位,初始值为00h),A=待计算数据(8位)
    ; 结果:B=计算后的CRC8值(8位)
    QuickCRC8:
            push  dph             ; Save DPH
            push  dpl             ; Save DPL
            push  acc             ; Save Acc
            mov   dptr,#CRC8Tab   ; Point To Table
            xrl   a,b             ; XOR In CRC
            movc  a,@a+dptr       ; Get New CRC Byte
            mov   b,a             ; Store Back
            pop   acc             ; Recover Acc
            pop   dpl             ; Recover DPL
            pop   dph             ; Recover DPH
            ret
    }
    end;///////////////////////////////////////////////////////////
    // 32位CRC:按位计算,速度最慢,占用空间最少
    // 注:数据流是低位先行,与16位CRC相反
    ///////////////////////////////////////////////////////////
    function CalCRC32(data, crc, genpoly: DWord): DWord;
    var i: Integer;
    begin
      // 方法1:摘自XMODEM协议, 模仿CRC16计算方法, 但是低位先行
      crc := crc xor data;
      for i:=0 to 7 do
        if (crc and $01) <> 0 then // 只测试最低位
          crc := (crc shr 1) xor genpoly // 最低位为1,移位和异或处理
        else crc := crc shr 1;           // 否则只移位(除2)
      Result := crc;
    end;///////////////////////////////////////////////////////////
    // 32位CRC:生成CRC32表(256项),用于快速查表计算
    // 在程序初始化时就先调用,预先生成CRC32Tab[256]查表数据
    ///////////////////////////////////////////////////////////
    procedure InitCRC32Tab(genpoly: DWord);
    var i: Integer;
    begin
      for i:=0 to 255 do
        CRC32Tab[i] := CalCRC32(i,0,genpoly);
    end;///////////////////////////////////////////////////////////
    // 32位CRC:通过查表快速计算,速度快,占用空间多
    // 注:数据流是低位先行,与16位CRC相反
    // 要预先生成CRC32Tab[256]查表数据
    ///////////////////////////////////////////////////////////
    function QuickCRC32(data, crc: DWord): DWord;
    begin
      crc := CRC32Tab[Byte(crc xor data)] xor (crc shr 8);
      Result := crc;
    end;
      

  3.   

    ///////////////////////////////////////////////////////////
    // 初始化
    ///////////////////////////////////////////////////////////
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      GenPoly8 := StrToInt(GenPoly8Edit.Text);
      InitCRC8Tab(GenPoly8); // 先生成CRC8表(256项),用于快速查表计算  GenPoly16 := StrToInt(GenPoly16Edit.Text);
      InitCRC16Tab(GenPoly16); // 先生成CRC16表(256项),用于快速查表计算  GenPoly32 := StrToInt(GenPoly32Edit.Text);
      InitCRC32Tab(GenPoly32); // 先生成CRC32表(256项),用于快速查表计算
    end;///////////////////////////////////////////////////////////
    // 测试比较CRC16/CRC8/CRC32的不同算法
    // 若CRC初始值为0,则结果与快速查表表格数据相同
    ///////////////////////////////////////////////////////////
    procedure TForm1.TestCRC16BtnClick(Sender: TObject);
    var data, crc, crcstart: Word;
    begin
      crcstart := $1234; // $0000;
      Memo1.Clear;
      Memo1.Lines.Add('16bit CRC');
      for data:=0 to 255 do
      begin
        crc := CalCRC16(data,crcstart,GenPoly16); // 按位计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 4) + ' ';
      end;  Memo1.Lines.Add('');
      Memo1.Lines.Add('16bit Quick CRC');
      for data:=0 to 255 do
      begin
        crc := QuickCRC16(data,crcstart); // 按字节查表计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 4) + ' ';
      end;
    end;procedure TForm1.TestCRC8BtnClick(Sender: TObject);
    var data, crc, crcstart: Byte;
    begin
      crcstart := $12; // $00
      Memo1.Clear;
      Memo1.Lines.Add('8bit CRC');
      for data:=0 to 255 do
      begin
        crc := CalCRC8(data,crcstart,GenPoly8); // 按位计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 2) + '   ';
      end;  Memo1.Lines.Add('');
      Memo1.Lines.Add('8bit Quick CRC');
      for data:=0 to 255 do
      begin
        crc := QuickCRC8(data,crcstart); // 按字节查表计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 2) + '   ';
      end;
    end;procedure TForm1.TestCRC32BtnClick(Sender: TObject);
    var data, crc, crcstart: DWord;
    begin
      crcstart := $12345678; // $00000000;
      Memo1.Clear;
      Memo1.Lines.Add('32bit CRC');
      for data:=0 to 255 do
      begin
        crc := CalCRC32(data,crcstart,GenPoly32); // 按位计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 8) + '  ';
      end;  Memo1.Lines.Add('');
      Memo1.Lines.Add('32bit Quick CRC');
      for data:=0 to 255 do
      begin
        crc := QuickCRC32(data,crcstart); // 按字节查表计算CRC
        Memo1.Text := Memo1.Text + IntToHex(crc, 8) + '  ';
      end;
    end;///////////////////////////////////////////////////////////
    // 从文本字串中分解出16进制的数据,返回这些8位数据组成的字串
    // 文本字串分解规则:
    // 1.数据是用16进制表示的8位数据(如FC,3D等)
    // 2.每个数据只取最后两个16进制字符,如1F3D只取3D,前面多余部分抛弃
    // 3.每个数据之间用空格或回车换行等格式符号隔开
    ///////////////////////////////////////////////////////////
    function GetDataFromText(str: String): String;
    var i, p1, p2: Integer;
    begin
      Result := '';
      while str <> '' do
      begin
        i := 0;
        p1 := Pos(' ',str);
        p2 := Pos(#13#10,str);    if p1=1 then // 空格在最前面
        begin Delete(str,1,1); continue; end;
        if p2=1 then // #13#10在最前面
        begin Delete(str,1,2); continue; end;    if (p1=0) and (p2=0) and (str<>'') then // 都没有找到,结束
        begin
          i := StrToIntDef('$'+str,0);
          Delete(str,1,Length(str));
        end;
        if ((p1>0) and (p2=0)) or // 找到空格
           ((p1>0) and (p2>0) and (p1<p2)) then // 或都找到,但空格在前
        begin
          i := StrToIntDef('$'+Copy(str,1,p1-1),0);
          Delete(str,1,p1);
        end;
        if ((p1=0) and (p2>0)) or // 找到#13#10
           ((p1>0) and (p2>0) and (p1>p2)) then // 或都找到,但空格在后
        begin
          i := StrToIntDef('$'+Copy(str,1,p2-1),0);
          Delete(str,1,p2+1);
        end;
        Result := Result + Chr(i); // 8位数据转为字符
      end; // while
    end;///////////////////////////////////////////////////////////
    // 计算一组数据的CRC16/CRC8/CRC32结果
    // 数据来源于文本框中的数据字串
    ///////////////////////////////////////////////////////////
    procedure TForm1.CalCRC16BtnClick(Sender: TObject);
    var
      i: Integer;
      databuf: String;
      data, crc: Word;
    begin
      databuf := GetDataFromText(Memo1.Text); // 从文本中读取数据
      crc := 0; // CRC初始值
      for i:=1 to Length(databuf) do
      begin
        data := Ord(databuf[i]); // 字符转为8位数据
        crc := CalCRC16(data,crc,GenPoly16); // 按位计算CRC
    //    crc := QuickCRC16(data,crc); // 快速查表计算CRC
      end;
      CRC16ResultEdit.Text := 'CRC16 = ' + IntToHex(crc,4); // 显示结果
    end;procedure TForm1.CalCRC8BtnClick(Sender: TObject);
    var
      i: Integer;
      databuf: String;
      data, crc: Byte;
    begin
      databuf := GetDataFromText(Memo1.Text); // 从文本中读取数据
      crc := 0; // CRC初始值
      for i:=1 to Length(databuf) do
      begin
        data := Ord(databuf[i]); // 字符转为8位数据
        crc := CalCRC8(data,crc,GenPoly8); // 按位计算CRC
    //    crc := QuickCRC8(data,crc); // 快速查表计算CRC
      end;
      CRC8ResultEdit.Text := 'CRC8 = ' + IntToHex(crc,2); // 显示结果
    end;procedure TForm1.CalCRC32BtnClick(Sender: TObject);
    var
      i: Integer;
      databuf: String;
      data, crc: DWord;
    begin
      databuf := GetDataFromText(Memo1.Text); // 从文本中读取数据
      crc := 0; // CRC初始值
      for i:=1 to Length(databuf) do
      begin
        data := Ord(databuf[i]); // 字符转为8位数据
        crc := CalCRC32(data,crc,GenPoly32); // 按位计算CRC
    //    crc := QuickCRC32(data,crc); // 快速查表计算CRC
      end;
      CRC32ResultEdit.Text := 'CRC32 = ' + IntToHex(crc,8); // 显示结果
    end;end.