вот кому интересно функция на паскале подсчета CRC16 для ModBus:

function CRC16(Msg: string) :Word;
var
i, j :Integer;
begin
Result := $FFFF;
for i := 1 to Length(Msg)
do
begin
Result := Ord(Msg[i]) xor Result;
for j := 1 to 8
do
begin
if (Result and 1) = 1
then
Result := (Result shr 1) xor $A001
else
Result := Result shr 1;
end;
end;
end;

пример формирования посылки для запроса состояний дискретных входов на ModBus RTU для прибора с адресом 16:

Msg := #$10#$03#$00#$33#$00#$01;

Msg := Msg + Chr(Lo(CRC16(Msg))) + Chr(Hi(CRC16(Msg)));

отправляем посылку в порт и получаем ответ.