MODBUS CRC Generation

I've been trying to understand the implementation of CRC on a datasream that I send to and from an ESP32 via standard Bluetooth. Without having the technical knowledge to fully understand the CRC process, I've been able to implement (read:uncover) code that would appear to be common between the ESP32 and App Inventor. Namely, this is the link that has bee referred to by many:

I have managed to get this working on the ESP32 for a string i'm sending:

#define UInt16 uint16_t
// CRC should be DD18
char *t = (char *)"151.45671118|33.5678|0|123.4|A|0000000|12.3|16%";
// Compute the MODBUS RTU CRC
UInt16 ModRTU_CRC(char * buf, int len)
{
  UInt16 crc = 0xFFFF;
 
  for (int pos = 0; pos < len; pos++) {
    crc ^= (UInt16)buf[pos];          // XOR byte into least sig. byte of crc
 
    for (int i = 8; i != 0; i--) {    // Loop over each bit
      if ((crc & 0x0001) != 0) {      // If the LSB is set
        crc >>= 1;                    // Shift right and XOR 0xA001
        crc ^= 0xA001;
      }
      else                            // Else LSB is not set
        crc >>= 1;                    // Just shift right
    }
  }
  // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
  return crc;  
}

void setup()
{
  Serial.begin(9600);
  while(!Serial);
  delay(1000);
  
  Serial.println(ModRTU_CRC(t,strlen(t)),HEX);

@ABG has created an untested block set that i'll base my evolving understanding on here:

BUT. I don't just want to get the answer need without understanding how I get to the result I need. I'm still trying to understand the char *t = (char *) component at the start of the ESP32 code. Any help here or pointers to help me best understand this process would be appreciated.

Just as another note to this. I feel like I need to get a better grip on the basics of variables in all their different forms before I start playing with this too much.

I'm currently working with strings and arrays in arduino environment and I haven't quite grasped that either. So to try and bring that half-baked knowledge into this question right now might be a leap too far.

You are wise to treat cautiously.

I would start with
https://www.google.com/search?q=C+data+types

When learning data types, it is important to know

  • how many bytes are used?
  • how are negative values stored?
  • are the values big-endian or little-endian?
  • Is the data type composed of more than one smaller data types?
  • can the data type expand dynamically to cover more storage?
  • does the data type contain pointers to other data in memory?
  • is the encoding binary or decimal, if it is a number?
  • is the encoding of text simple ASCII, or is it extended to a multi-byte scheme like UTF-8 ?

AI2 tries to gloss over these questions, but primordial cave languages like C expose all the innards.

Thanks @ABG,

The guys over on the Arduino forums have helped me better understand how I was poorly constructing my Strings and i've now better understand how i'm actually combining doubles, floats, const chars, and ints into a string. I can now parse that string well on the ESP32, and while I still don't fully follow the maths on the CRC code (or the CRC process in general), I am getting repeatable and expected results.

Moving back over to AI2, I now understand the code (or the flow of code) you'd prepared in some older posts i've noted above. I've been able to modify this to interpret a broader range of messages than comma separated messages. I also realised the code relied on ASCII decimal entries, so to resolve this i've used the Xoma ASCII to decimal extension. This is the aia:

MODBUS_CRC16.aia (8.6 KB)

My next challenge is to resolve how to split the last value from a delimited text string. eg:

123|124345|A|12343.5|43455|7677
to:
123|124345|A|12343.5|43455

Noting the last value in the text string can be of various lengths.

Slightly more complicated than I thought. Here is my second attempt (after my first attempt failed)!

Uses the Uno Double Reverse to get rid of the last "|" delimiter.
Then it deletes the inverted )( brackets by splitting out the middle between those first and last characters.
Then breaks the split text into a list at the " ".
And finally picks the first item of that list.

I'm sure there's a simpler, more elegant way of doing it, but for now it's working.

Sorry, this isn't really the intent of this original post title.




Thank you. Nice procedures.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.