Max485 Burns up

Hereafter a simple sketch for Master and Slave.
For the Master I have 2 versions. Which is the best ?

Version 1: Enable of Max486 is low, Just before sending High and after sending Low
Version 2: Enable of Max486 is Hgh, just before reading Low and after reading again High.

Master version 1

/*
 * Master RS485 Version 1
 */
#include <SoftwareSerial.h>

#include "RS485_protocol.h"
#define SSerialRX   51        // Serial Receive pin  RO
#define SSerialTX   50        // Serial Transmit pin  DI
const byte ENABLE_PIN = 49;   // Enable sending rs485  DE and RE are connected on board
SoftwareSerial rs485 (SSerialRX, SSerialTX);  // receive pin, transmit pin
byte buf[27];

// callback routines RS485
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}

void setup() {

  rs485.begin (19200);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  digitalWrite (ENABLE_PIN, LOW);  // disable sending
}

void loop() {
  // Other code before
  // send message
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending
  delayMicroseconds(50);
  sendMsg (fWrite, "Message to Slave",  16);
  rs485.flush();
  delayMicroseconds(50);
  digitalWrite (ENABLE_PIN, LOW);  // disable sending

  // receive message
  int received = recvMsg (fAvailable, fRead, buf, 16, 250);
 
  if (received > 0) {
    // New message received in buf[]
    // process Message
  }

  // Other code
}

Master version 2

/*
   Master RS485 - Version 2
*/
#include <SoftwareSerial.h>
#include "RS485_protocol.h"
#define SSerialRX   51        // Serial Receive pin  RO
#define SSerialTX   50        // Serial Transmit pin  DI
const byte ENABLE_PIN = 49;   // Enable sending rs485  DE and RE are connected on board
SoftwareSerial rs485 (SSerialRX, SSerialTX);  // receive pin, transmit pin
byte buf[27];

// callback routines RS485
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}

void setup() {

  rs485.begin (19200);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending

}

void loop() {
  // Point A in time
  // send message

  delayMicroseconds(50);
  sendMsg (fWrite, "Message to Slave",  16);
  rs485.flush();
  delayMicroseconds(50);


  // receive message
  digitalWrite (ENABLE_PIN, LOW);  // disable sending
  int received = recvMsg (fAvailable, fRead, buf, 16, 250);
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending
  // Point B in time

  if (received > 0) {
    // New message received in buf[]
    // process Message
  }

  // Other code
}

Slave

/*
   Slave RS485
*/
#include <SoftwareSerial.h>

#include "RS485_protocol.h"
#define SSerialRX   7    //Serial Receive pin RO
#define SSerialTX   8    //Serial Transmit pin DI
const byte ENABLE_PIN = 4; // Enable sending rs485  DE and RE are connected on board
SoftwareSerial rs485 (SSerialRX, SSerialTX);  // receive pin, transmit pin

byte buf[27];

// callback routines RS485
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}

void setup()
{

  rs485.begin (19200);
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable

}

void loop()
{
  // other preparing code
  int received = recvMsg (fAvailable, fRead, buf, 16, 250);
  if (received > 0) {
    // Process message
    // Prepare Response message
    digitalWrite (ENABLE_PIN, HIGH);  // enable sending
    delayMicroseconds(50);
    sendMsg (fWrite, "Response MSG", 12);
    rs485.flush();
    delayMicroseconds(50);
    digitalWrite (ENABLE_PIN, LOW);  // disable sending
  }
  // Other post processing code
}
#define SSerialRX   51        // Serial Receive pin  RO
#define SSerialTX   50        // Serial Transmit pin  DI
const byte ENABLE_PIN = 49;   // Enable sending rs485  DE and RE are connected on board
SoftwareSerial rs485 (SSerialRX, SSerialTX);  // receive pin, transmit pin

if you have that many pins, you're likely using a Mega, which has 4 UART's so why would you want to use swSerial ?

For sure this is better. You are sending something, and pretty much giving permission to a node to respond. You want to make sure that the master is no longer transmitting.

Now there are a few things.
in the master.

  sendMsg (fWrite, "Message to Slave",  16);
  rs485.flush();
  delayMicroseconds(50);
  digitalWrite (ENABLE_PIN, LOW);  // disable sending

Given that you are sending using swSerial, the 50us may actually just be long enough since flush actually completes the whole sending before it considers the sending complete, but even so i would wait just a tad longer, say 100us
If you switch to hwSerial, you will have to wait at least 1ms at 19200kbps to complete sending 2 more bytes.

sendMsg (fWrite, "Message to Slave",  16);

now where is that function defined ?

Within the slave sketch, you only give permission to send regardless of what has come in and of what length that may be. If you have multiple slaves you have a problem.
You need the slave to verify the message is for that particular node and only then respond, and only within a timeframe. If a complete message comes in, the slave can, let's say, respond within 2 seconds, during which the master is waiting for that response. The slave should make sure that it has received a complete message and the master is not longer in 'drive-mode' If the response hasn't comes within 2.5 seconds, the master should be free to send again, either the same message again or a different message, possibly for a different node.
You need to incorporate this into you sketches before you start sending / testing. Actually safest would be to first let only the master send and blink a led on the slave,

Yes this is a mega, with a multiplexer board plugged in. This board has a UNO size. It’s a multiplexer.
So I can’t reach the pins for serial1, 2 or 3.
Idea to by a board of size mega, where I can connect to side of it.
But today not yet.

Ok I will change this and try.
For your info. The delay now is 2 milliseconds. But I have read somewhere it may be some microseconds.
So you suggest 100 microseconds.

In the

#include "RS485_protocol.h"

You are right.
But I the running sketches I have a complete protocol developed, with MasterID, SlaveID, FunctionType, Messagelength and message.
And there are a lot of checks:

  • is the message coming from the master
  • is the message for me
  • is the length correct
  • is the function correct

And if all these are positive, there is a reply.
And the master does the same checks, even he checks that the answer is coming from the slave to which the request was send.
Pretty nice

Picture ?

Well simply put, if you would be using hwSerial, flush() would hold the program until all bytes would be moved from the buffer to the UART, after which still nearly 2 bytes would have to be sent, which at 19200 takes almost 2 ms. You are using swSerial, where flush() holds the program until the last bit has been banged so to say, so the wait can be quite a lot shorter. 1 bit is about 50us, And that should be enough.

That's what i mean. Probably good to wait just a moment before responding to give the master time to get ready. You should also make sure that the slave responds within a period of time, and the master wait for the reply for a limited period of time only.

The response is immediately after the received message.

This is done in the RS485 protocol.

int recvMsg (AvailableCallback fAvailable,   // return available count
              ReadCallback fRead,             // read one byte
              byte * data,                    // buffer to receive into
              const byte length,              // maximum buffer size
              unsigned long timeout)          // milliseconds before timing out

RS485_protocol.h

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WConstants.h"
#endif

typedef void (*WriteCallback)  (const byte what);    // send a byte to serial port
typedef int  (*AvailableCallback)  ();    // return number of bytes available
typedef int  (*ReadCallback)  ();    // read a byte from serial port

void sendMsg (WriteCallback fSend, 
              const byte * data, const byte length);
int recvMsg (AvailableCallback fAvailable, ReadCallback fRead, 
              byte * data, const byte length, 
              unsigned long timeout = 500);

RS485_protocol.cpp

/*
 RS485 protocol library.

 Devised and written by Nick Gammon.
 Date: 14 November 2011
 Version: 1.1

 Version 1.1 reset the timeout period after getting STX.

 Can send from 1 to 255 bytes from one node to another with:

 * Packet start indicator (STX)
 * Each data byte is doubled and inverted to check validity
 * Packet end indicator (ETX)
 * Packet CRC (checksum)


 To allow flexibility with hardware (eg. Serial, SoftwareSerial, I2C)
 you provide three "callback" functions which send or receive data. Examples are:

 void fWrite (const byte what)
 {
 Serial.write (what);
 }

 int fAvailable ()
 {
 return Serial.available ();
 }

 int fRead ()
 {
 return Serial.read ();
 }


PERMISSION TO DISTRIBUTE

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 and associated documentation files (the "Software"), to deal in the Software without restriction,
 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.


 LIMITATION OF LIABILITY

 The software is provided "as is", without warranty of any kind, express or implied,
 including but not limited to the warranties of merchantability, fitness for a particular
 purpose and noninfringement. In no event shall the authors or copyright holders be liable
 for any claim, damages or other liability, whether in an action of contract,
 tort or otherwise, arising from, out of or in connection with the software
 or the use or other dealings in the software.

 */


#include <RS485_protocol.h>

const byte STX = '\2';
const byte ETX = '\3';

// calculate 8-bit CRC
static byte crc8 (const byte *addr, byte len)
{
  byte crc = 0;
  while (len--)
    {
    byte inbyte = *addr++;
    for (byte i = 8; i; i--)
      {
      byte mix = (crc ^ inbyte) & 0x01;
      crc >>= 1;
      if (mix)
        crc ^= 0x8C;
      inbyte >>= 1;
      }  // end of for
    }  // end of while
  return crc;
}  // end of crc8

// send a byte complemented, repeated
// only values sent would be (in hex):
//   0F, 1E, 2D, 3C, 4B, 5A, 69, 78, 87, 96, A5, B4, C3, D2, E1, F0
void sendComplemented (WriteCallback fSend, const byte what)
{
byte c;

  // first nibble
  c = what >> 4;
  fSend ((c << 4) | (c ^ 0x0F));

  // second nibble
  c = what & 0x0F;
  fSend ((c << 4) | (c ^ 0x0F));

}  // end of sendComplemented

// send a message of "length" bytes (max 255) to other end
// put STX at start, ETX at end, and add CRC
void sendMsg (WriteCallback fSend, const byte * data, const byte length)
{
  fSend (STX);  // STX
  for (byte i = 0; i < length; i++)
    sendComplemented (fSend, data [i]);
  fSend (ETX);  // ETX
  sendComplemented (fSend, crc8 (data, length));
}  // end of sendMsg

// receive a message, maximum "length" bytes, timeout after "timeout" milliseconds
// if nothing received, or an error (eg. bad CRC, bad data) return 0
// otherwise, returns length of received data
int recvMsg (AvailableCallback fAvailable,   // return available count
              ReadCallback fRead,             // read one byte
              byte * data,                    // buffer to receive into
              const byte length,              // maximum buffer size
              unsigned long timeout)          // milliseconds before timing out
  {

  unsigned long start_time = millis ();

  bool have_stx = false;

  // variables below are set when we get an STX
  bool have_etx;
  byte input_pos;
  bool first_nibble;
  byte current_byte;

  while (millis () - start_time < timeout)
    {
    if (fAvailable () > 0)
      {
      byte inByte = fRead ();
      switch (inByte)
        {

        case STX:   // start of text
          have_stx = true;
          have_etx = false;
          input_pos = 0;
          first_nibble = true;
          start_time = millis ();  // reset timeout period
          break;

        case ETX:   // end of text
          have_etx = true;
          break;

        default:
          // wait until packet officially starts
          if (!have_stx)
            break;

          // check byte is in valid form (4 bits followed by 4 bits complemented)
          if ((inByte >> 4) != ((inByte & 0x0F) ^ 0x0F) )
            return -1;  // bad character

          // convert back
          inByte >>= 4;

          // high-order nibble?
          if (first_nibble)
            {
            current_byte = inByte;
            first_nibble = false;
            break;
            }  // end of first nibble

          // low-order nibble
          current_byte <<= 4;
          current_byte |= inByte;
          first_nibble = true;

          // if we have the ETX this must be the CRC
          if (have_etx)
            {
            if (crc8 (data, input_pos) != current_byte)
              return -2;  // bad crc
            return input_pos;  // return received length
            }  // end if have ETX already

          // keep adding if not full
          if (input_pos < length)
            data [input_pos++] = current_byte;
          else
            return -3;  // overflow
          break;

        }  // end of switch
      }  // end of incoming data
    } // end of while not timed out

  return 0;  // timeout
} // end of recvMsg

You really want a picture. Don't be afraid.

Steering right side with master Arduino Mega 1

Master Arduino, you can see him with the multiplexer on top.

Steering part of right side with Slave with ID6 Nano

Slave ID 2 Nano to read RFID tags under some locomotives

Steering panel for the left part with slave ID 4 Mega. And board on it with the screws.

Steering panel left side with the L298N modules.

It looks disorderly, but it works fine.

1 Like

Here I'm again.
I desided to create 2 RS485 networks. But I think the libray I use don't support this.

RS485a connection with slave 2 and slave 6: Both slaves gets the messages and send the response, but the master don't receive the response message.
Even when I disconnect the cable to Slave 2. Then RS485a is only connected between Master and slave 6.

RS485b connection with slave 4: This is working perfect.

Here is the Master Code declarations:

// Needed for RS485
#include <SoftwareSerial.h>
#include "RS485_protocol.h"

// rs485a Communication with Slave 2 and 6
#define SSerialTXa  50        // 42 Serial Transmit pin Groen DI 
#define SSerialRXa  51        // 43 Serial Receive pin Oranje RO
const byte ENABLE_PINa = 49;   // 41 Enable sending rs485 Geel DE
SoftwareSerial rs485a (SSerialRXa, SSerialTXa);  // receive pin, transmit pin


// RS485b Communication with Slave 4
#define SSerialTXb  42        // 50 Serial Transmit pin Groen DI
#define SSerialRXb  43        // 51 Serial Receive pin Oranje RO
const byte ENABLE_PINb = 41;  // 49Enable sending rs485 Geel DE
SoftwareSerial rs485b (SSerialRXb, SSerialTXb);  // receive pin, transmit pin

elapsedMillis timerRS485;

Callback routines

// callback routines rs485
void fWritea (const byte what)
{
  rs485a.write (what);
}
int fAvailablea ()
{
  return rs485a.available ();
}
int fReada ()
{
  return rs485a.read ();
}
// callback routines RS485b
void fWriteb (const byte what)
{
  rs485b.write (what);
}
int fAvailableb ()
{
  return rs485b.available ();
}
int fReadb ()
{
  return rs485b.read ();
}

Setup code

  rs485a.begin (19200); // Initialize serial communications with MAX485
  pinMode (ENABLE_PINa, OUTPUT);  // driver output enable
  digitalWrite (ENABLE_PINa, LOW);  // disable sending

  rs485b.begin (19200); // Initialize serial communications with MAX485
  pinMode (ENABLE_PINb, OUTPUT);  // driver output enable
  digitalWrite (ENABLE_PINb, LOW);  // disable sending

Code in the Loop

  int received;
  if (arduino == 4) {
    sendarduinoB ();
    received = recvMsg (fAvailableb, fReadb, buf, sizeof(buf), 600);
  } else {
    sendarduinoA ();
    received = recvMsg (fAvailablea, fReada, buf, sizeof(buf), 600);
  }
void sendarduinoA () {
  digitalWrite (ENABLE_PINa, HIGH);  // enable sending
  delay(2);
  sendMsg (fWritea, msg,  msg[3] + 4);
  rs485a.flush();
  digitalWrite (ENABLE_PINa, LOW);  // disable sending
}
//===========================================================================
void sendarduinoB () {
  digitalWrite (ENABLE_PINb, HIGH);  // enable sending
  delay(2);
  sendMsg (fWriteb, msg,  msg[3] + 4);
  rs485b.flush();
  digitalWrite (ENABLE_PINb, LOW);  // disable sending
}

What is wrong is this code

Here again the library
RS485.protocol.h

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WConstants.h"
#endif

typedef void (*WriteCallback)  (const byte what);    // send a byte to serial port
typedef int  (*AvailableCallback)  ();    // return number of bytes available
typedef int  (*ReadCallback)  ();    // read a byte from serial port

void sendMsg (WriteCallback fSend, 
              const byte * data, const byte length);
int recvMsg (AvailableCallback fAvailable, ReadCallback fRead, 
              byte * data, const byte length, 
              unsigned long timeout = 500);

and the RS485_protocol.cpp

/*
 RS485 protocol library.

 Devised and written by Nick Gammon.
 Date: 14 November 2011
 Version: 1.1

 Version 1.1 reset the timeout period after getting STX.

 Can send from 1 to 255 bytes from one node to another with:

 * Packet start indicator (STX)
 * Each data byte is doubled and inverted to check validity
 * Packet end indicator (ETX)
 * Packet CRC (checksum)


 To allow flexibility with hardware (eg. Serial, SoftwareSerial, I2C)
 you provide three "callback" functions which send or receive data. Examples are:

 void fWrite (const byte what)
 {
 Serial.write (what);
 }

 int fAvailable ()
 {
 return Serial.available ();
 }

 int fRead ()
 {
 return Serial.read ();
 }


PERMISSION TO DISTRIBUTE

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 and associated documentation files (the "Software"), to deal in the Software without restriction,
 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.


 LIMITATION OF LIABILITY

 The software is provided "as is", without warranty of any kind, express or implied,
 including but not limited to the warranties of merchantability, fitness for a particular
 purpose and noninfringement. In no event shall the authors or copyright holders be liable
 for any claim, damages or other liability, whether in an action of contract,
 tort or otherwise, arising from, out of or in connection with the software
 or the use or other dealings in the software.

 */


#include <RS485_protocol.h>

const byte STX = '\2';
const byte ETX = '\3';

// calculate 8-bit CRC
static byte crc8 (const byte *addr, byte len)
{
  byte crc = 0;
  while (len--)
    {
    byte inbyte = *addr++;
    for (byte i = 8; i; i--)
      {
      byte mix = (crc ^ inbyte) & 0x01;
      crc >>= 1;
      if (mix)
        crc ^= 0x8C;
      inbyte >>= 1;
      }  // end of for
    }  // end of while
  return crc;
}  // end of crc8

// send a byte complemented, repeated
// only values sent would be (in hex):
//   0F, 1E, 2D, 3C, 4B, 5A, 69, 78, 87, 96, A5, B4, C3, D2, E1, F0
void sendComplemented (WriteCallback fSend, const byte what)
{
byte c;

  // first nibble
  c = what >> 4;
  fSend ((c << 4) | (c ^ 0x0F));

  // second nibble
  c = what & 0x0F;
  fSend ((c << 4) | (c ^ 0x0F));

}  // end of sendComplemented

// send a message of "length" bytes (max 255) to other end
// put STX at start, ETX at end, and add CRC
void sendMsg (WriteCallback fSend, const byte * data, const byte length)
{
  fSend (STX);  // STX
  for (byte i = 0; i < length; i++)
    sendComplemented (fSend, data [i]);
  fSend (ETX);  // ETX
  sendComplemented (fSend, crc8 (data, length));
}  // end of sendMsg

// receive a message, maximum "length" bytes, timeout after "timeout" milliseconds
// if nothing received, or an error (eg. bad CRC, bad data) return 0
// otherwise, returns length of received data
int recvMsg (AvailableCallback fAvailable,   // return available count
              ReadCallback fRead,             // read one byte
              byte * data,                    // buffer to receive into
              const byte length,              // maximum buffer size
              unsigned long timeout)          // milliseconds before timing out
  {

  unsigned long start_time = millis ();

  bool have_stx = false;

  // variables below are set when we get an STX
  bool have_etx;
  byte input_pos;
  bool first_nibble;
  byte current_byte;

  while (millis () - start_time < timeout)
    {
    if (fAvailable () > 0)
      {
      byte inByte = fRead ();
      switch (inByte)
        {

        case STX:   // start of text
          have_stx = true;
          have_etx = false;
          input_pos = 0;
          first_nibble = true;
          start_time = millis ();  // reset timeout period
          break;

        case ETX:   // end of text
          have_etx = true;
          break;

        default:
          // wait until packet officially starts
          if (!have_stx)
            break;

          // check byte is in valid form (4 bits followed by 4 bits complemented)
          if ((inByte >> 4) != ((inByte & 0x0F) ^ 0x0F) )
            return -1;  // bad character

          // convert back
          inByte >>= 4;

          // high-order nibble?
          if (first_nibble)
            {
            current_byte = inByte;
            first_nibble = false;
            break;
            }  // end of first nibble

          // low-order nibble
          current_byte <<= 4;
          current_byte |= inByte;
          first_nibble = true;

          // if we have the ETX this must be the CRC
          if (have_etx)
            {
            if (crc8 (data, input_pos) != current_byte)
              return -2;  // bad crc
            return input_pos;  // return received length
            }  // end if have ETX already

          // keep adding if not full
          if (input_pos < length)
            data [input_pos++] = current_byte;
          else
            return -3;  // overflow
          break;

        }  // end of switch
      }  // end of incoming data
    } // end of while not timed out

  return 0;  // timeout
} // end of recvMsg

Well you are using 2 swSerial objects, but for reception you need to tell which of the 2 objects you want to 'listen' to.
I am against you using swSerial on a board that has 4 UARTs but this is the reference

I know you are right. But for the moment I can't acces these port due to the PCB shield on top of the arduino.

MuxShieldII Mayhew Labs
I have 2 options:

  • I can put a side the Max shield from Mayhew Labs and connect it via cables
  • I can by a development board, so I can access the UART port's on the side of that board.

Development Board Mega

Is the used Library not working correctly in this case ?

 if (arduino == 4) {
    sendarduinoB ();
    received = recvMsg (fAvailableb, fReadb, buf, sizeof(buf), 600);
  } else {
    sendarduinoA ();
    received = recvMsg (fAvailablea, fReada, buf, sizeof(buf), 600);
  }

in the recvMsg function, there are different callback functions. fAvailableb and fAvailablea

int fAvailablea ()
{
  return rs485a.available ();
}
int fAvailableb ()
{
  return rs485b.available ();
}

and also fReadb and fReada.

int fReada ()
{
  return rs485a.read ();
}
int fReadb ()
{
  return rs485b.read ();
}

Or should I set the the correct port to listen. like this :

  if (arduino == 4) {
    sendarduinoB ();
    rs485b.listen();
    received = recvMsg (fAvailableb, fReadb, buf, sizeof(buf), 600);
  } else {
    sendarduinoA ();
    rs485a.listen();
    received = recvMsg (fAvailablea, fReada, buf, sizeof(buf), 600);
  }

Post a picture of the board you have, see if i can think of another option.

Pretty much like that, though i would set the port to listen on even before i would start sending.

  if (arduino == 4) {
    rs485b.listen();
    sendarduinoB ();
    received = recvMsg (fAvailableb, fReadb, buf, sizeof(buf), 600);
  } else {
    rs485a.listen();
    sendarduinoA ();
    received = recvMsg (fAvailablea, fReada, buf, sizeof(buf), 600);
  }

listen() sets the port listened on, but it doesn't actually affect any of the other functions.
I also fail to see the benefit of have 2 buses actually.

There is something wrong with the pins I use for RS485a.
When I switch the cables and the PinID’s The other one RS485b is not reading anything.
Are not so much pins available.

Meanwhile I created already an empty board with headers to plug in the multiplexer, so I can reach the hardware serial pins.

I removed the multiplexer and will put it aside.


As the serial1 and serial2 pins are now accessible, I put the cables into those pins, changed the sketch , and yes yes. It’s working.

Next days I have to reconnect the multiplexer and can continue my project.

Many thanks for your help and advice

Yeah that was what i was thinking. I actually would have suggested to solder something to extend the pins for UARTs 1, 2 & 3. Easiest would be female header pin ;-D on the backside of the PCB, had you shown me that picture sooner.

Good idea, but I don't like to solder directly on a board. If I want to change it in the future there can be a problem.

And that Muliplexer shield was not sheep. So I want to be careful.

Hence the suggestion to add female header pins soldered on the bottom side of the Mega, facing inwards, flat on top of the PCB. Female header pins are easy to remove and you can plug things into them, or not. I guess if you don't have them, you'd have to go and buy them.