// 生成modbus CRC16数据

时间:2021-08-25 02:58:37

     CRC-16 / MODBUS :

1)CRC寄存器初始值为 FFFF;即16个字节全为1;

2)CRC-16 / MODBUS的多项式A001H (1010 0000 0000 0001B) ‘H’表示16进制数,‘B’表示二进制数

计算步骤为: 
(1).预置 16 位寄存器为十六进制 FFFF(即全为 1) ,称此寄存器为 CRC  寄存器;  
(2).把第一个 8  位数据与 16  位 CRC  寄存器的低位相异或,把结果放于 CRC  寄
存器; 

(3).检测相异或后的CRC寄存器的最低位,若最低位为1:CRC寄存器先右移1位,再与多项式A001H进行异或;若为0,则CRC寄存器右移1位,无需与多项式进行异或。

(4).重复步骤 3  ,直到右移 8  次,这样整个 8 位数据全部进行了处理; 
(5).重复步骤 2  到步骤4,进行下一个 8  位数据的处理; 
(6).最后得到的 CRC  寄存器即为 CRC 码。 

附参考:

数据(16进制):01 03 61 00 00 02 CRC校验:F7 DB

附C语言实现代码:


#include <stdio.h>

int main(void)
{
    unsigned short tmp = 0xffff;
    unsigned short ret1 = 0;
    unsigned char buff[6] = {0};
    buff[0] = 0x01;
    buff[1] = 0x03;
    buff[2] = 0x61;
    buff[3] = 0x00;
    buff[4] = 0x00;
    buff[5] = 0x02;

    for(int n = 0; n < 6; n  ){/*此处的6 -- 要校验的位数为6个*/
        tmp = buff[n] ^ tmp;
        for(int i = 0;i < 8;i  ){  /*此处的8 -- 指每一个char类型又8bit,每bit都要处理*/
            if(tmp & 0x01){
                tmp = tmp >> 1;
                tmp = tmp ^ 0xa001;
            }
            else{
                tmp = tmp >> 1;
            }
        }
    }
    /*CRC校验后的值*/
    printf("%Xn",tmp);
    /*将CRC校验的高低位对换位置*/
    ret1 = tmp >> 8;
    ret1 = ret1 | (tmp << 8);
    printf("ret: %Xn",ret1);
    return 0;
}
输出结果:

F7DB
ret: DBF7



// 生成modbus CRC16数据
function CRC16(sSrc:shortstring):shortstring;
var
  tmp: word;
  ret1: word;
  buff: array of byte;
  n:integer;
  i:integer;

  ilen:Integer; //ssrc length
begin
  if trim(ssrc)=‘‘ then exit;

  tmp:= $FFFF;
  ret1:= 0;

  ssrc:= Trim(ssrc);
  ssrc:= StringReplace(sSrc, ,‘‘,[rfReplaceAll]);
  ilen:= length(ssrc);

  SetLength(buff,ilen div 2);
  i:=1;
  while i<ilen do
  begin
    buff[(i-1)div 2]:= StrToInt($ sSrc[i] sSrc[i 1]);
    i:=i 2;
  end;

  for n := 0 to Length(buff)-1 do  //*此处的6 -- 要校验的位数为6个*/
  begin
    tmp:= buff[n] xor tmp;
    for I := 0 to 7 do  //*此处的8 -- 指每一个char类型又8bit,每bit都要处理*/
    begin
      if(tmp and $01)<>0 then
      begin
        tmp:= tmp shr 1;
        tmp:= tmp xor $A001;
      end
      else
      begin
        tmp:= tmp shr 1;
      end;
    end;
  end;

  ret1 := tmp shr 8;        //*将CRC校验的高低位对换位置*/
  ret1 := ret1 or (tmp shl 8);
  Result:= IntToHex(ret1,4);

  //返回16进制串 用 空格 分开  crc 暂定 2字节
  result:= Result[1] Result[2]   Result[3] Result[4];
end;