How to Calculate CRC Modbus RTU

Question:

I'm trying to calculate a modbus crc in a PIC application, but the returned crc is always incorrect compared to online simulators .. follow code

void CRC (unsigned char* msg, unsigned char* out)
{
    //char CRC16[2] = {0xFF,0xFF};
    unsigned int CRC16 = 0xffff; 
    unsigned int poly =  0xA001;
    unsigned char data[14];
    unsigned char crc [2];

    for (int i=0; i<14; i++)
    {   
        CRC16 = (unsigned int)msg[i] ^ CRC16; //alteração data para msg
        for (int j=0; j<8; j++)
        {  
            CRC16 >>= 1;

            if(CRC16 & 0x0001 == 1) 
            {
                CRC16 ^= poly; 
            }
        }
    }
    crc[0] = CRC16 >> 8;
    crc[1] = CRC16 & 0b0000000011111111 ;
    strcpy (data,msg);
    strcat (data,crc);
    strcpy (out,data);


} 

I enter a 12 bytes buffer for the calculation and in the end the buffer must come out with the crc… but the crc calculation itself is returning the wrong value… what could be wrong in the code?

in case my message should return 8C0C but return 68FE

Answer:

The error is happening due to LSB check being after shift of CRC16 register.

This verification must take place before the shift operation, according to the code modified below:

void CRC (unsigned char* msg, unsigned char* out)
{
    //char CRC16[2] = {0xFF,0xFF};
    unsigned int CRC16 = 0xffff;
    unsigned int poly =  0xA001;
    unsigned char data[14];
    unsigned char crc [2];

    for (int i=0; i<14; i++)
    {
        CRC16 = (unsigned int)msg[i] ^ CRC16; //alteração data para msg
        for (int j=0; j<8; j++)
        {
          // AQUI: primeiro verifica, depois executa o shift
          if(CRC16 & 0x0001 == 1)  {
            CRC16 >>= 1;
            CRC16 ^= poly;
          } else {
            CRC16 >>= 1;
          }
        }
    }
    crc[0] = CRC16 >> 8;
    crc[1] = CRC16 & 0b0000000011111111 ;
    strcpy (data,msg);
    strcat (data,crc);
    strcpy (out,data);
}

Reference (pdf): MODBUS over Serial Line

Scroll to Top