Modbus CRC16 Calculation


I’m having an issue with the GenerateForwardCrc16OnString method.

I’m using a USB to FTDI serial device to send modbus strings to a J1939 converter. But unfortunately I haven’t got to that point yet.

The J1939 converter has an example modbus messages I’m testing my RS232 output with.


when I duplicate that message in PAC Control and use GenerateForwardCrc16OnString on it, the CRC that’s generated is FE95.


I’ve double checked the example CRC with a CRC generator I wrote in C# and it checks out. So I’m thinking I’m missing something small and silly in PAC Control.
I’ve used Forward and Reverse, etc. to no avail.

My code:

if (HasDownTimerExpired(CANout_Timer) == 1 or CANout_SendImmediately == 1) then

    SetDownTimerPreset(CANout_Delay, CANout_Timer);        

    CANout_SendImmediately = 0;

    CANout_Message = Chr(0x01) + Chr(0x10) + Chr(0x00) + Chr(0x00) + Chr(0x00) + Chr(0x01) + Chr(0x02) + Chr(0x12) + Chr(0x34);

    //CANout_Checksum = 0xAB27; // known checksum in hex
    //CANout_Checksum = 43815; // known checksum in dec

    // generate our own
    CANout_Checksum = GenerateForwardCrc16OnString(0, CANout_Message);


    NumberToHexString(CANout_Checksum, CANout_CRC); // convert to hex

    CANout_Message = CANout_Message + CANout_CRC; // append

Can anyone see any issue with what I’m doing? I’m wondering if I should just switch to codesys and output the J1939 natively.

Great question.

Paging @greichert for the Codesys question (Im thinking yes, the less middleware the better usually).
Paging @philip and @torchard for Modbus and code experience.

Thanks for the quick reply, Beno.

I’d really prefer not to switch, it’ll require rewriting a lot of code and then teaching my Techs to use it.
But, c’est la vi.

What is the additional data at the end (46 45)? These are being included in your check which is different than the example posted.

Hi Phil,

46, 45 are the FE portion of the FE95 checksum

The checksum should only be two bytes.

Use GenerateReverseCrc16OnString and put a -1 as the seed for the first parameter instead of 0 as Modbus spec wants to start with 0xFFFF on the CRC.

Then only use the 2 least significant bytes from the result, swap them around and you should be golden.

CANout_Checksum = "";
//Cal CRC
nTemp2 = GenerateReverseCrc16OnString(-1, CANout_Message);
// Add CRC
nTemp1 = nTemp2 bitand 0xFF;
CANout_Checksum += chr(nTemp1);
nTemp1 = (nTemp2 bitand 0xFF00) >> 8;
CANout_Checksum += chr(nTemp1);

Okay - you are appending converted hex string characters to binary data - don’t do that.


Phil, you’re a legend. It works like a dream.

Okay - you are appending converted hex string characters to binary data - don’t do that.

Yeah. I started scratching my head when I saw this. That was the something silly I was doing and the bit shifting was the thing I was missing!

Thanks Phil and Beno, have a great weekend!