Using Multiple Serial on Arduino Mega2560 (read one serial then print to another

Hello, i am currently developing a program to read multiple sensor with different interface and the wrap it into a string and then print it to be used by other microcontroller system and log it to SD Card. I planned to use all 4 of the UART available in Arduino Mega. Uart Mapping is like:
Serial for communicating with PC,9600 bps
Serial1 for sending all sensor output to other system,9600bps
Serial2 for receiving GPS data,4800bps
Serial3 for receiving IMU 9DOF Razor, 4800bps

other sensor that i used is pressure sensor via I2C and Analog pressure sensor.

My arduino program is 80% now, and i still have difficulties on reading the IMU Data because of this:

if i use this program

void setup() {
  Serial.begin(9600);
  Serial3.begin(4800);
  
}

String IMURead ="";

void loop(){
  if (Serial3.available() > 0 ) {
    // read incoming character from IMU
    int inChar = Serial3.read();
    if(isDigit(inChar)); // convert byte ke char and add to string
    {
      IMURead +=(char)inChar;
    }
    if (inChar == '\n') // if you got newline
    { 
      Serial.println (IMURead);
      delay(50);
      IMURead = "";
    }
  }
}

i could read the data from the IMU and it works fine, but the problem is, i can't put the IMU Read on the main loop, because i have my own section to print and store the data to SD Card, so i plan to made the IMU reading as separated function then call it on the main loop.

I have tried to modify the code above to be like this :

void setup() {
  Serial.begin(9600);
  Serial3.begin(4800);
  
}

int inChar;
String IMURead ="";

void loop(){ 
ReadIMU()
Serial.println (IMURead); 
delay(50);
}


String ReadIMU()  {
if (Serial3.available() > 0 ) {
     inChar = Serial3.read();
    do 
    {
    // read incoming character from IMU
   inChar = Serial3.read();
    if(isDigit(inChar)); // convert byte ke char and add to string
    {
      IMURead +=(char)inChar;
    } 
    }
    while (inChar != '\n'); 
  }
 
return IMURead;
IMURead="";
}

could somebody help my in this issue?

the bottom line, when the main loop calls the ReadIMU function, it will read serial3 data and stop when there is '\n' or ending character ';' being read from the serial3. Then it will return the value of IMURead to the main loop, so it could be printed and stored in SD card

Thanks in advance for the help

return IMURead;
IMURead="";
}

The return statement ends the function. Absolutely nothing after the return statement matters.

    while (inChar != '\n');

If the function reads a character, and it is not a carriage return, do nothing forever. Is that REALLY what you want?

Why does this function return a global variable?

int inChar;
String IMURead = "";

void loop(){ 

if (ReadIMU())   // Returns true if a full line has been read.
    {
    Serial.println (IMURead);
    IMURead = "";
    }
    
delay(50);
}


boolean ReadIMU()  
    {
    if (Serial3.available()) 
        {
        int inChar = Serial3.read();

        if(isDigit(inChar));
             IMURead +=(char)inChar;

        if (inChar == '\n')
            return true;
        }
    return false;
}

PaulS:

    while (inChar != '\n');

If the function reads a character, and it is not a carriage return, do nothing forever. Is that REALLY what you want?

That's the end of a do-while loop, not a stand-alone while loop.

That's the end of a do-while loop, not a stand-alone while loop.

Then it belongs on the line with the } that marks the end of the do/while block, and the stuff in between needs to be properly indented.

The do/while statement is one of the hardest to follow, and rarely should be used, primarily because it always executes at least once. If the goal is to read an store everything until the carriage return ends, then special handling is needed inside the do/while block to avoid problems where the 1st character read is a carriage return.

That special handling then complete eliminates any perceived advantages to having used a do/while statement.

The do/while statement is one of the hardest to follow, and rarely should be used, primarily because it always executes at least once. If the goal is to read an store everything until the carriage return ends, then special handling is needed inside the do/while block to avoid problems where the 1st character read is a carriage return.

yes, i want to store everything until i got '\n' then returned it to main void loop() because i want to print it and store it to SD Card along with other sensor parameter.

Could you suggest what kind of special handling is needed to achieve that? my data start with header # and ended with ; character
thanks

Could you suggest what kind of special handling is needed to achieve that? my data start with header # and ended with ; character

Then, why are you looking for a carriage return as the end of packet marker?

If you are sending #, some data, and ;, change two characters in this code:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

i try to modify the code to this following based on my requirement:

#define SOP '#'
#define EOP ';'

bool started = false;
bool ended = false;

char inData[21];
byte index;

void setup()
{
   Serial.begin(19200);
   Serial3.begin(19200);
   // Other stuff...
}

void loop(){
  bacaIMU();
  delay(50);
   Serial.println(inData);
    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
    }
    
 void bacaIMU(){
  // Read all serial data available, as fast as possible
  while(Serial3.available() > 0)
  {
    char inChar = Serial3.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 21)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet
   return;
  }
}

i also try replacing the void bacaIMU() with char* bacaIMU but both output the same as:

009796,
004664,-09608
009843,004699,-09594
009889,004728,-09584
009933,004754,-09573
009973,004779,-09568
010016,004800,-09558
010054,004823,-09556
010135,004861,-09540

10,004882,-09528
010313,004920,-09520

379,004937,-09515
010484,004955,-09495

547,004969,-09488
,004985,-09486
9,004995,-09481
41,005003,-09479
010964,005005,-09477
0
011005,005004,-09482
011029,005007,-09480

11047,005008,-09485
011065,005008,-09488
01

some of them are incomplete, do you have any suggestion?
thanks

do you have any suggestion?

No, but I do have a couple of questions.

I planned to use all 4 of the UART available in Arduino Mega. Uart Mapping is like:
Serial for communicating with PC,9600 bps
Serial1 for sending all sensor output to other system,9600bps
Serial2 for receiving GPS data,4800bps
Serial3 for receiving IMU 9DOF Razor, 4800bps

So, why is this in the code:

   Serial3.begin(19200);

Why are you plodding along with the output?

   Serial.begin(19200);

Get the output speed up, so the input buffer doesn't overflow while you are diddling around writing the output.

PaulS:

do you have any suggestion?

No, but I do have a couple of questions.

I planned to use all 4 of the UART available in Arduino Mega. Uart Mapping is like:
Serial for communicating with PC,9600 bps
Serial1 for sending all sensor output to other system,9600bps
Serial2 for receiving GPS data,4800bps
Serial3 for receiving IMU 9DOF Razor, 4800bps

So, why is this in the code:

   Serial3.begin(19200);

Why are you plodding along with the output?

   Serial.begin(19200);

Get the output speed up, so the input buffer doesn't overflow while you are diddling around writing the output.

i changed the sensor baud rate, at first i want to made the system fixed at 9600-4800-4800, but now i try some option, including faster baud rate to get the sentence complete

thanks anyway, i'll try some combination on baud rate and delay