Mega Serial1 <--> UNO SoftwareSerial... what am I missing?

I'm tearing my hair out. Having got the Nano chatting happily with Serial to enable/disable sampling and perform other actions by receipt of simple commands I'm now attempting to connect the Nano to a Mega which will collect data from several places and merge into one.

I just can't get the mega<-->nano comms working and it's driving me nuts!

Mega: Take Serial and pipe to Serial1, read from Serial1 and echo to Serial

#define PULSE_PIN 51

void setup()
{
pinMode ( PULSE_PIN, OUTPUT ) ;
Serial.begin(115200);
Serial1.begin ( 57600 ) ;
}
void loop()
{

if ( Serial.available() >0 )
{
Serial1.write ( Serial.read() ) ;
}
if ( Serial1.available() > 0 )
{
Serial.write ( Serial1.read() ) ;
}

if ( millis() % 1000 < 500 )
{
digitalWrite (PULSE_PIN, HIGH) ;
}
else
{
digitalWrite (PULSE_PIN, LOW) ;
}
}

NANO: Read SoftwareSerial and then echo back

#include <SoftwareSerial.h>
SoftwareSerial MySerial(5, 6) ; // RX, TX

#define PULSE_PIN 12

void setup()
{
pinMode ( PULSE_PIN, OUTPUT ) ;
MySerial.begin(57600);
}

void loop()
{
unsigned char chIn ;
static bool bLight = false ;

if ( MySerial.available() )
{
chIn = MySerial.read() ;
MySerial.write ( chIn ) ;

if ( bLight )
{
digitalWrite ( PULSE_PIN, HIGH ) ;
}
else
{
digitalWrite ( PULSE_PIN, LOW ) ;
}
bLight = !bLight ;

}

}

I've made sure that NANO-TX --> MEGA-RX and NANO-RX -->MEGA-TX. Hey, it's got so bad that I've even reversed them, just in case!

Are there any strange hardware requirements that I have to be aware of related to SoftwareSerial please? Pull-ups/downs/etc?

The two boards have a common ground and VCC and are < 15cm apart.

I've happily had Megas chatting with each other using Serial1/2/3.

Sorry if this isn't quite in the right section of the forum... this seemed most appropriate.

Did you try dropping the baud rate.
Leo..

Indeed I have Leo; 9,600, 57,600 115,200, and I've even made sure both ends are at the same speed at the same time! :slight_smile:

Could it be that the partity/stop/data settings for the SoftwareSerial default don't match Serial1's default on the Mega? Alas, I've not found what the SoftwareSerial defaults to.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. I would use those examples (preferably the 3rd one) on both the Mega and the Nano.

...R

I've now got them chatting, of a sort, swapping the wires over so that TX<-->TX and RX<-->RX, if the TX/RX pin labeling in the comments in the example at https://www.arduino.cc/en/Tutorial/SoftwareSerialExample is correct.

It's definitely passing in and back as I'm incrementing the char on the nano before echo. There's data corruption though, and that's without any interrupts set up (yet) for handling my sensors, so I'm giving up with this and I'm going to knock out a six-wire bidirectional protocol instead; one that won't be affected by interrupts.

Thanks for the comment folks.

I'm going to knock out a six-wire bidirectional protocol instead

On the surface, that certainly sounds more challenging than getting softwareSerial to function, especially the

one that won't be affected by interrupts

part.

But, as you haven't said anything further about what you were trying to do, it makes it difficult to suggest other ways of doing this. For instance, I2C, since the boards are close to one another. But, hey, if six-wire bidirectional protocols are easy for you to knock out, have at it. When you're done knocking out the software side, you can figure out which hardware would be...

Hey, you might first want to take inventory of the hardware functionality you have and then... oh, never mind.

You're not the only one who has problems wrapping his/her head around SoftwareSerial. I eventually managed to get an example working reliably with between a Leonardo (has Serial1) and an Uno.

I suspect that the trick is in some form of protocol where you will not send data to the Uno till you have received a reply from it after sending data. In the below Leonardo code. I've used a flag to keep track of this.

The code for both is fully based on Robin2's updated serial input basics.

Leonardo code

const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup()
{
  Serial.begin(250000);
  while (!Serial);
  Serial1.begin(9600);

  Serial.println("Leonardo ready");
}

void loop()
{
  char hallo[] = {0x02, 'h', 'a', 'l', 'l', 'o', 0x03, '\0'};

  static bool fAwaitingAck = false;
  if (fAwaitingAck == false)
  {
    Serial1.print(hallo);
    fAwaitingAck = true;
  }
  recvWithStartEndMarkers();
  if (newData == true)
  {
    showNewData();
    fAwaitingAck = false;
  }
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = 0x02;
  char endMarker = 0x03;
  char rc;

  while (Serial1.available() > 0 && newData == false)
  {
    rc = Serial1.read();

    if (recvInProgress == true)
    {
      if (rc != endMarker)
      {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars)
        {
          ndx = numChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

void showNewData()
{
  static unsigned long counter = 0;

  if (newData == true)
  {
    Serial.print(++counter); Serial.print(": ");
    Serial.println(receivedChars);
    newData = false;
  }
}

Uno code

#include <SoftwareSerial.h>

SoftwareSerial mySerial(6, 7); // RX, TX

const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup()
{
  Serial.begin(250000);
  mySerial.begin(9600);

  Serial.println("Uno ready");
}

void loop()
{
  char ack[] = {0x02, 'A', 'C', 'K', 0x03, '\0'};

  recvWithStartEndMarkers();
  if (newData == true)
  {
    showNewData();
    mySerial.print(ack);
  }
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = 0x02;  // STX
  char endMarker = 0x03;    // ETX
  char rc;

  while (mySerial.available() > 0 && newData == false)
  {
    rc = mySerial.read();

    if (recvInProgress == true)
    {
      if (rc != endMarker)
      {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars)
        {
          ndx = numChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

void showNewData()
{
  static unsigned long counter = 0;
  if (newData == true)
  {
    Serial.print(++counter); Serial.print(": ");
    Serial.println(receivedChars);
    newData = false;
  }
}

Now this implementation might be overkill for your needs, but it might help you on the way.

Just use AltSoftSerial or NeoSWSerial instead. That's a lot easier than trying to get SoftwareSerial to work.

Both of those libraries can transmit and receive at the same time. SoftwareSerial cannot.

AltSoftSerial and NeoSWSerial do not disable interrupts for the entire character receipt time. 1ms @ 9600 is forever, to a 16MHz MCU. SoftwareSerial is totally focused receiving or transmitting a char.

NeoSWSerial disables interrupts for the entire character transmit time, but it can still receive characters. It only works at 9600, 19200 and 38400 baud rates. Those are the most common baud rates, and 38400 is really an upper limit for reliable software serial ports.

AltSoftSerial does not disable interrupts for either transmit or receive. It's the best choice when you need a software serial port, but it only works on two specific pins (8 & 9 on the UNO & Nano).

The are both drop-in replacements for SoftwareSerial. Your original sketch should work correctly with either library. NeoSWSerial is available from the Arduino IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries.