Multiple Serial Connections

Hi, I'm currently building a air quality monitor with the following sensors: MH-Z19, PMS5003 and a HIH6130 (yet to insert code) with an Uno. I came to learn that only one serial software port can listen at any given time. I am learning about the Softwareserial.listen but am unsure how I can use it because there I have two libraries taken from online and Softwareserial.listen is not defined in the library.

Or should I use a Arduino Mega as I also came to read about it, having 3 other serial ports as compared to the Uno. How will it be different then?

Appreciate any help in guiding my understanding! Thanks!

#include <SGBotic_MHZ19.h>
#include <SGBotic_PMS5003.h>
#include <SoftwareSerial.h>

//sets up the (RX, TX) digital pins 
SoftwareSerial pmsSerial(2, 3); //device's TX attached to digital pin 2 
                                //device's RX attached to digital pin 3 
SGBotic_PMS5003 PMS5003 = SGBotic_PMS5003(&pmsSerial); 

SoftwareSerial co2Serial(10,11); //device's TX attached to digital pin 10
                                 //device's RX attached to digital pin 11  
SGBotic_MHZ19 co2 = SGBotic_MHZ19(&co2Serial); 

uint16_t PMSdata[data_size]; 

void setup() {
  Serial.begin(9600); 
  co2.begin(9600); 
  PMS5003.begin(9600); 
  Serial.println("Sensors will begin reading in 30s");
  delay(30000); //delay 30s
}

void loop() {  
  int ppm = co2.readPPM(); 
  
  if (PMS5003.readPMS(PMSdata))
  {
    Serial.println();
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (standard)");
    Serial.print("PM 1.0: "); Serial.print(PMSdata[pm10_standard]);
    Serial.print("\t\tPM 2.5: "); Serial.print(PMSdata[pm25_standard]);
    Serial.print("\t\tPM 10: "); Serial.println(PMSdata[pm100_standard]);
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (environmental)");
    Serial.print("PM 1.0: "); Serial.print(PMSdata[pm10_env]);
    Serial.print("\t\tPM 2.5: "); Serial.print(PMSdata[pm25_env]);
    Serial.print("\t\tPM 10: "); Serial.println(PMSdata[pm100_env]);
    Serial.println("---------------------------------------");
    Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(PMSdata[particles_03um]);
    Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(PMSdata[particles_05um]);
    Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(PMSdata[particles_10um]);
    Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(PMSdata[particles_25um]);
    Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(PMSdata[particles_50um]);
    Serial.print("Particles > 50 um / 0.1L air:"); Serial.println(PMSdata[particles_100um]);
    Serial.println("---------------------------------------");
  }
}

if you can't control when the sensors will send information, you can't stay in listen mode only on one, they all need to be active at the same time.

it will definitely be more robust with real hardware serial ports if you can move to a MEGA.

Looking at the SGBotic PMS5003 or the MHZ19 libraries, they accept a hardware Serial port to listen to in their constructor so on a MEGA the code could be just to reference which Serial port is connected to which sensor, for example

SGBotic_PMS5003 PMS5003 = SGBotic_PMS5003(&Serial1); 
SGBotic_MHZ19 co2 = SGBotic_MHZ19(&Serial2);

and you can get rid of the SoftwareSerial stuff.

Ah, thank you very much. I'll look to getting a Arduino Mega then. Since I have no use for the SoftwareSerial in a Mega, then the first few lines of code should be something like this right?

#include <SGBotic_MHZ19.h>
#include <SGBotic_PMS5003.h>

Serial1(RX, TX); //pins on the Mega
SGBotic_PMS5003 PMS5003 = SGBotic_PMS5003(&Serial1);


Serial2(RX, TX); //pins on the Mega
SGBotic_PMS5003 PMS5003 = SGBotic_PMS5003(&Serial2);

Edit: Wait, I realized there is still a need for the SoftwareSerial library to communicate to the Serial Monitor via the hardware serial on the Mega.

For further understanding, in the case of Uno, is this link: https://www.arduino.cc/en/Tutorial/TwoPortReceive a good source of how I can call each of the sensors individually to start sending info?

Again, thank you!

surreal123:
Edit: Wait, I realized there is still a need for the SoftwareSerial library to communicate to the Serial Monitor via the hardware serial on the Mega.

No you don't :slight_smile:

the Arduino Mega has 4 hardware Serial ports named Serial, Serial1, Serial2, Serial3. You don't need to do anything to declare them the IDE does the right thing for you when you compile for a MEGA.

Serial is connected to pin 0 and 1 and is used by the Serial Monitor over USB. So don't mess with pin 0 and 1 nor Serial, use that as your connection to upload code and display stuff in the Serial Monitor

That leaves you with 3 other hardware Serial ports you can use as you see fit to communicate with external TTL Serial devices.


As you can see Serial1 on pins 19 (Rx1) and 18 (Tx1), Serial2 on pins 17 (Rx2) and 16 (Tx2), Serial3 on pins 15 (Rx3) and 14 (Tx3) and the standard Serial port is on pins 0 (Rx0) and 1 (Tx0)

The code would just look like this

#include <SGBotic_MHZ19.h>
#include <SGBotic_PMS5003.h>

SGBotic_PMS5003 PMS5003Sensor = SGBotic_PMS5003(&Serial1);
SGBotic_MHZ19 CO2Sensor = SGBotic_MHZ19(&Serial2);

void setup()
{
  Serial.begin(115200); // for the Serial Monitor can be used at the speed you want, 115200 better than 9600 - why go slow :)
  co2.begin(9600); 
  PMS5003.begin(9600); 
  Serial.println("Sensors will begin reading in 30s");
  delay(30000); //delay 30s
}

...

surreal123:
For further understanding, in the case of Uno, is this link: https://www.arduino.cc/en/Tutorial/TwoPortReceivea good source of how I can call each of the sensors individually to start sending info?

Yes this is the right tutorial but as explained above this will kinda work if whatever is attached on the other end of the Serial line does not speak when you are not listening. They mention so as well in the code:

In order to listen on a software port, you call port.listen().
When using two software serial ports, you have to switch ports
by listen()ing on each one in turn. Pick a logical time to switch
ports, like the end of an expected transmission, or when the
buffer is empty. This example switches ports when there is nothing
more to read from a port

In your case if you can't control when you get input from your sensor (I've not looked at the library to see if you ping them to get data and they never speak to you otherwise or if there is a stream of input) then that will be hard to implement. If on the other hand the sensors need to be pinged to send information back then the technique described in this article is appropriate for your needs (but beware Software Serial is not as good as a true hardware port esp. if lots of data comes in and can conflict with other stuff in your code)