Arduino to arduino Serial

I've searching all over this forum and all over the internet, but I can't find a SIMPLE solution for my SIMPLE problem. Some of the things that I read are too simple, others are too complex (for me :confused: )
I want to use an Arduino (Nano) that collects data from 3 sensors and send these three (bytes) and an a checksum (integer) over a serial connection to another Arduino (Mega). Besides getting serial info this Mega is doing lots of other stuff. So this Mega can't wait a long time for incoming data.
The Nano collects data continuously and on request of the Mega it sends the last collected data. The Mega receives and continues its other tasks.
I have basic knowledge about programming (how to convert different data types, reading sensors etc.) but I don't understand (can't find) an easy way to send (simple) data from one to another arduino.

Anyone has a simple example to set me on my way ?

in advance : THANKS ! :slight_smile:

Are you writing the code for both Ardinos?

If you are only writing code for the sender, what data format is the receiver expecting?

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

You could easily extend the code to include a checksum, however with a wired connection I doubt if it would be necessary.

...R

If you use this serial transfer library, it already incorporates checksums, cyclic redundancy checking, and start/end markers. It is also very fast and reliable.

Here's an example of how to use the library:

TX Arduino:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';
  
  myTransfer.sendData(3);
  delay(100);
}

RX Arduino:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

PaulVdB:
Anyone has a simple example to set me on my way ?

In the following example --
The NANO has these 3 bytes 0x31, 0x32, and 0x33 data and a computed 1-byte CHKSUM. The NANO will send these 4 bytes data to MEGA once MEGA makes a request to NANO through interrupt.

1. The hardware setup.
uartNanoMas-Mega.png
Figure-1:

2. Sketch for NANO

byte myData[4] = 0x31, 0x32, 0x33, 0x00};
#include<SoftwareSerial.h>
SoftwareSerial SUART(4, 5);

void setup()
{
    byte CHKSUM = ~lowByte(myData[0] + myData[1] + myData[2]) + 1;
    myData[4] = CHKSUM;
    for(byte i=0; j<sizeof myData; i++)
    {
         SUART.write(myData[i]);
    }
    delay(1000);

}

3. Sketch for MEGA
Try to write something and then we will correct it.

uartNanoMas-Mega.png

Thanks, guys !
I'll try your suggestions ASAP, but for the moment (sadly enough) I have to set my attention to some other things... I'll be back in a few days to report my findings !
Nevertheless : your solutions look promising !! So : thanks again !

Power_Broker:
If you use this serial transfer library, it already incorporates checksums, cyclic redundancy checking, and start/end markers. It is also very fast and reliable.

Here's an example of how to use the library:

TX Arduino:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';
 
  myTransfer.sendData(3);
  delay(100);
}




RX Arduino:


#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

OK. Thanks Power_Broker. I'm gonna try your suggestion first. Few questions :

  • Is there a place where I can find all the keywords and their meaning for SerialTransfer ?
  • I see that you're using "Serial1". As far as I know a Nano only has 1 serial ... ? Does it mean I have to include "SoftwareSerial" ?

Again thanks for your help !

PaulVdB:

  • Is there a place where I can find all the keywords and their meaning for SerialTransfer?

Look in the library's .h. More specifically, look at the public contents of the library's main class as listed in the .h.

Here is what you have available to you: (the example code shows how to use each of these)

  • txBuff
  • rxBuff
  • bytesRead
  • status
  • begin
  • sendData
  • available

PaulVdB:

  • I see that you're using "Serial1". As far as I know a Nano only has 1 serial ... ? Does it mean I have to include "SoftwareSerial"?

It's always best to use hardware serial ports, but if you have to, yes, use softwareserial or another such "bit-banging" library.

OK. Thanks Power_Broker.
Your info was very helpful. I could establish a connection between my Nano and my Mega using following sketches.

Nano

#include "SerialTransfer.h"
SerialTransfer myTransfer;
void setup()
{
  Serial.begin(1200);
 // Serial1.begin(115200);
  myTransfer.begin(Serial);
}
void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';
  
  myTransfer.sendData(3);
  delay(100);
}

As you see I didn't use serial1 because the Nano only has 1 Serial port (0). It implies that I have to disconnect the serial wires while uploading a sketch. Maybe later I'll try to use SoftwareSerial to avoid this.
I lowered the bitrate to 1200 because (for test purposes), I used just simple (unscreened) wires for Rx, Tx and GND and also because speed is not important for me now.

Mega :

#include "SerialTransfer.h"
SerialTransfer myTransfer;

void setup()
{
  Serial.begin(1200);
  Serial3.begin(1200);
  myTransfer.begin(Serial3);
}
void loop()
{
  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
   // Serial.println();
  }
  else
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
  delay(500);
}

The final delay(500) is used to mimic the time that the complete program will need before it gets back to collecting serial data. I used a bitrate of 1200 to print to the Serial Monitor because I've read that using different baud rates on different serials can cause problems.

The result that I see on the Serial monitor (connected to the Mega) is rather weird. It works, but now and then I get error messages... (Same errors when using different baud rates)
Here's what I see on the Serial Monitor of the Mega :

...
New Data
hi
New Data
hi
New Data
hi
New Data
hi
New Data
hi
New Data
hi
ERROR: -1
New Data
hi
ERROR: -1
New Data
hi
New Data
hi
New Data
hi
New Data
hi
New Data
hi
ERROR: 2
ERROR: 2
ERROR: -1
New Data
hi
New Data
hi
New Data
hi
etc ...

Here and there also an ERROR -3 appears ... Maybe the errors appear because the nano is trying to send while the Mega is still reading ? But then why is it always a different error code ?

Anyhow... :slight_smile: I think that (thanks to your info) I am on a good road, but there's still a few "pot holes" ...

So... things BEGIN to work... !!YES!!
Do you have any ideas to smooth out those "pot holes" so that I can go on (and maybe have to ask more questions :slight_smile: )
Again, in advance : I thank you for your "cooperation" :wink:

PS. Nano and Mega are connected to the same PC, but each on their own arduino.exe

Here are what the errors mean:

const int8_t CONTINUE         = 2;
const int8_t NEW_DATA         = 1;
const int8_t NO_DATA          = 0;
const int8_t CHECKSUM_ERROR   = -1;
const int8_t PAYLOAD_ERROR    = -2;
const int8_t STOP_BYTE_ERROR  = -3;

Looks like your packets are getting corrupted from time to time. This is probably due to using such a strange baud. 1200 is VERY, VERY slow and I'm not even sure if it's a stable baud for an MCU with a 16MHz clock.

I think the baud you decided to go with is periodically causing packet corruption.

I also think you should take out the delay() calls - your loop() should never take 500ms to process unless you have a really good reason (in other words: if loop() takes 500ms, you're wrong). The delay(500) might be causing input buffer overflow, which means part of a packet will get dropped, thus causing parsing errors.

My suggestion:
1.) Change your baud to 115200 for all Serial/Serial# class instances
2.) Get rid of the delay(500)

Of course : thanks again ! :slight_smile:
First of all I took out the 500mS delay. For the rest I didn't change anything to the two sketches. But I tested different Baud rates. (I changed every time ALL Baud rates in both sketches to the same number) From the error list you gave me, I conclude that all negatives are bad, all the other error numbers are OK (nothing to worry about).

1200 : mostly "New Data, hi", now and then a burst (7,8 or 9) of Error 2's. After the series of 2's usually a -1

2400 : Many good ones, now and the error 2 or 0

4800 : Many error 0's, very few 2's, some "good ones" (never 2 good ones in a row)

9600 : More error 0's, after a series of 0's : often a 2 and then a good one.
19200 : see 9600
38400, 57600, 74880, 115200 : see 19200.

... the higher the Baud rate, the more 0's in a row, again sometimes followed by a 2 and then a good one. Since 2400 no more negative errors... Using a higher Baud rate DID solve the problem. Thanks !

I think that the error 0 isn't a real error, there's just no Data coming in (100mS delay in the Nano). so that's OK, I can "catch" that in my sketch. I'm a little concerned about error 2 that tells me "continue" ... Continue what ? The negative errors tell me that something went wrong during the transmission. so they're also "catchable". I haven't seen any other error numbers...

So : many of the "pot holes" are getting taken care of ! :slight_smile:
My next challenge is to get the Mega to ASK the Nano for data. (I'll keep you informed :wink: ) Doing this I'll get rid of the many error 0's because I only get data when I ask for it, and my loop in the (receiving) Mega can take as long as it wants to be. Right ?

Here you can find a spreadsheet with (only significant) numbers of my tests : https://paulvdbo.stackstorage.com/s/zNKnCNZteMBHjWR

Again : 1K thanks !
C you later ? :slight_smile:

Yes, in fact, I need to update the example RX code to pass the "errors" CONTINUE and NO_DATA since they aren't really errors at all. CONTINUE means it is currently parsing a packet, but wasn't able to finish just yet. It will continue to finish parsing the packet once myTransfer.available() is called again. This is a good thing, not really an error at all. The errors all have negative values, the non-error statuses are 0 and up.

Try this for RX code:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial3.begin(115200);
  myTransfer.begin(Serial3);
}

void loop()
{
  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

As for the querying, you can have the mega send some characters (could be "hi\n", lol) and if the payload is equal to the predetermined query string, have the nano respond with a packet of queried data.

This library supports full duplex, packets can be sent both ways simultaneously.

Oh yeah !!!

That extra "if(myTransfer.status < 0)" did it ! (As a matter of fact, I was thinking of something like that myself 8) ) NO MORE "errors" :slight_smile:
Now first I'll try to send some "real" data continuously ... and then I'll do the querying thing ... Fingers crossed !

P.S. 10K Thanks !

OK !
These 2 sketches seem to work WONDERFUL !!!

Nano (sender)

#include "SerialTransfer.h"
SerialTransfer myTransfer;
void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}
void loop()
{
  myTransfer.txBuff[0] = analogRead(A0) / 4;
  myTransfer.txBuff[1] = analogRead(A1) / 4;
  myTransfer.txBuff[2] = analogRead(A2) / 4;
  myTransfer.sendData(3);
  delay(100);
}

Mega (receiver)

#include "SerialTransfer.h"
SerialTransfer myTransfer;
byte data[] = {0, 0, 0};
byte bytes;
byte i;
void setup()
{
  Serial.begin(115200);
  Serial3.begin(115200);
  myTransfer.begin(Serial3);
}
void loop()
{
  if (myTransfer.available())
  {
    bytes = myTransfer.bytesRead;
    for (i = 0; i < bytes; i++)
    {
      data[i] = (myTransfer.rxBuff[i]);
      Serial.println (data[i]);
    }
    Serial.println();
  }
  else if (myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

Up to the next step : request & reply...
(Just gimme a few ... ;D )

100K thanks Power_Broker !

Try this for sending integer values:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}

void loop()
{
  uint16_t reading = analogRead(A0);
  myTransfer.txBuff[0] = (reading >> 8) & 0xFF;
  myTransfer.txBuff[1] = reading & 0xFF;

  reading = analogRead(A1);
  myTransfer.txBuff[2] = (reading >> 8) & 0xFF;
  myTransfer.txBuff[3] = reading & 0xFF;

  reading = analogRead(A2);
  myTransfer.txBuff[4] = (reading >> 8) & 0xFF;
  myTransfer.txBuff[5] = reading & 0xFF;
  
  myTransfer.sendData(6);
  delay(100);
}

I'm glad the library is working out for you! :slight_smile:

Power_Broker : You did it again ! :slight_smile:
Works like a charm !!!

//NANO

#include "SerialTransfer.h"
SerialTransfer myTransfer;
int Temp;
int HumAir;
int HumSoil;
void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}
void loop()
{
  Temp = analogRead(A0);
  myTransfer.txBuff[0] = (Temp >> 8) & 0xFF;
  myTransfer.txBuff[1] = Temp & 0xFF;
 
  HumAir = analogRead(A1);  
  myTransfer.txBuff[2] = (HumAir >> 8) & 0xFF;
  myTransfer.txBuff[3] = HumAir & 0xFF;
  
  HumSoil = analogRead(A2);   
  myTransfer.txBuff[4] = (HumSoil >> 8) & 0xFF;
  myTransfer.txBuff[5] = HumSoil & 0xFF;
  
  myTransfer.sendData(6);
  delay(100);
}
//MEGA

#include "SerialTransfer.h"
SerialTransfer myTransfer;
byte data[] = {0, 0, 0, 0, 0, 0};
byte bytes;
byte i;
int Temp;
int HumAir;
int HumSoil;

void setup()
{
  Serial.begin(115200);
  Serial3.begin(115200);
  myTransfer.begin(Serial3);
}
void loop()
{
  if (myTransfer.available())
  {
    bytes = myTransfer.bytesRead;
    for (i = 0; i < bytes; i++)
    {
      data[i] = (myTransfer.rxBuff[i]);
    }
    Temp = (data[0] * 256) + data[1];
    HumAir = (data[2] * 256) + data[3];
    HumSoil = (data[4] * 256) + data[5];
    Serial.print("Temp = ");
    Serial.println(Temp);
    Serial.print("HumA = ");
    Serial.println(HumAir);
    Serial.print("HumS = ");
    Serial.println(HumSoil);
    Serial.println();
  }
  else if (myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

1M thanks !
Now I'll try "Data request and answer" ... I'll keep you informed ! :slight_smile:

P.S. I hope that also others can benefit from this thread. It is SUPER CLEAR !

YES !
request/reply seems to work well with these sketches :

//NANO

#include "SerialTransfer.h"
SerialTransfer myTransfer;
int Temp;
int HumAir;
int HumSoil;
byte rec;
void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}
void loop()
{
  if (myTransfer.available())
  { 
    if (myTransfer.rxBuff[0] == 'X')
    {
      Temp = analogRead(A0);
      myTransfer.txBuff[0] = (Temp >> 8) & 0xFF;
      myTransfer.txBuff[1] = Temp & 0xFF;

      HumAir = analogRead(A1);
      myTransfer.txBuff[2] = (HumAir >> 8) & 0xFF;
      myTransfer.txBuff[3] = HumAir & 0xFF;

      HumSoil = analogRead(A2);
      myTransfer.txBuff[4] = (HumSoil >> 8) & 0xFF;
      myTransfer.txBuff[5] = HumSoil & 0xFF;

      myTransfer.sendData(6);
      delay(100);
    }
  }
}
//MEGA

#include "SerialTransfer.h"
SerialTransfer myTransfer;
byte data[] = {0, 0, 0, 0, 0, 0};
byte bytes;
byte i;
int Temp;
int HumAir;
int HumSoil;

void setup()
{
  Serial.begin(115200);
  Serial3.begin(115200);
  myTransfer.begin(Serial3);
}
void loop()
{
  if (millis() % 5000 == 0)
  {
    myTransfer.txBuff[0] = 'X';
    myTransfer.sendData(1);
    delay(100);
  }
  if (myTransfer.available())
  {
    bytes = myTransfer.bytesRead;
    for (i = 0; i < bytes; i++)
    {
      data[i] = (myTransfer.rxBuff[i]);
    }
    Temp = (data[0] * 256) + data[1];
    HumAir = (data[2] * 256) + data[3];
    HumSoil = (data[4] * 256) + data[5];
    Serial.print("Temp = ");
    Serial.println(Temp);
    Serial.print("HumA = ");
    Serial.println(HumAir);
    Serial.print("HumS = ");
    Serial.println(HumSoil);
    Serial.println();
  }
  else if (myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

My Serial communication problem seems to be solved ! thanks to your super simple/straight- forward library.

Of course I'll have to test in more "real life" circumstances. I'm affraid that the lenght of the communication cable (7-10m) might give problems. If that's the case, I'll try a few options :

  • adding RS485 converters,
  • adding level converters (e.g. 5 to 12?24? volts)
  • and maybe even go wireless.

I guess that your "SerialTransfer.h" library won't have any problems with these converters because they are just kinda "slaves" who only convert the native RS232(5Volt) signals.

One other thing what I'm not sure about : is it possible to use some kinda softwareSerial on the Nano ? (I'm getting tired to plug and unplug the rx/tx wires to upload a new sketch... :roll_eyes: )

Anyhow ... How can I thank you for your time/patience and CLEAR explanations ? (PM me :slight_smile: )

PaulVdB:
My Serial communication problem seems to be solved ! thanks to your super simple/straight- forward library.

Yay! :slight_smile:

PaulVdB:
I guess that your "SerialTransfer.h" library won't have any problems with these converters because they are just kinda "slaves" who only convert the native RS232(5Volt) signals.

Yes, the library works with all UART/USART devices, regardless if they are radios. In fact, I designed the library for me to transfer commands and telemetry wirelessly between [an Arduino hand controller and an Arduino controlled RC plane.

](https://www.youtube.com/watch?v=rPLp50zgQIw)

PaulVdB:
One other thing what I'm not sure about : is it possible to use some kinda softwareSerial on the Nano ? (I'm getting tired to plug and unplug the rx/tx wires to upload a new sketch... :roll_eyes: )

Although it isn't advised, you can use softwareserial on the nano. It's best to use softwareserial for testing (for the reasons you mention), but convert the code to Serial once the rest of the code is complete and polished. Either way, it's your project!

Although it isn't advised, you can use softwareserial on the nano. It's best to use softwareserial for testing (for the reasons you mention), but convert the code to Serial once the rest of the code is complete and polished.

I'll install a (push) button :slight_smile:

an Arduino hand controller and an Arduino controlled RC plane.

: GREAT !!! (I saw the video)
So you send commands to the plane and get back info (e.g. from GPS etc.) ?

Meanwhile, I integrated your communication "system" in my main (still incomplete) MEGA program, and again it works like a charm !

So again : thanks for sharing your knowledge !

PaulVdB:
I'll install a (push) button :slight_smile:

You probably would want to use a triple-pole-double-throw (TPDT) switch instead

PaulVdB:
So you send commands to the plane and get back info (e.g. from GPS etc.) ?

GPS uses it's own packet standard (NMEA sentences), so I created a different library for GPS comms. It's more of the "inter-Arduino" communication that I use the SerialTransfer.h library

PaulVdB:
So again : thanks for sharing your knowledge !

Glad to help!