Arduino: Scheduling multiple SoftwareSerial ports

The SoftwareSerial library included with the Arduino environment is fantastic, and allows you to have multiple software serial ports in addition to the hardware UART. Unfortunately though, you can only receive data on one port at a time.

You can easily select which port to listen to using the inbuilt

softwareserial.listen();

Any incoming data on another port will be discarded. Using this method wherever I needed to change serial ports actually ended up being a little bit clumsy and didn’t work that well. I would end up with garbeled data coming in all over the place.

So, I wrote this simple scheduler to handle the scheduling of SoftwareSerial access:

boolean ssScheduler(byte requestPort) { boolean ret = false; // Port not locked, assign + reset timer if ((!SS_LOCKED_BY) || (SS_LOCKED_BY == requestPort)) { SS_LOCKED_BY = requestPort; ss_lock_timeout = millis()+SS_LOCK_TIME; ret = true; } else if (SS_LOCKED_BY != requestPort) { //has timout expired? if (millis() >= ss_lock_timeout) { //If so, release the lock and assign to the requesting port ssReleaseLock(); SS_LOCKED_BY = requestPort; ss_lock_timeout = millis()+SS_LOCK_TIME; ret = true; } else { //Otherwise, deny the request ret = false; } } switch(SS_LOCKED_BY) { case 0: //No one has locked the SS system break; case 1: // GSM - SoftSer1. SoftSer1.listen(); break; case 2: SoftSer2.listen(); break; default: break; } return ret; }

And the function to release the serial lock

void ssReleaseLock() { SS_LOCKED_BY = 0; ss_lock_timeout = 0; }

And we just need to add in the appropriate control structures where we need to use a software serial port:

if (ssScheduler(SOFTSER1)) { // Do stuff with SoftwareSerial here ssReleaseLock() // When finished }

Depending on requirements you may actually want to handle something if the lock is denied, or loop it so it will continue to retry until the lock is available

Doing this, when a function is called it can request control of the software serial system to listen for data. When it has a lock, the lock will be held until either it is released or another function requests control and the timeout of 10 seconds has expired (In which case it will be released and assigned to the requesting function.

In testing it seems to work very smoothly with no more garbled data!