-2

Good day everyone. I am trying to create a software to comunicate modbus devices to my software. I have problem on CRC16 sometimes the device respond sometimes not.

Details below:

function CRC16(Data: AnsiString): AnsiString;
var
 i,j,iSum,f : Integer;
begin
 iSum := $FFFF;
 for i := 1 to Length(Data) do
 begin
  iSum := iSum xor Ord(Data[i]);
  for j := 1 to 8 do
  begin
   f := iSum and $0001;
   iSum := iSum shr 1;
   if f = 1 then iSum := iSum xor $A001;
  end;
 end;
 Result := AnsiChar(Lo(iSum)) + AnsiChar(Hi(iSum));
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
  YearVar : String;
  AnsiOrig : ansiString;
  Ansi : ansiString;
  Ansi2 : ansiString;

  YearConvert : Integer;
  YearUpdater : String;
  YearUpdaterCRC : String;

begin
  CloseAllConnection;
  ComPortUpdate.Open;

  if ComPortUpdate.Connected then
  Begin
    YearConvert := StrToInt(Edit1.Text);

    AnsiOrig := IntToHex(YearConvert,4);
    Ansi := Copy(AnsiOrig,1,2);
    Ansi2 := Copy(AnsiOrig,3,2);

    {ShowMessage(AnsiOrig);
    ShowMessage(Ansi);
    ShowMessage(Ansi2);  }

    YearUpdater :=  chr(StrToInt('$' + EditAddress.Text)) + chr($06) + chr($02)+
     chr($04) +  chr(StrtoInt('$' + Ansi)) + chr(StrtoInt('$' + Ansi2));

     YearUpdaterCrc := CRC16(YearUpdater);

     //ShowMessage(StringToHex(YearUpdater + YearUpdaterCRC));
     ComPortUpdate.WriteStr(YearUpdater + YearUpdaterCRC);

     ComPortUpdate.ClearBuffer(True,True);
  End
  else
  begin
    ShowMessage('Communication port is not connected');
  end;
end;

This works:

YearUpdater := chr(StrToInt('$' + EditAddress.Text)) + chr($06) + chr($02) + chr($04) +
               chr($07) + chr($E0);

but this does not work:

YearUpdater := chr(StrToInt('$' + EditAddress.Text)) + chr($06) + chr($02) + chr($04) +  
                chr($07) + chr($DF);

I think has a wrong check digit.

Please help, or maybe post a working CRC16 function. Thanks in advance.

LU RD
  • 34,438
  • 5
  • 88
  • 296

2 Answers2

0

Normally, in RS232 communication, I use only strings or chars 8-bit lenght. Try changing all variables from string to ansistring and use Ansichar() instead of Chr().

the line to change is this:

YearUpdater := chr(StrToInt('$' + EditAddress.Text)) + chr($06) + chr($02)+ chr($04) + chr(StrtoInt('$' + Ansi)) + chr(StrtoInt('$' + Ansi2));

YearUpdater must be Ansistring.

Lorenzo
  • 23
  • 3
0

From my point of view your CRC-16 function is wrong. Can you try this?

procedure ByteCRC(Data: Byte; var CRC: Word);
var i: Byte;
begin
  for i := 1 to 8 do
  begin
    CRC := CRC shr 1;
    if (Data and $01) xor (CRC and $0001) > 0 then
      CRC := CRC xor $A001;
    Data := Data shr 1;
  end;
end;

function CRC16(Data: AnsiString): AnsiString;
var
  i: cardinal;
  CRC: Word;
begin
  CRC := 0;
  for i := 1 to length(s) do 
    ByteCRC(ord(s[i]), CRC);
  result := AnsiChar(lo(CRC)) + AnsiChar(hi(CRC));
end;