高手們,請教下關于數據校驗的CRC算法啊,好郁悶,看到CSDN論壇也有一些相關的貼,好像有兩種方法,查表法和計算法,不知這兩種方法那種好點,因為crc的帖子還是看得不是很懂,請高手們可否做一個小的程序,兩個EDIT,一個按鈕就可以,第一個edit輸入一些16進制的字符串,按按鈕,第二個edit返回這一堆數的驗證碼啊,比如:輸入030301010001,按鈕,第二個edit顯示D5D4,好像是不是又涉及到一些字符串和16進制的問題,所以不是很懂,請教請教,最好是把程序發到我郵箱啦,無限感激,謝謝謝謝,我的郵箱是[email protected]

解决方案 »

  1.   


    //********************************************************
    //               生成crc16校验码
    //               s:要校验的字符串,len:字符串的长度
    //               返回值是2个字节的校验码              
    //********************************************************
    function  crc16(s:string;len:integer):word;
    var
      flag,c,crc:word;
      i,j:integer;
    begin
      crc:=$0000;
      for i:=1 to len do
      begin
        c:=ord(s[i]);
        c:=c shl 8;
        crc:=crc xor c;
        for j:=1 to 8 do
        begin
          flag:=crc and $8000;
          crc:=crc shl 1;
          if flag>0 then crc:=crc xor $8005;
        end;
      end;
      result:=crc;
    end;
      

  2.   

    re:yuqianyi1974
    你好,謝謝你發過來的程序啊,但是還想請教下下面的問題啊
    我一般是發送16進制的數據,比如03 03 01 01 00 01 校驗位(2位),這樣的格式啊,一個8個字節的,我用一些CRC校驗的工具算出來是D5 D4,但是你提供的那兩個程序計算出來都是A92610BB,不知是不是我那里說不清楚了,他那里只是寫是CRC校驗,我也不是很清楚是16,還是32啊,聽說還有8的啊,所以還想請教請教,謝謝發送格式:03 03 01 01 00 01 D5 D4 
      

  3.   

    8位的function Crc_8n(p: array of Byte; len: Byte): Byte;
    var
      j, cbit, aout, crc, crc_a, crc_b: Byte;
      i: Integer;
    begin
      crc := 0;
      i := 0;
      repeat
        crc_a := p[i];
        inc(i);
        j := 8;
        cbit := 1;
        repeat
          crc_b := crc_a;
          crc_b := crc_b xor crc;
          aout := crc_b and cbit;
          if aout <> 0 then begin
            crc := crc xor $18;
            crc := crc shr 1;
            crc := crc or $80;
          end else begin
            crc := crc shr 1;
          end;
          crc_a := crc_a shr 1;
          dec(j);
        until j = 0;
        dec(len);
      until len = 0;
      Result := crc;
    end;
      

  4.   

    CRC考验有那么好吗?
    我还有一个要查表的,要不要
      

  5.   

    謝謝大家的回答,我查了下需要是CRC16的啊,最好是做一個小的工程發到我郵箱啦,就是兩個edit,一個按鈕就可以啦,無限感激,郵箱:[email protected]
    謝謝
      

  6.   

    //********************************************************
    //               生成crc16校验码
    //               s:要校验的字符串,len:字符串的长度
    //               返回值是2个字节的校验码              
    //********************************************************
    function  crc16(s:string;len:integer):word;
    var
      flag,c,crc:word;
      i,j:integer;
    begin
      crc:=$0000;
      for i:=1 to len do
      begin
        c:=ord(s[i]);
        c:=c shl 8;
        crc:=crc xor c;
        for j:=1 to 8 do
        begin
          flag:=crc and $8000;
          crc:=crc shl 1;
          if flag>0 then crc:=crc xor $8005;
        end;
      end;
      result:=crc;
    end;
      

  7.   

    re:jacknes009
    謝謝你的回答啊,不過好像跟kampan兄一樣的哦,因為不知道這個返回來的WORD的怎樣轉換成一個字符串用edit來顯示啊???所以還請高手們能做做個小工程發到我有限啦,謝謝
    輸入:$03 03 01 01 00 01
    結果:$03 03 01 01 00 01 D5 D4謝謝謝謝
      

  8.   

    function  crc16(s:string;len:integer):string; 
    var 
      flag,c,crc:word; 
      i,j:integer; 
    begin 
      crc:=$0000; 
      for i:=1 to len do 
      begin 
        c:=ord(s[i]); 
        c:=c shl 8; 
        crc:=crc xor c; 
        for j:=1 to 8 do 
        begin 
          flag:=crc and $8000; 
          crc:=crc shl 1; 
          if flag>0 then crc:=crc xor $8005; 
        end; 
      end; 
      result:=IntToHex(crc,2); 
    end; 
      

  9.   

    function crc16(s: string; len: integer): string;
    var
      flag, c, crc: word;
      i, j: integer;
    begin
      crc := $0000;
      for i := 1 to (len div 2) do
      begin
        //c := ord(s[i]);    c := strtoint('$' + copy(s, (2*i-1), 2)); //16进制转10进制,每两位    c := c shl 8;
        crc := crc xor c;
        for j := 1 to 8 do
        begin
          flag := crc and $8000;
          crc := crc shl 1;
          if flag > 0 then crc := crc xor $8005;
        end;
      end;
      result := IntToHex(crc, 2);
    end;
      

  10.   

    re:oosmile
    你好,谢谢回答,但是我调用的时候算出来怎么不对的呢?奇怪
    我在edit1输入030301010001,按钮动作写:edit2.Text:=crc16(edit1.Text,6);
    但是edit2运行的结果是8A39,而不是D5 D4啊 ,D5 D4 才是对的啊?
    继续请教谢谢
      

  11.   

    谢谢各位的回答,听说还是查表法要消耗的计算机资源比较少,所以还是倾向与用查表法得到的CRC16算法啊,请高手们指导指导,最好是可以做一个例子工程发给我啦,谢谢
      

  12.   

    各位:
        如果我一边是用C语言写的校验程序,用的校验因子表进行校验的,一边是用DELPHI写的校验程序,假如就用
    这位大哥的:    //********************************************************
    //               生成crc16校验码
    //               s:要校验的字符串,len:字符串的长度
    //               返回值是2个字节的校验码              
    //********************************************************
    function  crc16(s:string;len:integer):word;
    var
      flag,c,crc:word;
      i,j:integer;
    begin
      crc:=$0000;
      for i:=1 to len do
      begin
        c:=ord(s[i]);
        c:=c shl 8;
        crc:=crc xor c;
        for j:=1 to 8 do
        begin
          flag:=crc and $8000;
          crc:=crc shl 1;
          if flag>0 then crc:=crc xor $8005;
        end;
      end;
      result:=crc;
    end;这样校验码一样吗?
      

  13.   

    继续请教题目内容:
    高手們,請教下關于數據校驗的CRC16算法啊,好郁悶,看到CSDN論壇也有一些相關的貼,好像有兩種方法,查表法和計算法,不知這兩種方法那種好點,因為crc16的帖子還是看得不是很懂,請高手們可否做一個小的程序,兩個EDIT,一個按鈕就可以,第一個edit輸入一些16進制的字符串,按按鈕,第二個edit返回這一堆數的驗證碼啊,比如:輸入030301010001,按鈕,第二個edit顯示D5D4,好像是不是又涉及到一些字符串和16進制的問題,所以不是很懂,請教請教,最好是把程序發到我郵箱啦,無限感激,謝謝謝謝,
    我的郵箱是[email protected]輸入:$03 03 01 01 00 01 
    結果:$03 03 01 01 00 01 D5 D4 
      

  14.   

    仪表通讯协议(MODBUS RTU)
    http://www.metersnet.com/download/modbus.pdf2.错误校验
    冗余循环码(CRC)包含2个字节,即16位二进制。CRC码由发送设备计算,放置于发送信息的尾部。接收信息的设备再重新计算接收到信息的 CRC码,比较计算得到的CRC码是否与接收到的相符,如果两者不相符,则表明出错。
    CRC码的计算方法是,先预置16位寄存器全为1。再逐步把每8位数据信息进行处理。在进行CRC码计算时只用8位数据位,起始位及停止位,如有奇偶校验位的话也包括奇偶校验位,都不参与CRC码计算。
    在计算CRC码时,8位数据与寄存器的数据相异或,得到的结果向低位移一字节,用0填补最高位。再检查最低位,如果最低位为1,把寄存器的内容与预置数相异或,如果最低位为0,不进行异或运算。
    这个过程一直重复8次。第8次移位后,下一个8位再与现在寄存器的内容相相异或,这个过程与以上一样重复8次。当所有的数据信息处理完后,最后寄存器的内容即为CRC码值。CRC码中的数据发送、接收时低字节在前。
    计算CRC码的步骤为:
    1) 预置16位寄存器为十六进制FFFF(即全为1)。称此寄存器为CRC寄存器;
    2) 把第一个8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器;
    3) 把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位;
    4) 如果最低位为0:重复第3步(再次移位); 如果最低位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
    5) 重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
    6) 重复步骤2到步骤5,进行下一个8位数据的处理;
    7) 最后得到的CRC寄存器即为CRC码。(二)、CRC校验码计算
    UINT crc
    void calccrc(BYTE crcbuf)
    {
    BYTE i;
    crc=crc ^ crcbuf;
    for(i=0;i<8;i++)
    {
    BYTE TT;
    TT=crc&1;
    crc=crc>>1;
    crc=crc&0x7fff;
    if (TT==1)
    crc=crc^0xa001;
    crc=crc&0xffff;
    }
    }
    delphi代码function crc16(s: string; len: integer): string;
    var
      flag, c, crc: word;
      i, j: integer;
    begin
      crc := $FFFF;
      for i := 1 to (len div 2) do
      begin
        c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位
        crc := crc xor c;
        for j := 1 to 8 do
        begin
          flag := crc and 1;
          crc := crc shr 1;
          if flag = 1 then crc := crc xor $A001;
        end;
      end;
      result := IntToHex(crc, 2);
    end;你再看看吧
      

  15.   

    少了两句,呵呵function crc16(s: string; len: integer): string;
    var
      flag, c, crc: word;
      i, j: integer;
    begin
      crc := $FFFF;
      for i := 1 to (len div 2) do
      begin
        c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位
        crc := crc xor c;
        for j := 1 to 8 do
        begin
          flag := crc and 1;
          crc := crc shr 1;
          crc := crc and $7FFF;
          if flag = 1 then
          begin
            crc := crc xor $A001;
            crc := crc and $FFFF;
          end;
        end;
      end;
      result := IntToHex(crc, 2);
    end;
      

  16.   

    非常感激回答啊,已经很接近啦,还有一点小问题啊,就是算出来应按是D5 D4,而上面这个算法算出来是D4 D5啊,好像高低位要反一下啊,谢谢,
      

  17.   

    faint……
    function crc16(s: string; len: integer): string; 
    var 
      flag, c, crc: word; 
      i, j: integer; 
    begin 
      crc := $FFFF; 
      for i := 1 to (len div 2) do 
      begin 
        c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位 
        crc := crc xor c; 
        for j := 1 to 8 do 
        begin 
          flag := crc and 1; 
          crc := crc shr 1; 
          crc := crc and $7FFF; 
          if flag = 1 then 
          begin 
            crc := crc xor $A001; 
            crc := crc and $FFFF;  
          end; 
        end; 
      end; 
      crc := ((crc and $FF00) shr 8) + ((crc and $FF) shl 8);
      result := IntToHex(crc, 2); 
    end;
      

  18.   

    modbus RTU?function ModBusCRC(Data: string): string; //生成modbus CRC数据
    var
      CRC16Lo, CRC16Hi, CL, CH, UseHi, UseLo: Dword;
      i, index: integer;
    begin
      CRC16Lo := $FF; //CRC16Lo为CRC寄存器低8位
      CRC16Hi := $FF; //CRC16Hi为CRC寄存器高8位
      CL := $1;
      CH := $A0; // A001 H 是CRC-16多项式代码
      for i := 1 to Length(Data) do  begin
        CRC16Lo := CRC16Lo xor ord(Data[i]); //每一个数据与CRC寄存器异或
        for index := 0 to 7 do begin
          UseHi := CRC16Hi;
          UseLo := CRC16Lo;
          CRC16Hi := CRC16Hi shr 1;
          CRC16Lo := CRC16Lo shr 1; //右移一位
          if ((UseHi and $1) = $1) then //如果高位字节最后一位是1的话
            CRC16Lo := CRC16Lo or $80; //低位字节右移后前面补1      if ((UseLo and $1) = $1) then begin//如果LSB 为1,则与多项式进行异或
            CRC16Hi := CRC16Hi xor CH;
            CRC16Lo := CRC16Lo xor CL;
          end;
        end;
      end;  Result := Char(CRC16Lo) + Char(CRC16Hi);
    end;    //计算CRC校验
        CRCData:=ModBusCRC(sendbuf);
        //加上CRC校验
        sendbuf:=sendbuf+CRCData;