zoukankan      html  css  js  c++  java
  • 如何使用Delphi编写Modbus RTU CRC16的校验码

    在工业控制中,Modbus RTU CRC16的校验码用的比较广泛,包括本人富士产品中,PC与伺服电机以及PC与VP系列的变频器的Modbus RTU通讯中都使用到了CRC16.

        而对CRC16的计算的方式基本上有2种:第一种,使用双循环依照CRC的计算方法进行计算,第二种,采用查表的方式。本人愚钝无比,从网络上搜来的查表法都与实际的正确CRC16的结果有所差异,因此编写了一个小程序供自己使用。
       软件的界面很简单,输入诸如“010303020014”的值,然后每2个字符作为一个字节,填入字节数,然后就可以计算出校验码,校验码的多项式为:X16+X15+X2+1.
     
     
    实现的源代码如下:
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
     
    type
      TForm1 = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        Edit2: TEdit;
        Edit3: TEdit;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Memo1: TMemo;
        Label4: TLabel;
      function CalCRC16(AData:array of Byte;AStart,AEnd:Integer):Word;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
    //××××××××××××××××××××××××××
    // CalCRC16用于计算Modbus RTU的CRC16
    // 多项式公式为X16+X15+X2+1
    //××××××××××××××××××××××××××
    function TForm1.CalCRC16(AData:array of Byte;AStart,AEnd:Integer):Word;
    const
      GENP=$A001;  //多项式公式X16+X15+X2+1(1100 0000 0000 0101)
    var
      crc:Word;
      i:Integer;
      tmp:Byte;
    procedure CalOneByte(AByte:Byte);  //计算1个字节的校验码
    var
    j:Integer;
    begin
      crc:=crc xor AByte;   //将数据与CRC寄存器的低8位进行异或
      for j:=0 to 7 do      //对每一位进行校验
      begin
        tmp:=crc and 1;        //取出最低位
        crc:=crc shr 1;        //寄存器向右移一位
        crc:=crc and $7FFF;    //将最高位置0
        if tmp=1 then         //检测移出的位,如果为1,那么与多项式异或
          crc:=crc xor GENP;
          crc:=crc and $FFFF;
      end;
    end;
    begin
      crc:=$FFFF;             //将余数设定为FFFF
      for i:=AStart to AEnd do   //对每一个字节进行校验
        CalOneByte(AData[i]);
      Result:=crc;
    end;
     
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Data:array[0..255] of Byte;
      i,j,Count:Integer;
      Res:Word;
      szData:string;
    begin
      szData:=Form1.Edit2.Text;    //读入欲校验的字符串
      Count:=StrToInt(form1.Edit3.Text); //读入需要计算的字符串长度
      i:=1;
      j:=0;
      for j:=0 to Count-1 do
      begin
        if (i mod 2)=0 then    //每2个字符放入一个字节中
             i:=i+1;
        if i>=Length(szData) then
            exit;
        Data[j]:=StrToInt('$'+copy(szData,i,2)); //取出字符并转换为16进制数
        i:=i+1;
      end;
     
      Res:=CalCRC16(Data,Low(Data),Count-1);
      form1.Edit1.Text:=IntToHex(Res,4);
    end;
     
    end.
     
    原贴:
    http://blog.163.com/shcima@yeah/blog/static/107821988201062105441133/
     
     

    你这个程序有问题,有空联系我,不对。我的QQ是992725706

    2011-08-21 14:31
     cvlsam 回复 dfdfdfdf
    已经用于实际项目中了……
    2015-05-07 11:09
    15751010184 回复 dfdfdfdf
    不要怀疑这个程序的正确性。。。。不过modbus上使用可能是需要把高低对调一下,别的我就不知道了!
      Res:=CalCRC16(Data,Low(Data),Count-1);
      crc:=IntToHex(Res,4);
      crcL:=crc[3]+crc[4] ;
      crcH:=crc[1]+crc[2] ;
      memo1.Text:=crcL+crcH;
    2015-05-07 11:04
    不过在modbus通讯字符串里,那个得到的校验码确实需要把高位和低位对调一下。。。但是任然万分感激楼主把我从一个星期的蛋疼中解救出来。。。。楼主我能加你qq么?以后多请教一下你。。。。
    2015-05-07 11:00
    真是感激啊。。。。。。位校验程序网上很多,关键就在需要校验的字符怎么处理再给予校验,各种坑啊。。。。楼主贴出了字符到校验的处理全过程。。。。。业界良心啊!!!!!!!!
    2014-02-20 23:03
    1
    您太厉害了 好佩服
    2013-07-21 17:41
    patchhome

    好像计算出来的高2位和低2位应该对调才和设备的对上。

    2011-05-16 08:40
    2010-09-19 10:50
    恩,我也才刚冲学校走出来, 单位要求学习delphi,先在编城中有关通讯这块遇到问题,主要用modbus协议CRC的算法,有空向您多请教
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    TCP/IP 13学习笔记
    代码注入的三种方法
    一个简单的GTK的例子程序
    打印同样一个数据,竟然出现不同的结果,解决方法。
    解决multiple definition of的方法
    anjuta的安装、配置以及第一个hello程序
    rhythmbox中文乱码的解决方法
    Windows 和 Linux开发工具对比
    debian(包括ubuntu)命令行下的中文支持
    如何解决warning: no newline at end of file?
  • 原文地址:https://www.cnblogs.com/zhangzhifeng/p/5577634.html
Copyright © 2011-2022 走看看