inconsistent data length when using 2 serial ports on Mega 2560

Hi there!

I am trying to get data from two IMU using serial ports on Mega, I can get the data using the code below, but I am getting two sets of data from each IMU at a time, and sometimes the length of the data are off. (please see snapshot of the Serial Monitor in attach)

Does it have to do with synchronization? or something else? Please help me out if you could point out the problem, and guide me to the right direction to solve the problem. Thank you very much in advance. Have a great day!

char buffer[15];

void setup()
{
  Serial.begin(57600);
  Serial1.begin(57600);
  Serial2.begin(57600);
   }

void loop() {
 
  Serial.println("data from IMU one:");
  //while there is data coming in, read it 
  //and send to the hardware serial port:
  while (Serial1.available()>0){
    char buffer=Serial1.read();
    Serial.write(buffer);
    
  }
  
  Serial.println();
  
  Serial.println("data from IMU two:");
  while (Serial2.available()>0){
    char buffer=Serial2.read();
    Serial.write(buffer);
  }
  
  Serial.println();
}

For a start you will be flooding Serial with "data from IMU one:" and "data from IMU two:" (even if there is no data) so the real data probably doesn't get much chance. Try getting rid of those messages.

Hi Nick

Thank you so much for your speedy reply, it does solve my problem (i get consistent data length and only one set of data at a time). However, after 3 sets of data, a negative sign pops up in a blank line, which looks something like below. the negative sign belongs to the following data i believe. Could you kindly let me know what's causing it? and could you also tell me what might be causing the problem? as I would like to learn more how and why the serial monitor behave this way. Thank you again Nick!

-14.34,31.74,215.04,60.17,-3.83,58.67,-32.00,21.00,28.00

-33.79,24.58,221.18,60.17,-2.33,49.50,-66.00,2.00,12.00

-15.36,31.74,214.02,60.33,-4.33,58.33,-31.00,22.00,26.00

-

33.79,23.55,220.16,59.67,-2.33,49.33,-65.00,2.00,12.00

-14.34,31.74,215.04,61.00,-3.50,58.00,-30.00,22.00,27.00

-34.82,23.55,220.16,59.67,-2.17,49.00,-65.00,1.00,11.00

-15.36,31.74,215.04,60.50,-3.67,57.67,-32.00,21.00,27.00

-33.79,22.53,220.16,59.83,-1.83,49.67,-65.00,2.00,12.00

-14.34,31.74,215.04,60.00,-3.50,58.50,-31.00,21.00,27.00

-

34.82,23.55,219.14,59.67,-2.17,49.33,-66.00,1.00,12.00

Hi Nick,

To follow up, it seems that sometimes two dash/negative sign occurs. Could you kindly tell me what might causes this?

-36.86,24.58,219.14,59.17,-1.83,50.33,-67.00,1.00,11.00

-16.38,33.79,215.04,59.67,-4.67,59.00,-32.00,21.00,28.00

-37.89,24.58,219.14,59.00,-2.17,50.67,-67.00,2.00,11.00

-15.36,33.79,215.04,59.83,-4.00,59.33,-32.00,21.00,28.00

-

36.86,24.58,220.16,58.17,-2.17,50.67,-65.00,1.00,12.00

16.38,33.79,216.06,60.17,-4.17,58.83,-31.00,21.00,27.00

-36.86,24.58,219.14,59.00,-2.17,50.50,-65.00,2.00,11.00

16.38,32.77,214.02,59.83,-3.83,59.00,-32.00,20.00,27.00

-36.86,24.58,219.14,58.83,-1.67,50.83,-66.00,1.00,12.00

15.36,33.79,216.06,60.17,-4.33,58.83,-31.00,20.00,26.00

Can you post your new code? I notice that you have perhaps not removed the Serial.println() which execute all the time.

Also you (rather confusingly) have multiple variables called buffer:

char buffer[15];

...
    char buffer=Serial1.read();
-
-
36.86,24.58,220.16,58.17,-2.17,50.67,-65.00,1.00,12.00

You are interspersing reads from both Serial1 and Serial2. You know that bytes arrive one at a time? Thus, it is possible that your figures above are really:

-36.86,-24.58,220.16,58.17,-2.17,50.67,-65.00,1.00,12.00

Or conceivably a mixture. You just can't rely on a "batch" from Serial1, followed by a batch from Serial2. The way you are doing it is going to give meaningless results. Imagine if the "36" came from Serial1 and the "86" came from Serial2. What use is the combined line?

If this was my project I would read the data separately from each device using one of the examples in serial input basics. You can't rely on any "natural" speed of arrival of serial data. Unless you organize things carefully you might get a b c a b c or a b b c c a c b

I would have three "copies" of the receive function - one for each channel.

When I have the data from the three devices I would then send it onwards in a suitable format so that the different parts can be identified.

...R

Hi Nick,

Once again, thank you so much for your reply, may I confirm with you my understanding of UART protocol?

  1. If I am communicating via serial port 1(pin 18,19) and serial port 2(pin 16,17), because it's asynchronous, the data are NOT transmitting in order respectively. meaning i might get one byte from port 1 and another byte from port 2? I have been trying to confirm whether this is right or not but so far no luck.

  2. I thought about Most significant bit and least significant bit to indicate the start and end of the data, is this the right way to go about this problem?

  3. Below is the full code, I haven't modified the code much because I was trying to figure out how to get the data in the right format (as i am going to log the data on excel for further calculation, please let me know if you know of a better alternative to log data!) However, now i know the data is out of order and useless, could you kindly give me some hints on how I could modify the code/hardware so that i get data from serial port 1 then serial port 2 in order?

All in all, the main goal for the project is to collect data from three Razor IMU (https://www.sparkfun.com/products/10736) via MEGA 2560, then utilize those data for further calculation. I also purchased three LSM9DS0 (https://www.sparkfun.com/products/12636), which will require I2C protocol since they do not have the ATmega board installed. My current method is to use Razor IMU to get the data, upload it to excel and then do some further calculation on Matlab or Mathematica. Could you kindly tell me if there is a better way of doing it?

Thank you very much for your help Nick, I really appreciate your time and effort.

byte buffer1;
byte buffer2;

void setup()
{
  Serial.begin(57600);
  Serial1.begin(57600);
  Serial2.begin(57600);
   }

void loop() {

  //Serial.println("data from IMU one:");
  //while there is data coming in, read it 
  //and send to the hardware serial port:
  while (Serial1.available()>0){
    buffer1=Serial1.read();
    Serial.write(buffer1); 
  }
  
  //Serial.println();
  
  
  //Serial.println("data from IMU two:");
  while (Serial2.available()>0){
    buffer2=Serial2.read();
    Serial.write(buffer2);
  }
  
  Serial.println();
}

michaelcheng1991: Hi Nick,

Once again, thank you so much for your reply, may I confirm with you my understanding of UART protocol?

  1. If I am communicating via serial port 1(pin 18,19) and serial port 2(pin 16,17), because it's asynchronous, the data are NOT transmitting in order respectively. meaning i might get one byte from port 1 and another byte from port 2? I have been trying to confirm whether this is right or not but so far no luck.

  2. I thought about Most significant bit and least significant bit to indicate the start and end of the data, is this the right way to go about this problem?

  3. Below is the full code, I haven't modified the code much because I was trying to figure out how to get the data in the right format (as i am going to log the data on excel for further calculation, please let me know if you know of a better alternative to log data!) However, now i know the data is out of order and useless, could you kindly give me some hints on how I could modify the code/hardware so that i get data from serial port 1 then serial port 2 in order?

All in all, the main goal for the project is to collect data from three Razor IMU (https://www.sparkfun.com/products/10736) via MEGA 2560, then utilize those data for further calculation. I also purchased three LSM9DS0 (https://www.sparkfun.com/products/12636), which will require I2C protocol since they do not have the ATmega board installed. My current method is to use Razor IMU to get the data, upload it to excel and then do some further calculation on Matlab or Mathematica. Could you kindly tell me if there is a better way of doing it?

Thank you very much for your help Nick, I really appreciate your time and effort.

what Nick and others are saying, is that after you read the data from the individual serial ports you combine the results into one data stream. The loop can process faster than the Serial ports can send/receive data. so if both port have data pending, your code will empty the receive buffer faster than they can be filled, Until you fill the output buffer, then the input buffer can start filling.

Since the Serial buffers are 64 bytes, and you are receiving 2(Serial1,Serial2) stream at 56k and only sending 1(Serial) stream at 56k you can,will overflow (Serial) if the data stream from (Serial1+Serial2) is greater than 56k. If this is true you will loose the data from Serial1 or Serial2 the Calls to Serial.write() will hang when its transmit buffer fills. so The data receive buffers for Serial1, Serial2 will overflow.

I changed your code to identify the source of each character sent through Serial

byte buffer1;
byte buffer2;

void setup()
{
  Serial.begin(57600);
  Serial1.begin(57600);
  Serial2.begin(57600);
   }

static uint8_t lastSerial=0;  // source of last character send out Serial
void loop() {

  //Serial.println("data from IMU one:");
  //while there is data coming in, read it 
  //and send to the hardware serial port:
  if(Serial1.available()){
    if (lastSerial!=1) Serial.print("\none:");                             // mark data as coming from Serial1
    lastSerial = 1;
    }
  while (Serial1.available()>0){
    buffer1=Serial1.read();
    Serial.write(buffer1); 
  }
  
  //Serial.println();
  
  
  //Serial.println("data from IMU two:");
  if(Serial2.available()){
    if (lastSerial!=2) Serial.print("\ntwo:");                             // mark data as coming from Serial2
    lastSerial = 2;
    }
  while (Serial2.available()>0){
    buffer2=Serial2.read();
    Serial.write(buffer2);
  }
  
//  Serial.println();
}

[/quote]

Chuck.

A buffer is a place to collect more than one byte of data. Naming a variable buffersometing does not make it a buffer.

meaning i might get one byte from port 1 and another byte from port 2?

That's right. One byte at a time. You might get 3 bytes from port 1 and 2 from port 2. Mixing them up afterwards is meaningless. One approach would be to collect all data from port 1 into one variable (buffer), and all from port 2 into a different buffer. In each case, you would wait for a terminating character such as a newline. Then you could echo something like:

Buffer 1: 36.86,24.58,220.16,58.17

[quote author=Nick Gammon link=msg=2326275 date=1437597571] That's right. One byte at a time. You might get 3 bytes from port 1 and 2 from port 2. Mixing them up afterwards is meaningless. One approach would be to collect all data from port 1 into one variable (buffer), and all from port 2 into a different buffer. [/quote]

That is stating more clearly what I was trying to say in Reply #6

...R

Hi Chuck!

Thank you very much for your reply and modifying the code. However, after some research, I still can't figure how the modified code produce result as follow. (random negative sign and two sets or three sets of data at once from one serial port)

one:-35.84,-2.05,222.21,0.17,105.00,162.17,-68.00,4.00,11.00

-34.82,-2.05,221.18,0.67,104.83,162.00,-68.00,4.00,12.00

two:-24.58,7.17,216.06,11.00,88.00,186.17,-33.00,20.00,26.00 -25.60,8.19,217.09,10.00,88.17,186.50,-33.00,21.00,28.00

one:34.82,-1.02,220.16,0.67,104.67,162.17,-67.00,3.00,12.00 -34.82,-1.02,220.16,0.33,104.83,161.67,-66.00,3.00,11.00 -33.79,0.00,220.16,0.67,104.00,162.00,-67.00,4.00,11.00

two:-24.58,8.19,215.04,10.67,88.33,186.83,-32.00,21.00,28.00 -23.5.17,88.00,186.00,-33.00,2000,27.00 -24.58,8.19,216.06,10.33,88.33,186.50,-33.00,21.00,28.00

Also, I've been trying to format the output such that the data from the second serial port follows the first serial port such as

one:34.82,-1.02,220.16,0.67,104.67,162.17,-67.00,3.00,12.00two:-24.58,8.19,215.04,10.67,88.33,186.83,-32.00,21.00,28.00

I tried Serial.print but all the decimal places are omitted, could you please give me some hint on how to resolve this problem please?

Since the Serial buffers are 64 bytes, and you are receiving 2(Serial1,Serial2) stream at 56k and only sending 1(Serial) stream at 56k you can,will overflow (Serial) if the data stream from (Serial1+Serial2) is greater than 56k.

From how i understand it, you mean Serial communication is very slow for the MEGA, and since the BAUD rate is set to be 56400, the buffer will be overflowed with data coming from the sensor? Could you tell me what you mean by "only sending 1(Serial) stream at 56k you can"? are you saying the MEGA communicate with the computer via the TX0 and RX0 ?

chucktodd: static uint8_t lastSerial=0;  // source of last character send out Serial

Chuck.

I am thinking the static variable lastSerial is local correct? meaning after each loop, lastSerial changes to 1 or 2 according to which serial port acts last? Also, I will probably not be able to think of your way to go around my problem due to my lack of knowledge in C++. Could you recommend me a good way to learn how to code in Arduino more efficiently?

Thank you Chuck once again for your help and time, I really appreciate it!

Hi Robin!

Thank you very much for your reply, sorry it took me awhile to read your other post. However, I couldn't quite relate your post on Serial input with my project (forgive me as I am not familiar with C++). From my understanding your post has to do with inserting input on the serial monitor while I am trying to use MEGA to collect data from multiple IMUs. If you could just slightly elaborate on how to use three "copies" of the receive function for the channel individually, it will be really helpful for me to better relating your help with my project.

All i can think of is that maybe by copies of receive function you are referring to Chucks' Modified code in reply #8?

I really appreciate your help and time, I look forward to hearing from you.

Robin2: If this was my project I would read the data separately from each device using one of the examples in serial input basics. You can't rely on any "natural" speed of arrival of serial data. Unless you organize things carefully you might get a b c a b c or a b b c c a c b

I would have three "copies" of the receive function - one for each channel.

When I have the data from the three devices I would then send it onwards in a suitable format so that the different parts can be identified.

...R