Arduino Mega 2560 - Redefine Serial on the fly to Serial1, Serial2 or Serial3

I am using 3 of the Arduino Mega2560's Serial Ports. One for USB to PC, one for Bluetooth and one for GPS.
Serial.print prints to the USB port to the PC. However, in the program I want to redefine Serial to Serial2 so that the statement Serial.print will now print to the Bluetooth port. I understand that I could use Serial2.print but it would save a lot of code if I could just change what port is referenced by Serial.print.

The program monitors whether there are characters from both ports.
if (Serial.available() > 0 || BTSerial.available() > 0)
{ if (Serial.available()==0) {incoming_char = BTSerial.read();}
else {incoming_char = Serial.read(); }

If I send a certain command ('s') from the Bluetooth module (via a smartphone), I want all Serial.print statements to now reference the Bluetooth serial port (BTSerial) instead of the USB port.

I could do it with Software.Serial
#include <SoftwareSerial.h> //for the bluetooth communications
SoftwareSerial BTSerial(8,9);
by tying BT Rx to Tx (which I've done with a Pro-Mini) to get Serial.print to print to both ports.

But since the Mega2560 already has multiple serial ports, why not use them instead.
If no simple solution then I will use the hardware solution (BT Rx to Tx).

do a #define OUTGOINGPORT Serial
write there OUTGOINGPORT.print("Hello World");
when you want to Send to BT, change it to #define OUTGOINGPORT Serial2

otherwise define a reference to the portHardwareSerial & outgoingPort = Serial;, write/print to outgoingPort and change it when needed to Serial2

I prefer to avoid preprocessor macros if possible. Trouble with a reference is you only get to assign it a value once - upon initialization. So, you would need to define a new reference every time you want to change it.

Define a global pointer to a Stream object:

Stream *outputPort;

Then, assign a value as required:

outputPort = &Serial;
outputPort = &Serial1;

You'll then have to use the '->' notation for calling functions on the object being pointed to:

outputPort->print("Hello World");

EDIT:
In fact, if you're only sending data to it, you could use a Print * pointer. That way you could also use any output-only class that inherits from the Print class (eg. LCD).

Thanks for the help.

I tried this;
#include <Streaming.h>
Stream *outputPort;
outputPort = &Serial;

But returns error that outputPort does not name a type.
So never having used Stream, I suspect I am missing something.

However, I appear to have found a simple solution thanks to a member named septillion.
#define BTSerial Serial2
HardwareSerial *serialInUse;
void setup() {
serialInUse = &Serial;

void loop() {

serialInUse ->println("Hello World");

else if(incoming_char== 'j') {serialInUse = &BTSerial;}
else if(incoming_char== 'k') {serialInUse = &Serial;}

I have tried it and seems to work just fine. I just have to change all the print statements from Serial. to serialInUse-> which is easy enough.

markvincenzo:
Thanks for the help.

I tried this;
#include <Streaming.h>
Stream *outputPort;
outputPort = &Serial;

But returns error that outputPort does not name a type.
So never having used Stream, I suspect I am missing something.

Post the complete code that you tried and the complete error messages. Code snippets and your paraphrased versions of the error message won't help us help you. You don't need Streaming.h.

markvincenzo:

HardwareSerial *serialInUse;

You're better off using

Stream *serialInUse;

Because not all Serial ports on all boards are instances of the HardwareSerial class.

And, as I also advised, if you're only doing output, then:

Print *serialInUse;

Is even more general.

Thanks again. Your method also works.
My mistake was that I did not do the reassignment serialInUse = &Serial; in void setup().

Here is the code that I tried with your suggestion and it works;
/* ---------------------------------------------------------------- //
Data Acquisition for Pond Skimmer V2.00 11-6-2020 by A.E.Nuemann Ph.D
for Arduino Mega 2560, 8K Ram, 256K Flash, 4 Serial Ports

Set IDE as follows;
Board = Mega 2560
Processor = ATMega2560

Collect data on GPS, Ultrasonic Ranging, Accelerometer, Gyroscope and Compass Heading
// ---------------------------------------------------------------- */
#include <Wire.h>

int SerialOn = 0;

//Serial Ports on Mega2560
// Serial0 = 0-Rx, 1-Tx USB Comm

// GPSSerial = 19-Rx, 18-Tx GPS
#define GPSSerial Serial1

// Serial2 = 17-Rx, 16-Tx Bluetooth
#define BTSerial Serial2

// Serial3 = 15-Rx, 14-Tx
Stream *serialInUse;

//****************** SETUP ******************************/
void setup() {
serialInUse = &Serial;

SetSerial115(); // init serial port to 115,200 baud
BTSerial.begin(115200); // Bluetooth
delay(200);
serialInUse ->println("Pond Skimmer Data Acquisition using Arduino ATMega 2560");
}

//********************** MAIN *************************/
void loop() {

GetSerialCommands();
serialInUse ->println("Hello World");
delay (1000);

}

//********************** Functions *************************/

void GetSerialCommands() {
char incoming_char="";
if (Serial.available() > 0 || BTSerial.available() > 0)
{ if (Serial.available()==0) {incoming_char = BTSerial.read();}
else {incoming_char = Serial.read(); }

if(incoming_char== 'j') {serialInUse = &BTSerial;}
else if(incoming_char== 'k') {serialInUse = &Serial;}
}
}

//**************************************************************

void SetSerial115(){
char incoming_char="";
if (SerialOn != 115)
{
Serial.begin(115200);
while (!Serial) {
// will pause until serial console opens
delay(10);}
}
incoming_char = BTSerial.read(); //read to flush it
incoming_char = Serial.read();
SerialOn = 115;
}

Unsure why you did not try what was suggested in #1 as the define was already there. Using a reference lets you keep using the dot notation instead of ->

Using a Print or Stream pointer won’t support begin() probably

The error you had before was because you did not perform the declaration and initialization in one step. Code can only live in functions so instead of

 Stream *outputPort;
outputPort = &Serial;

you needed to do Stream *outputPort = &Serial;

J-M-L:
Using a Print or Stream pointer won’t support begin() probably

That's the whole point. Not every object named "Serialx" is an instance of HardwareSerial. For example, "Serial" is an instance of usb_serial_class on a Teensy 3.2 (while Serial1 is an instance of HardwareSerial). Thus, they may not need a begin() method. Likewise other classes you may want to do I/O with (like an LCD) might use a different initialization method then begin().

So, if you want to dynamically and repeatedly switch back and forth between different I/O objects, you initialize each one using its native method (begin or whatever) and then use a pointer to the most general class that addresses them all. So, that's Stream * if you want to do input / output and it's Print * if you only need to do output.

A reference is no good for dynamic and repeated switching because you can't reassign what it references.

Thanks to you both. I appreciate the information and methods.
I have mainly done assembly language programming but started doing some projects with the Arduino a few years ago and still learning!

gfvalvo:
That's the whole point.

fair enough but OP’s need was on a MEGA with an easy way to switch hardware serial without changing many lines. The define or the reference or the pointer with an HardwareSerial type gets him there by just changing the number

It's good that different solutions were offered. That gives everyone some different ideas to try.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.