Receiving data from 3 nano on 3 serial Mega

Hi,

I have a project with 1 Mega and 3 nano. Each nano have sensors and they are sending the results to the Mega via the 3 serial ports on the Mega. Each nano is sending the data with the RX pin using comma separated value with < and > as a start and end marker.

For my tests I didn’t connect any sensors on the nano yet, so to simulate
sensors values, I serial print the followings for sending;

Serial.print("<");
Serial.print(“B”);
Serial.print(",");
Serial.print(55);
Serial.print(",");
Serial.print(6666);
Serial.print(",");
Serial.print(115);
Serial.println(">");

I can see on the serial monitor of that nano <B,55,6666,115>

I did the same thing but with different values on the two other nano.

Each of them have their TX pin connect to RX1 RX2 and RX3 of the Mega.

My probleme is that the parsing is often mixing the data.

When it’s ok I can see on the Mega the following,

flowGrise 55
totalGrise 6666
voltsSolarPump 115

And then oups! it miss the last value and print the first one again at the 3rd position like this.

flowGrise 55
totalGrise 6666
voltsSolarPump 55

The missing data occure every 4 or 5 prints

I used the following code on the mega to parse the data and since I have to parse
the data from 3 different serial ports, I renamed the variable.

I didn’t put the full code with lcd display and other sensor connect directly to the
Mega but all the code for the data parsing is below.

#include <DS3231.h>
#include "Ultrasonic_1.h"
#include "Ultrasonic_2.h"
#include <Wire.h>
#include "Wire.h"
#include <OneWire.h>
#include "LCD.h"
#include "LiquidCrystal_I2C.h"
#include "RTClib.h"
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include "printf.h"



//To process data received on RX_1
const byte numChars = 64;
char receivedChars[numChars];
char tempChars[numChars]; 
char markID1[numChars] = {0};
int flowNoir;
int totalNoir;
int flowOrange;
int totalOrange;
boolean newData = false;


//To process data received on RX_2
const byte numChars2 = 64;
char receivedChars2[numChars2];
char tempChars2[numChars2]; 
char markID2[numChars2] = {0};
int flowGrise;
int totalGrise;
int voltsSolarPump;
boolean newData2 = false;


//To process data received on RX_3
const byte numChars3 = 64;
char receivedChars3[numChars3];
char tempChars3[numChars3]; 
char markID3[numChars3] = {0};
int ampBattArray;
int voltsBattArray;
int voltsSolarArray;
boolean newData3 = false;



void setup(){

   Serial.begin(115200);
   Serial1.begin(115200);
   Serial2.begin(115200);
   Serial3.begin(115200);

}


void dataSeparator1() {

   if (newData == true) {
   strcpy(tempChars, receivedChars);
   dataParser1();
   newData = false;
   }
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial1.available() > 0 && newData == false) {
      
        rc = Serial1.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 dataSeparator2() { //For data comming to Serial 2

   if (newData2 == true) {
   strcpy(tempChars2, receivedChars2);
   dataParser2();
   newData2 = false;
   }
    static boolean recvInProgress2 = false;
    static byte ndx2 = 0;
    char startMarker2 = '<';
    char endMarker2 = '>';
    char rc2;

    while (Serial2.available() > 0 && newData2 == false) {
        rc2 = Serial2.read();
        if (recvInProgress2 == true) {
            if (rc2 != endMarker2) {
                receivedChars2[ndx2] = rc2;
                ndx2++;
                if (ndx2 >= numChars2) {
                    ndx2 = numChars2 - 1;
                }
            }else {
                receivedChars2[ndx2] = '\0'; // terminate the string
                recvInProgress2 = false;
                ndx2 = 0;
                newData2 = true;
           }
        }else if (rc2 == startMarker2) {
        recvInProgress2 = true;
        }
    }
}



void dataSeparator3() { //For data comming to Serial 3

   if (newData3 == true) {
   strcpy(tempChars3, receivedChars3);
   dataParser3();
   newData3 = false;
   }
    
    static boolean recvInProgress3 = false;
    static byte ndx3 = 0;
    char startMarker3 = '<';
    char endMarker3 = '>';
    char rc3;

    while (Serial3.available() > 0 && newData3 == false) {
      
        rc3 = Serial3.read();
        if (recvInProgress3 == true) {
            if (rc3 != endMarker3) {
                receivedChars3[ndx3] = rc3;
                ndx3++;
                if (ndx3 >= numChars3) {
                    ndx3 = numChars3 - 1;
                }
        }else {
                receivedChars3[ndx3] = '\0'; // terminate the string
                recvInProgress3 = false;
                ndx3 = 0;
                newData3 = true;
           }
        }else if (rc3 == startMarker3) {
        recvInProgress3 = true;
        }
    }
}



void dataParser1() { 

    char * strtokIndx;
    
    strtokIndx = strtok(tempChars,",");
    strcpy(markID1, strtokIndx); 
    
    strtokIndx = strtok(NULL, ","); 
    flowNoir = atoi(strtokIndx); 
    
    strtokIndx = strtok(NULL, ","); 
    totalNoir = atoi(strtokIndx);
    
    strtokIndx = strtok(NULL, ",");
    flowOrange = atoi(strtokIndx);
    
    strtokIndx = strtok(NULL, ","); 
    totalOrange = atoi(strtokIndx);
}



void dataParser2() { 

    char * strtokIndx2;
    
    strtokIndx2 = strtok(tempChars2,","); 
    strcpy(markID2, strtokIndx2); 
    
    strtokIndx2 = strtok(NULL, ","); 
    flowGrise = atoi(strtokIndx2); 
    
    strtokIndx2 = strtok(NULL, ","); 
    totalGrise = atoi(strtokIndx2);
    
    strtokIndx2 = strtok(NULL, ","); 
    voltsSolarPump = atoi(strtokIndx2); 
}


void dataParser3() {

    char * strtokIndx3;
    
    strtokIndx3 = strtok(tempChars3,",");    
    strcpy(markID3, strtokIndx3); 
       
    strtokIndx3 = strtok(NULL, ","); 
    ampBattArray= atoi(strtokIndx3);  
       
    strtokIndx3 = strtok(NULL, ","); 
    voltsBattArray= atoi(strtokIndx3);  
      
    strtokIndx3 = strtok(NULL, ","); 
    voltsSolarArray = atoi(strtokIndx3); 
}



void SerialPrint(){

  Serial.print("Flow_Noir  ");
  Serial.println(flowNoir);

  Serial.print("Total_Noir  ");
  Serial.println(totalNoir);

  Serial.print("Flow_Orange  ");
  Serial.println(flowOrange);

  Serial.print("Total Orange  ");
  Serial.println(totalOrange);



  Serial.print("Flow_Grises  ");
  Serial.println(flowGrise);

  Serial.print("Total Grise  ");
  Serial.println(totalGrise);
  
  Serial.print("VoltsSolarPump: ");
  Serial.println(voltsSolarPump);


  
  Serial.print("VoltsBattArray: ");
  Serial.println(voltsBattArray);
  
  Serial.print("AmpBattArray: ");
  Serial.println(ampBattArray);

  Serial.print("VoltsSolarArray: ");
  Serial.println(voltsSolarArray);

  
}



void loop(){

   dataSeparator1();
   dataSeparator2();
   dataSeparator3();
   SerialPrint();

}

Am I missing something ? That code worked on other projects with a nano sending
sensors value to a 8266 via the serial port so the 8266 can send the result to Wi-Fi.

I use it more than once without any problems but it was always between nano and 8266
with only one serial port.

In this project with the Mega, I disconnect the RX of the two other nano and the
problem is the same.

Maybe there is something I don’t know about Mega and serial ports.

Add to this that I’m a newbie in programming, you can see why I need help.

Thanks for any help.

i Suspect that the problem is that your while(Serial.available()) loop ends before all characters are read. to transfer a byte at 115200 still takes about 100 microseconds, the Serial buffer may be empty by the time the Arduino reads the 3rd or 4th Character. try

while (Serial3.available() > 0 && newData3 == false) {
     delayMicroseconds(100);
     etc...

Deva_Rishi: i Suspect that the problem is that your while(Serial.available()) loop ends before all characters are read.

That's not the problem. He has abstracted the code from the 3rd example in my Serial Input Basics. Though why he mucked about with it I don't know. Neither do I know if he mucked about with it in a fatal manner.

@hddforensic, I suspect the problem is in the code you didn't Post. Have you tried the program that is in your Original Post and what happens when you run it?

...R

Hi Robin,

Like I said before I'm not a real programmer but I'm still learning so I apologize If I mucked your code. BTW I'm french so I had to google the word "Mucke" to understand what you mean by that :-).

I found part of the problem but it's probably not the real reason. One of the fonction in my code that I didn't put in the post, is for reading AC Current with the Emon library. It work in my orginal code because in that one I'm reading data from only two nano and Ac Currrent from two sensors.

But in the code were I have the data problem, I'm reading six current sensors and it is slowing the Mega.

When I remove the Ac Current fonction the Mega is much much faster and I don`t miss data or If I do, it's very rare so it doesn't matter anymore.

If I could fix the data parser section, the speed of the Mega probably won't matter but I don't know how.

Since a nano is only 5$ I made a test.

I add a 4th nano for the 6 Current sensors and TX the data to the Mega but since the Mega only have 3 serial ports, I used software serial to create a 4th one.

I also reduce the speed at 9600 for all of the nano.

The results was better but little data were lost again so I add "switch case" and made the code to parse only one port after the other. After a few minutes I cut and past the result from the serial windows to an Excel spreadsheet and found only 36 errors on 19,224 prints. This is much much better but.. it's just a workaround and not a real solution.

I can live with that but If you can show me in parsing section of the code what I can fix, it would be nice.

Tanks

hddforensic: BTW I'm french so I had to google the word "Mucke" to understand what you mean by that :-).

"Muck" is that fascinating mixture of water and earth mixed with manure that you find in farmyards after heavy rain. :)

The Mega has to be able to take the data from the 3 serial input buffers fast enough so that none of it gets lost.

If you can arrange for the Nanos to send a max of 64 bytes at a time and wait until they get a request before sending the next message then the Mega can operate in a more relaxed fashion. The serial input buffer can hold up to 64 bytes and if no more arrives it can be left sitting there for a considerable time.

And, if you are sending short messages and if the Mega knows the size of the incoming message it can use if (Serial.available() >= messageLength) { so as not to waste time reading bytes until they have all arrived

Be aware, however, the the Serial system relies on interrupts to move data from the USART to the Serial input buffer and if something else in your code is preventing interrupts from happening then the data might get lost at the USART. The USART only has storage for one or two bytes (can't remember which).

...R

How often do your Nanos send data to the Mega; as often as possible or e.g. every 500 ms?

Robin asked if the code that you posted shows the problem? Please answer that. I suspect that the answer is yes.

Your Serial.print print at least 100 characters (without the actual data). After 64 chararters, it starts blocking and during the block you will not be able to receive data. You will loose it at a lower level already (not in the parsers). Check if increasing the baudrate on Serial (and Serial only) to 1000000 or 2000000 will reduce the problem.

You have a lot of other stuff going on that you did not post; that might also be blocking and it will have the same effect.

If I could fix the data parser section, the speed of the Mega probably won’t matter but I don’t know how.

The problem is not in the parsers :wink: If I’m right, you will need to slow down the amount of data from the Nanos (e.g. send data every second) so the Mega can also handle other things.