Go Down

Topic: Arduino to arduino Serial (Read 928 times) previous topic - next topic

PaulVdB

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  :smiley-confuse: )
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 !  :)

mikb55

Are you writing the code for both Ardinos?

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


Robin2

#2
Nov 17, 2019, 11:13 am Last Edit: Nov 17, 2019, 11:14 am by Robin2
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)
Code: [Select]
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
Two or three hours spent thinking and reading documentation solves most programming problems.

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:
Code: [Select]

#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:
Code: [Select]

#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);
  }
}
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

GolamMostafa

#4
Nov 17, 2019, 10:54 pm Last Edit: Nov 19, 2019, 01:21 am by GolamMostafa
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.

Figure-1:

2.  Sketch for NANO
Code: [Select]
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.

PaulVdB

#5
Nov 18, 2019, 11:00 am Last Edit: Nov 18, 2019, 11:01 am by PaulVdB
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 !

PaulVdB

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:
Code: [Select]

#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:
Code: [Select]

#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 !

Power_Broker

- 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



- 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.
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

PaulVdB

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

Nano
-----
Code: [Select]
#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 :
-------
Code: [Select]
#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... :) 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 :) )
Again, in advance : I thank you for your "cooperation"  ;)

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

Power_Broker

#9
Nov 19, 2019, 10:48 pm Last Edit: Nov 19, 2019, 10:50 pm by Power_Broker
Here are what the errors mean:

Code: [Select]

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)
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

PaulVdB

Of course : thanks again ! :)
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 ! :)
My next challenge is to get the Mega to ASK the Nano for data.  (I'll keep you informed ;) ) 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 ? :)




Power_Broker

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:
Code: [Select]

#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.
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

PaulVdB

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" :)
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 !

PaulVdB

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

Nano (sender)
--------------
Code: [Select]
#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)
---------------
Code: [Select]
#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 !

Power_Broker

Try this for sending integer values:

Code: [Select]

#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!  :)
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

Go Up