two port software serial problem

Hi,

I have tried the following softwareserial example for 2 ports:

#include <SoftwareSerial.h>
// software serial #1: RX = digital pin 10, TX = digital pin 11
SoftwareSerial portOne(10, 11);

// software serial #2: RX = digital pin 8, TX = digital pin 9
// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega
SoftwareSerial portTwo(8, 9);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // Start each software serial port
  portOne.begin(9600);
  portTwo.begin(9600);
}

void loop() {
  // By default, the last intialized port is listening.
  // when you want to listen on a port, explicitly select it:
  portOne.listen();
  Serial.println("Data from port one:");
  // while there is data coming in, read it
  // and send to the hardware serial port:
  while (portOne.available() > 0) {
    char inByte = portOne.read();
    Serial.write(inByte);
  }

  // blank line to separate data from the two ports:
  Serial.println();

  // Now listen on the second port
  portTwo.listen();
  // while there is data coming in, read it
  // and send to the hardware serial port:
  Serial.println("Data from port two:");
  while (portTwo.available() > 0) {
    char inByte = portTwo.read();
    Serial.write(inByte);
  }

  // blank line to separate data from the two ports:
  Serial.println();
}

however it is not working that well: printed out data is corrupted.

looking around on the web it is my understanding that the issue lies with the fact softwareserial have only one buffer that it uses for all the created ports.

so I would like to modify the library so that a new buffer (structure containg the buffer , header_position and tail_position) is assigned to each port we define.

however what I am struggling with is then how to refer back to the said buffers when calling the read() functions.

As suggestions on how this can be coded in would be much appreciated.

SoftwareSerial.cpp (13.1 KB)

SoftwareSerial.h (3.89 KB)

That's not the only issue - software serial requires the full attention of the processor to send or receive. That means that if you have two software serial ports, and one of them receives a character while the other is receiving or transmitting a character, you'll get garbage. You'll have the same problem if you try to transmit a character while receiving on one instance of software serial (to demo this, do a simple sketch that echos everything it receives on serial - if you use the hardware serial port, this works, while it will not work with software serial). Normally you work around this by listening to only one port at a time, which renders the buffer issue irrelevant.

If you cannot work around the limitations of software serial, you'll need to use a microcontroller with more hardware serial ports (such as the atmega 2560, as used in the Arduino Mega, which has 4 hardware serial ports), or the atmega1284 ( used in numerous unofficial boards and supported by the excellent MightyCore - github.com/MCUDude/MightyCore )

There are two other libraries that should be used, if possible.

  1. AltSoftSerial is the best alternative:

It only works on two specific pins.
You can only have one instance of AltSoftSerial.
It can transmit and receive at the same time.
It is very efficient.

  1. NeoSWSerial is almost as good:

It works on any pins.
It only supports baud rates 9600, 19200 and 38400.
You can have multiple instances of NeoSWSerial, but you can only listen to one at a time.
It can transmit and receive at the same time.
It is almost as efficient as AltSoftSerial, but it is still much better than SoftwareSerial.

Are you sure you need 3 serial ports? That is, are you sure you need 1 HardwareSerial (i.e., Serial) and 2 software serial ports? Sometimes, a device only needs to send to the Arduino (e.g., a GPS) or only receive from the Arduino (e.g., a display). You could use one serial port for both devices, as long as you can set them to the same baud rate.

Sometimes you can hook both of their receive pins to the Arduino transmit pin, and send commands to both. This is possible if the command sets are “different” enough. For example, GPS commands start with a ‘$’ and SIM commands start with “AT”. They would each ignore the commands for the other device.

And if your final installation does not use the USB port (aka Serial), you could use it for one of your interfaces.

BTW, calling listen() empties the input buffer, so you will never find any characters available after switching. :frowning:

Cheers,
/dev

Thank you DrAzzy, /dev for your comments. I now understand betterr where the issue lies and what alternatives are available. I will give those a try. they should provide the fix I need.