HC-12 to HC-12 wireless transmision glitch

Hi!

I have designed a small project to transmit data from an Arduino Nano to a Arduino Pro Mini using the HC-12 wireless serial module.

The string transmitted looks like this: $RC2,35,0,0,22,33,13.2,10.0,*09 and is terminated in \r and \n.
Once the string is received on the receiving part, tha data is parsed with strtok() and each value between the commas is represented on a 0.96 OLED display.

If I simulate the codes on an online platform all goes well. The problem is that when I try it with the actual hardware I get a weird glitch.
Every now and then (maybe once every 2 seconds) the last values (13.2,10.0) and the first value (35) get mixed up. The display shows 35 instead of 13.2 or 10.0. The values still show up, but in the wrong place. And the wrong values show up for a split second but enough to be noticed.

The code on the transmit part is simple. It just transmits the string once every 20 milliseconds.
Here is the code on the receiving part.

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <tvg.h>


/*
//============
setup the display, declare all the vriables and states,etc.
//============
*/

void setup() {
  Serial.begin(9600);
  // initialize and clear display
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  pinMode(10, INPUT);
  pinMode(11, INPUT);
  pinMode(12, INPUT);
  pinMode(A0, INPUT); 
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.display();
  delay(3000);
  display.clearDisplay();

}

//============

void loop() {
    
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);  // this temporary copy is necessary to protect the original data
        parseData();              //   because strtok() used in parseData() replaces the commas with \0
        newData = false;
    }
  
 // displays a nice framework for the values 
  if (index>0 && index<6){
    display.drawLine(51, 2, 51, 25, WHITE);
    display.drawLine(51, 38, 51, 61, WHITE);
    display.drawLine(51, 45, 125, 45, WHITE);
    display.drawLine(2, 22, 49, 22, WHITE);
    display.drawLine(2, 41, 49, 41, WHITE);
    display.drawLine(2, 22, 2, 25, WHITE);
    display.drawLine(2, 38, 2, 41, WHITE);
    display.drawLine(49, 22, 49, 25, WHITE);
    display.drawLine(49, 38, 49, 41, WHITE);
    display.drawLine(49, 25, 51, 25, WHITE);
    display.drawLine(49, 38, 51, 38, WHITE);
    display.drawRect(0, 0, 128, 64, WHITE);
  }

  
  if (index==6){
    // here is the part where all the data is drawn on the OLED. The numbers are coordinates
    display.clearDisplay();
    hbrk = map(brk, 0, 100, 10, 51);
    hacc = map(acc, 0, 100, 10, 51);
    display.setTextSize(1);
    display.setCursor(2,5);
    display.print(F("LAP:"));
    display.setCursor(32,5);
    display.print(lap);
    display.setCursor(2,18);
    display.print(F("SPD:"));
    display.setCursor(32,18);
    display.print(spd);
    display.setCursor(2,31);
    display.print(F("RPM:"));
    display.setCursor(32,31);
    display.print(rpm);
    display.setCursor(2,44);
    display.print(F("GEAR:"));
    display.setCursor(32,44);
    display.print(gear);
    display.setCursor(86,55);
    display.println(F("BRK-ACC:"));
    display.fillRect(92, 52, 8, hbrk, WHITE);
    display.fillRect(113, 52, 8, hacc, WHITE);
    display.display();
    delay(20);
    display.clearDisplay();
    display.setTextSize(2);
  }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '

Please help me figure why this happens. I have tried delaying the transmitting, varying the transmit time, removing the \n and the \r - this last one made an impact as the glitches were happening a lot less.

Let me know if you need any more information. :slight_smile:

Thank you very much.

;
    char endMarker = ‘\n’;
    char rc;

while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = ‘\0’; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

char * strtokIndx; // this is used by strtok() as an index

strtokIndx = strtok(tempChars,",");    // get the first part - the string
    strcpy(messageFromPC, strtokIndx);    // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, “,”);    // Every now and then this part gets mixed up with SPD and LAP
    count = atoi(strtokIndx);
   
    strtokIndx = strtok(NULL, “,”);          // this continues where the previous call left off
    rpm = atoi(strtokIndx);
   
    strtokIndx = strtok(NULL, “,”);      // this continues where the previous call left off
    gear = atoi(strtokIndx);
   
    strtokIndx = strtok(NULL, “,”);    // this continues where the previous call left off
    acc = atoi(strtokIndx);
   
    strtokIndx = strtok(NULL, “,”);        // this continues where the previous call left off
    brk = atoi(strtokIndx);
   
    strtokIndx = strtok(NULL, “,”);
    lap = atof(strtokIndx);            // every now and then this part gets mixed up with COUNT

strtokIndx = strtok(NULL, “,”);
    spd = atof(strtokIndx);          // every now and then this part gets mixed up with COUNT
   
 
}


Please help me figure why this happens. I have tried delaying the transmitting, varying the transmit time, removing the \n and the \r - this last one made an impact as the glitches were happening a lot less. 

Let me know if you need any more information. :)

Thank you very much.

The code on the transmit part is simple. It just transmits the string once every 20 milliseconds.

At 9600 baud, how long does it take to send/receive the number of bytes you are sending?

PaulS:
At 9600 baud, how long does it take to send/receive the number of bytes you are sending?

The string varyes in lenght based on the input and the COUNT variable that is used as the first value in the string (it goes up to 65535) so the time it takes to transmit it also depends on the variables.

Will do a check today or tomorrow and will let you know. (Do you know any easy way to check this?)

Do you know any easy way to check this?

I'm interested in the theoretical minimum time, which can be calculated, if you know the maximum length of the string. 9600 baud means 9600 bits per second. There are 8 data bits and a start bit and a stop bit for each byte sent, so the maximum number of characters sent, per second, is 960. Sending data every 20 milliseconds means that you are sending 50 packets per second. 960 / 50 = 19.2 bytes per packet maximum.

All of your packets look to be larger than that. I count 40 in the example you showed.

So, I'm guessing that, if the Arduino sounded a tone every time it discarded a byte because the buffer was full, your Arduino would be constantly making noise.

You have 3 choices, as I see it.

  1. Send less data
  2. Send the data less often
  3. Pick up the pace. The stone ages are over. You can, very reliably, send data 12 times that fast, assuming that whatever is sending the data can be made to send it faster.

guzu:
The code on the transmit part is simple. It just transmits the string once every 20 milliseconds.

Try a much longer interval between messages.

Why would you need more than 5 or 10 messages per second?

...R

This post is the follow up post of Post#3 and Post#4.

In your string, there are 40 characters including \r (carriage rerun) and \n (new line). Each character is transmitted as 8-bit ASCII code in a 10-bit wide asynchronous telemetry frame. The string contains 40x10 = 400 bit data which you are sending again and again at 20 ms interval. The speed of transmission is 9600 Bd = 9600 bits/sec.

The transmission time for 400 bits is (1000/9600)*400 = 41.67 ms. That means that you have to wait for at least 41.67 ms time (practically, make it 100 ms) before you send the next string; but, you are sending the next string just after 20 ms time There is, clearly, an overlap (Fig-1) between the previous string and the current (next) string, and this overlapping makes glitches (noise = unintelligent information) in your received data.


Figure-1: String transmission time vs string repetition time

The remedies are proposed in Post#3 and Post#4.

You have 3 choices, as I see it.

  1. Send less data
  2. Send the data less often
  3. Pick up the pace. The stone ages are over. You can, very reliably, send data 12 times that fast, assuming that whatever is sending the data can be made to send it faster.

Try a much longer interval between messages.

Thank you all very much.
I ran some tests with a transmit rate of 5Hz (every 200 milliseconds) and so far everything is running smoothly. :slight_smile: So it was indeed the amount of data I was sending over the small time period.

Will try in the evening to see if I can get reliable readings at 10Hz with the 9600 baud rate. I am trying to keep the 9600 baud rate because this gives the HC-12 longer communication range.

Thank you for the time you took to help me. I really appreciate it!

guzu:
Will try in the evening to see if I can get reliable readings at 10Hz with the 9600 baud rate. I am trying to keep the 9600 baud rate because this gives the HC-12 longer communication range.

You have not told why you need a particular number of messages per second.

It may be worth reviewing the design of your system to see if it could equally well with fewer messages AND/OR maybe not all of the data needs to be transmitted each time.

...R

Robin2:
You have not told why you need a particular number of messages per second.

It may be worth reviewing the design of your system to see if it could equally well with fewer messages AND/OR maybe not all of the data needs to be transmitted each time.

...R

The system I designed is a data logging/transmitting for racing karts.
I wanted the high ”refresh rate” to be able to log the data as accurately as possible since it changes very fast at 130Km/h and 12.000 RPM.

The data transmitted is also used in an Android app (via Bluetooth) that combines it with GPS data and needs the $RC2 and *xx bytes to interpret the message correctly.

So the whole string needs to be send as one chunk of data. If you think of some improvements that could be made elsewhere or need any more info, just let me know.

Thank you.

guzu:
So the whole string needs to be send as one chunk of data. If you think of some improvements that could be made elsewhere or need any more info, just let me know.

This may be a situation where it is worth taking the trouble to send the data in binary format rather than as text.

If you can post 2 or 3 examples of complete messages I will have a think about how that could be done as simply as possible. Also let me know the max and min value for each data item.

Another thought is to record the data on an SD card for later analysis.

...R

Robin2:
This may be a situation where it is worth taking the trouble to send the data in binary format rather than as text.

If you can post 2 or 3 examples of complete messages I will have a think about how that could be done as simply as possible. Also let me know the max and min value for each data item.

Another thought is to record the data on an SD card for later analysis.

...R

Here are some example messages:

$RC2,,20,,,,322,0,100,100,0.0,34.8,,,,*31
$RC2,,21,,,,333,0,100,100,0.0,34.7,,,,*3f
$RC2,,22,,,,155,0,100,100,0.0,15.7,,,,*3d
$RC2,,23,,,,155,0,100,100,0.0,15.7,,,,*3c
$RC2,,24,,,,155,0,100,100,0.0,15.7,,,,*3b
$RC2,,25,,,,155,0,100,100,0.0,15.7,,,,*3a

And here are the expected values for the numbers:

$RC2 - does not change
1st number 1 - 65,535
2nd number 0 - 13,000
3rd number 0 - 6
4th number 0 - 100
5th number 0 - 100
6th number 0.0 - 999.9 (normally will go up to about 200.0)
7th number 0.0 - 999.9 (normally will go up to about 140.0)
*31 - HEX checksum for the string

The SD card log will come a bit later on.

Thank you all for taking the time to help me. :slight_smile: