yesful 发表于 2010-10-27 14:54:16

关于CRC校验问题

最近学习delphi写modbus协议串口通信,在CRC校验上遇到了问题,搞不是很明白。这是我参考网上资料写的一个程序,但校验结果与我想要的校验结果不一致。请大家帮我看一下什么原因,看一下我这校验方法是否正确。(多项式为CRC-16的)我在网上找了两个CRC校验工具,校验结果不一样的,不明白。
疑问:在RTU模式,单片机接收的指令串是8个16进制数,那我在上位机上,往单片机发送的是ASICC码,如何转换?如我想发送指令串‘010300010001+校验码’,是直接发送,还是用strtohex()转换成Hex?在数据CRC校验和发送的形式时,数据是以字符串形,还是以10进制,还是以16进制这个问题,很不清晰。
希望大家多多指教。
unit modbusread;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, CPortCtl, CPort;

type

TDataByte = array of byte;

TForm1 = class(TForm)
    btnRead: TButton;
    edAdress: TEdit;
    edCRC: TEdit;
    Label1: TLabel;
    TXMemo: TMemo;
    Label2: TLabel;
    ComPort: TComPort;
    ComLed1: TComLed;
    ComLed2: TComLed;
    ComLed3: TComLed;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    btnSet: TButton;
    RXMemo: TMemo;
    Label6: TLabel;
    Label7: TLabel;
    Button2: TButton;
    btnCom: TButton;
    procedure btnSetClick(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure btnComClick(Sender: TObject);
    procedure ComPortAfterOpen(Sender: TObject);
    procedure ComPortAfterClose(Sender: TObject);
    procedure btnReadClick(Sender: TObject);
    procedure SendString(const Str : string);

private
    { Private declarations }
public
    { Public declarations }
end;

const
          CRCHi: array of byte =
        (
        $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00,
        $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1,
        $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81,
        $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40,
        $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $01,
        $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0,
        $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80,
        $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41,
        $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $00,
        $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0,
        $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80,
        $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $01, $C0, $80, $41,
        $00, $C1, $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $01,
        $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1,
        $81, $40, $00, $C1, $81, $40, $01, $C0, $80, $41, $00, $C1, $81,
        $40, $01, $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40,
        $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1, $81, $40, $01,
        $C0, $80, $41, $01, $C0, $80, $41, $00, $C1, $81, $40, $00, $C1,
        $81, $40, $01, $C0, $80, $41, $00, $C1, $81, $40, $01, $C0, $80,
        $41, $01, $C0, $80, $41, $00, $C1, $81, $40
        ) ;

        CRCLo: array ofbyte =
        (
        $00, $C0, $C1, $01, $C3, $03, $02, $C2, $C6, $06, $07, $C7, $05,
        $C5, $C4, $04, $CC, $0C, $0D, $CD, $0F, $CF, $CE, $0E, $0A, $CA,
        $CB, $0B, $C9, $09, $08, $C8, $D8, $18, $19, $D9, $1B, $DB, $DA,
        $1A, $1E, $DE, $DF, $1F, $DD, $1D, $1C, $DC, $14, $D4, $D5, $15,
        $D7, $17, $16, $D6, $D2, $12, $13, $D3, $11, $D1, $D0, $10, $F0,
        $30, $31, $F1, $33, $F3, $F2, $32, $36, $F6, $F7, $37, $F5, $35,
        $34, $F4, $3C, $FC, $FD, $3D, $FF, $3F, $3E, $FE, $FA, $3A, $3B,
        $FB, $39, $F9, $F8, $38, $28, $E8, $E9, $29, $EB, $2B, $2A, $EA,
        $EE, $2E, $2F, $EF, $2D, $ED, $EC, $2C, $E4, $24, $25, $E5, $27,
        $E7, $E6, $26, $22, $E2, $E3, $23, $E1, $21, $20, $E0, $A0, $60,
        $61, $A1, $63, $A3, $A2, $62, $66, $A6, $A7, $67, $A5, $65, $64,
        $A4, $6C, $AC, $AD, $6D, $AF, $6F, $6E, $AE, $AA, $6A, $6B, $AB,
        $69, $A9, $A8, $68, $78, $B8, $B9, $79, $BB, $7B, $7A, $BA, $BE,
        $7E, $7F, $BF, $7D, $BD, $BC, $7C, $B4, $74, $75, $B5, $77, $B7,
        $B6, $76, $72, $B2, $B3, $73, $B1, $71, $70, $B0, $50, $90, $91,
        $51, $93, $53, $52, $92, $96, $56, $57, $97, $55, $95, $94, $54,
        $9C, $5C, $5D, $9D, $5F, $9F, $9E, $5E, $5A, $9A, $9B, $5B, $99,
        $59, $58, $98, $88, $48, $49, $89, $4B, $8B, $8A, $4A, $4E, $8E,
        $8F, $4F, $8D, $4D, $4C, $8C, $44, $84, $85, $45, $87, $47, $46,
        $86, $82, $42, $43, $83, $41, $81, $80, $40
        );

var
Form1: TForm1;

WriteComStr : string; //写命令字
ReadComStr : string; //    读命令字

{对象参数}
Address : string ;//对象地址

implementation

{$R *.dfm}

function crc16(var dataaddress :byte; datalength: byte): word;
        var
          hi: byte;
          lo: byte;
          i: byte;
          index: byte;
          datadd: pbytearray;
        begin
          hi := $FF;
          lo := $FF;
    datadd := @dataaddress;
          i := 0;
          while (datalength > 0) do
          begin
          index := (hi xor datadd^);
          i := i + 1;
          hi := lo xor crchi;
      lo := crclo;
           datalength := datalength - 1;
          end;
          crc16 := hi shl 8 or lo;
        end;   


        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 := $01;
          CH := $A0; //A001 H 是CRC-16多项式代码
          for i := 1 to Length(Data) do
          begin
          CRC16Lo := CRC16Lo xor ord(Data); //每一个数据与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 //如果LSB 为1,则与多项式进行异或
      begin
                CRC16Hi := CRC16Hi xor CH;
                CRC16Lo := CRC16Lo xor CL;
              end;
          end;
          end;

          Result := IntToHex(CRC16Lo, 2) + IntToHex(CRC16Hi, 2);
        end;

function StrToHexStr(const S:string):string;
//字符串转换成16进制字符串
var
I:Integer;
begin
for I:=1 to Length(S) do
begin
    if I=1 then
      Result:=IntToHex(Ord(S),2)
    else Result:=Result+' '+IntToHex(Ord(S),2);
end;
end;

function HexStrToStr(const S:string):string;
//16进制字符串转换成字符串
var
t:Integer;
ts:string;
M,Code:Integer;
begin
t:=1;
Result:='';
while t<=Length(S) do
begin
    while not (S in ['0'..'9','A'..'F','a'..'f']) do
      inc(t);
    if (t+1>Length(S))or(not (S in ['0'..'9','A'..'F','a'..'f'])) then
      ts:='$'+S
    else
      ts:='$'+S+S;
    Val(ts,M,Code);
    if Code=0 then
      Result:=Result+Chr(M);
    inc(t,2);
end;
end;

procedure TForm1.btnSetClick(Sender: TObject);
begin
      ComPort.ShowSetupDialog;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    Form1.close;
end;

procedure TForm1.btnComClick(Sender: TObject);
begin
   if ComPort.Connected then
      ComPort.close
      else ComPort.open;
end;

procedure TForm1.ComPortAfterOpen(Sender: TObject);
begin
btnCom.Caption:='stop';
// ShowStatus;
end;

procedure TForm1.ComPortAfterClose(Sender: TObject);
begin
btnCom.Caption:='open';
//ShowStatus;
end;


procedure TForm1.SendString(const Str : string);
var obj : PAsync;
begin
    InitAsync(obj);
    try
    ComPort.WriteStrAsync(str,obj);
    ComPort.WaitForAsync(obj);
//    FTXNum := FTXNum + Length(Str);
    finally
    DoneAsync(obj);
//    Timer1.Enabled := True;
//    ShowTX;
    end;
end;


procedure TForm1.btnReadClick(Sender: TObject);
var str : string;
          Data1 : TDataByte;
          c:word;
          i,l:integer;
begin
    if not ComPort.Connectedthen
    showmessage('please opten compot!')
    else
   begin
       ReadComStr := edAdress.text+'0300010001' ;
       Str := ReadComStr+ModBusCRC(ReadComStr);
       l := Length(ReadComStr);
             Setlength(Data1,l);
             for i:=0 to l-1 do
             Data1:= ord(ReadComStr);
             c:=CRC16(Data1,l);
       edCRC.text := inttohex(C,4);
       SendString(Str);
       TXMemo.Text := TXMemo.Text + Str+'';
   end;
end;

end.
页: [1]
查看完整版本: 关于CRC校验问题