Accessing multiple sensor device data by serial communication using Arduino Mega 2560 two hardware Serial ports

I am trying to read serial data from a sensor PMS5003, which is used for environmental particulate matter parameters measurement; and a Neo-6M GPS module for GPS location data using two hardware serial ports of Arduino Mega micro-controller Board.

I have tried to fetch the data from these two devices individually and it successfully working. But the problem is arising when I am trying to read data from both serial devices at the same time, it is only printing the PMS5003 sensor data correctly, but it is not printing the NEO6M GPS data. I have checked that if(gps.encode(Serial1.read())) always false when both devices try to work.

When I am commenting out " Serial2.begin(9600);", it is printing GPS values correctly. I want to read data from both devices at the same time. Please check the code, if I have any mistakes, and suggest to me the right direction for this. I think both serial devices are not working simultaneously.
Thank you in advance.

Following is the code:

#include <TinyGPS.h>
float glat, glon;
TinyGPS gps; // create gps object

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(9600);
  Serial2.begin(9600);

}

struct pms5003data {
  uint16_t framelen;
  uint16_t pm10_standard, pm25_standard, pm100_standard;
  uint16_t pm10_env, pm25_env, pm100_env;
  uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
  uint16_t unused;
  uint16_t checksum;
};
 
struct pms5003data data;

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial1.available()>0) { // check for GPS data
     //Serial.println("GPS Data Available!!!");
     if(gps.encode(Serial1.read()))
     { 
       Serial.println("GPS Data Found!!!");
       gps.f_get_position(&glat,&glon); // get latitude and longitude
       Serial.println("Position: ");
    
       //Latitude
       Serial.print("Latitude: ");
       Serial.println(glat,6);
    
       //Longitude
       Serial.print("Longitude: ");
       Serial.println(glon,6);
      }
   }
   if (Serial2.available()>0) { // check for PMS data
      if(readPMSdata(&Serial2))
      { 
         Serial.println("PM Data Found!!!");

         Serial.println("Particle Matter: ");
         Serial.print("PM 1.0: "); 
         Serial.println(data.pm10_env);
         Serial.print("PM 2.5: "); 
         Serial.println(data.pm25_env);
         Serial.print("PM 10: "); 
         Serial.println(data.pm100_env);
       }
    }

  Serial.println();
  Serial.println();
  delay(100);
  
}

boolean readPMSdata(Stream *s) {
  if (! s->available()) {
    return false;
  }
  
  // Read a byte at a time until we get to the special '0x42' start-byte
  if (s->peek() != 0x42) {
    s->read();
    return false;
  }
 
  // Now read all 32 bytes
  if (s->available() < 32) {
    return false;
  }
    
  uint8_t buffer[32];    
  uint16_t sum = 0;
  s->readBytes(buffer, 32);
 
  // get checksum ready
  for (uint8_t i=0; i<30; i++) {
    sum += buffer[i];
  }
  
  // The data comes in endian'd, this solves it so it works on all platforms
  uint16_t buffer_u16[15];
  for (uint8_t i=0; i<15; i++) {
    buffer_u16[i] = buffer[2 + i*2 + 1];
    buffer_u16[i] += (buffer[2 + i*2] << 8);
  }
 
  // put it into a nice struct :)
  memcpy((void *)&data, (void *)buffer_u16, 30);
 
  if (sum != data.checksum) {
    Serial.println("Checksum failure");
    return false;
  }
  // success!
  return true;
}

pms_gps_v3.ino (2.5 KB)

Generally, the serial connections for multiple hardware serial is:

The Arduino Mega has three additional serial ports: Serial1 on pins 19 (RX) and 18 (TX), Serial2 on pins 17 (RX) and 16 (TX), Serial3 on pins 15 (RX) and 14 (TX). To use these pins to communicate with your personal computer, you will need an additional USB-to-serial adaptor, as they are not connected to the Mega's USB-to-serial adaptor. To use them to communicate with an external TTL serial device, connect the TX pin to your device's RX pin, the RX to your device's TX pin, and the ground of your Mega to your device's ground.

Afterthought:
Try reading the GPS last.

Wouldn't it make more sense to do that before going to the effort of repackaging the sensor data?

I wonder if readPMSdata is taking too long. If it does, then data will be dropped from the GPS when the buffer fills up and then you will see a failure to encode correctly.

It has been many, many years but I seem to remember that Ladyada originally used software serial in her GPS library and established a dual-buffer scheme to get around stalls caused by GPS.

No more struggling with the Arduino Uno in your previous topic. That's good :smiley:

Using the 64 bytes buffer inside the Serial library is okay. You wait until all 32 bytes are in that buffer. If you add more to your sketch, then I would like to read every single byte that is available. In that case, you need an extra buffer in your sketch to fill up to 32 bytes. Your sketch would become easier, because you already have such a buffer.

Can you fix a few things ? I want to improve the sketch, and then you can add more debug messages.

I wrote before: "When reading serial data, the sketch should never wait. It should read the data as soon as data arrives"
So please remove this from the loop():

  Serial.println();
  Serial.println();
  delay(100);

This is not okay:

if (! s->available())

The Serial.available() return a number. The exclamation operator is a boolean operator.
Note to others: It is not okay, but that is my personal opinion. When a sketch does not work, then at least I want to get rid of half-baked language tricks.

The code to check the checksum is not straightforward as TheMemberFormerlyKnownAsAWOL already wrote. I can not see a bug there, but it is hard to read code.

Thanks for your response to my post.

Can you please suggest what to do into this code into these two cases:

boolean readPMSdata(Stream *s) {
  if (! s->available()) {
    return false;
  }
if (sum != data.checksum) {
    Serial.println("Checksum failure");
    return false;
  }

Please suggest me.

I'd move 2. to immediately after the checksum calculation, and lose the print.

Thanks for your response.

I wish to comment out the lines of case 2. Is it ok?

Uhm, this might seem silly, but it is really that easy:
Say it in words: If there is no data, then...
Put on your Arduino hat and say it again: If the a amount of available data is zero, then...
Say it in code: if(s->available() == 0)

It's fine, if you don't care whether or not the data received is valid

Hello, I have a similar problem with the "Checksum failure", do you know anything about this?
Thanks.

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