Sending more than one integer between 2 Arduinos via the same serial channel

Hi all,

I know this has been covered a few times but I'm struggling to find a best practice as it seems to work a few different ways...

I'm hoping to send up to 4 numbers between a pair of arduinos, the numbers will be the following size:

Speed = 999
RPM = 9999
Temperature = 99
Fuel = 999

Is there a best way to do this with minimal holdups in the code?

Thanks!

I don’t think there’s a single best method - you may need to consider the consequences of not receiving a value correctly, or it may not matter.
You’ll have to label the values somehow.

The usual way is to send a non-digit character first, to enable the two Arduino to synchronise. Then you can send the 4 numbers, perhaps with commas or spaces between them, then some final non-digit character to indicate the end of the message.

To avoid holdups, just use Serial.available() to check there is something to read before using Serial.read(). While waiting for the synchronisation character, just check Serial.available() > 0. If so, read a character. If it’s not the sync character, ignore it. If it is the sync character, you can go ahead and read the rest of the message.

So for example the message might look like

<999,9999,99,999>

Thanks guys, that makes sense... What though is the best way to determine the length of each integer... I guess it could change if the number goes from 2 to 100 or something like that...?

what’s the reason? why do you want to have “the length” of an integer?

by the way,
I suggest to transmit each value separetly with an indicator, ending with an linefeed:
S999
R9999
T99
F99

just parse the integer value beginning with readed[1] whereof readed[0] gives you what the other arduino has sent.

Thanks I have done something similar using commas, but I'm struggling to create the message on the write end... This is what I tried but it doesn't work...

Char Serial_Message;

Serial_Message = SPEED_MPH & ", " & RPM & ", 45, 37";

Any ideas?

Error "invalid operands of types 'int' and 'const char [3]' to binary 'operator&'"

why the usage of a buffer? Just print what you have...

const char delimiter=',';

Serial.print(SPEED_MPH);
Serial.print(delimiter);
Serial.print(RPM);
Serial.println(); // End of line

and by the way, a char holds one character ... not a string.

So I’m using the guide which requires a start and finish marker so I think this is what I need but it doesn’t seem to work… I feel like I’m close!

Serial1.print(’<’);
Serial1.print(SPEED_MPH);
Serial1.print(delimiter);
Serial1.print(RPM);
Serial1.print(delimiter);
Serial1.print(‘45’);
Serial1.print(delimiter);
Serial1.print(‘37’);
Serial1.print(’>’);
Serial1.println();
Serial1.write;

what is the reason for the last write/what do you expect that this write should do?
what error message do you get, if any?
what do you see on your output connected to another Serial Monitor?

it doesn't seem to work

Please post a complete program that transmits the data and a complete program that reads the data and explain what is wrong

You should get warnings like

C:\Users\sterretje\AppData\Local\Temp\arduino_modified_sketch_787493\sketch_jan26a.ino:2:16: warning: multi-character character constant [-Wmultichar]

   Serial.print('45');

If not, go to file -> preferences and set "Compiler warnings" to ALL.

What are the characters that you want to send? A dash and a percentage? Or the text 45 and 37?

1 Like

UKHeliBob:
Please post a complete program that transmits the data and a complete program that reads the data and explain what is wrong

Ok so my transmitter code is:

#include <AccelStepper.h>

// Define some steppers and the pins the will use
AccelStepper stepper1(AccelStepper::DRIVER, 5, 6); //Step, Direction
AccelStepper stepper2(AccelStepper::DRIVER, 7, 8); //Step, Direction
const int RESET = 18; // pin for RESET
int SPEED_Pin = 22;
int SPEED_Val=0;
int RPM_Pin = 20;
int RPM_Val;
int SPEED_STEPS;
int RPM_STEPS;

const int numReadings = 50;
int SPEED_readings[numReadings];      // the readings from the analog input
int SPEED_readIndex = 0;              // the index of the current reading
int SPEED_total = 0;                  // the running total
int SPEED_average = 0;                // the average
int SPEED_MPH = 0;

int RPM_readings[numReadings];      // the readings from the analog input
int RPM_readIndex = 0;              // the index of the current reading
int RPM_total = 0;                  // the running total
int RPM_average = 0;                // the average
int RPM = 0;

unsigned long startMillis;  
unsigned long currentMillis;
const unsigned long period = 100; 

const byte delimiter=',';

void setup()
{  
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH); 
    for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    SPEED_readings[thisReading] = 0;
    RPM_readings[thisReading] = 0;
    }
    
    stepper1.setMaxSpeed(10000.0);
    stepper1.setAcceleration(250000.0);
    stepper2.setMaxSpeed(10000.0);
    stepper2.setAcceleration(250000.0);
    
    stepper1.runToNewPosition(3780);
    stepper1.runToNewPosition(0);

    stepper2.runToNewPosition(-3780);
    stepper2.runToNewPosition(0);

    startMillis = millis();  //initial start time
}

void loop(){

//=====SPEED CALC=============  
  // subtract the last reading:
  SPEED_total = SPEED_total - SPEED_readings[SPEED_readIndex];
  // read from the sensor:
  SPEED_Val = map(analogRead(SPEED_Pin), 0, 1023, 0, 3780);  //scal val2 (kph) to stepper motor positions
  
  SPEED_readings[SPEED_readIndex] =SPEED_Val;
  SPEED_total = SPEED_total + SPEED_readings[SPEED_readIndex];
  SPEED_readIndex = SPEED_readIndex + 1;
  if (SPEED_readIndex >= numReadings) {
    SPEED_readIndex = 0;
  }

  // calculate the average:
  SPEED_STEPS = SPEED_total / numReadings;     //10*(((total / numReadings)+5)/10);
  SPEED_MPH = SPEED_STEPS/18.9;
  //Serial1.write(SPEED_MPH);

  //=====RPM CALC=============  
  // subtract the last reading:
  RPM_total = RPM_total - RPM_readings[RPM_readIndex];
  // read from the sensor:
  RPM_Val = map(analogRead(RPM_Pin), 0, 1023, 0, -3780);  //scal val2 (kph) to stepper motor positions
  
  RPM_readings[RPM_readIndex] =RPM_Val;
  RPM_total = RPM_total + RPM_readings[RPM_readIndex];
  RPM_readIndex = RPM_readIndex + 1;
  if (RPM_readIndex >= numReadings) {
    RPM_readIndex = 0;
  }

  // calculate the average:
  RPM_STEPS = RPM_total / numReadings;
  RPM = RPM_STEPS/18.9;
  
  
 //============================= 
  currentMillis = millis();
  if (currentMillis - startMillis >= period) 
  {
    Serial1.print('<');
    Serial1.print(SPEED_MPH);
    Serial1.print(delimiter);
    Serial1.print(RPM);
    Serial1.print(delimiter);
    Serial1.print('45');
    Serial1.print(delimiter);
    Serial1.print('37');
    Serial1.print('>');
    //Serial1.println();
    startMillis = currentMillis;
  }

  //=============================
  
    stepper1.moveTo(SPEED_STEPS);
    stepper2.moveTo(RPM_STEPS);
    stepper1.run();
    stepper2.run();
}

The receiver code is:

#include <EEPROM.h>
#include <Bounce2.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>

//---INITIALISE OLED------------------------------------------------
#define OLED_RESET  -1
Adafruit_SSD1306 display(128,32,&Wire, OLED_RESET);
//---END INITIALISE OLED------------------------------------------------

//Serial
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

int SPEED_MPH;
int RPM;
int WATER_TEMP;
int COOLANT_TEMP;

void setup(void) {
    
   Serial.begin(250000);
   Serial1.begin(250000);
   loadEEPROMSettings();
   Wire.setClock(3400000);
   

/
//-----------INITIATE SCREEN----------------------------------------------
  Serial.println("Starting OLED");
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  }

void loop(void) {

//=========READ SERIAL=========
  Get_Serial_Data();
  Parse_Serial_Data();
 
}


//-----------------------Receive Serial Data--------------------------------------------------------
void Get_Serial_Data() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
 // if (Serial.available() > 0) {
    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;
        }
    }
}

//--------------Parse Data from Serial----------------
void Parse_Serial_Data() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(receivedChars,",");
  SPEED_MPH = atoi(strtokIndx);
  
  strtokIndx = strtok(NULL, ",");
  RPM = atoi(strtokIndx);    
  
  strtokIndx = strtok(NULL, ",");
  COOLANT_TEMP = atoi(strtokIndx);

  strtokIndx = strtok(NULL, ",");
  FUEL_LEVEL = atoi(strtokIndx);

}

I removed the code for showing the data on the screen to make it simpler to read, but there is additional code that does the displaying of the data.

1 Like
 Serial1.print('45');

Single quotes are used around a single char, double quotes around constant strings

Just out of interest, try this

void setup() 
{
  Serial.begin(115200);
  while(!Serial);
  Serial.println('45');
}

void loop() 
{
}

What do you want to see in the Serial monitor ?
What do you actually see in the Serial monitor ?

UKHeliBob:

 Serial1.print('45');

Single quotes are used around a single char, double quotes around constant strings

Just out of interest, try this

void setup() 

{
  Serial.begin(115200);
  while(!Serial);
  Serial.println('45');
}

void loop()
{
}



What do you want to see in the Serial monitor ?
What do you actually see in the Serial monitor ?

See reply #10 as well :wink:

A basic concept to remember is to send the data in a format/manner that is easy to parse on the receiving end. The data packet can contain start markers, end markers, and data delimiters. They can be used as necessary just depending on the data being sent and the timing of the sending.

sterretje:
You should get warnings like

C:\Users\sterretje\AppData\Local\Temp\arduino_modified_sketch_787493\sketch_jan26a.ino:2:16: warning: multi-character character constant [-Wmultichar]

Serial.print(‘45’);



If not, go to file -> preferences and set "Compiler warnings" to ALL.

What are the characters that you want to send? A dash and a percentage? Or the text 45 and 37?

Hey sorry I have now set this option and got the monitor working correctly. I followed Bob’s advice and changed to double quotes and now if I run the following code on the transmitter:

Serial.print(’<’);
Serial.print(SPEED_MPH);
Serial.print(’,’);
Serial.print(RPM);
Serial.print(’,’);
Serial.print(“45”);
Serial.print(’,’);
Serial.print(“37”);
Serial.print(’>’);

I get a stream of:

<19,0,45,37>

Which is absolutely correct, so I will now change “Serial.print” to Serial1.print to transmit. So the transmitter is working. Just need to work out the receiver now!

EDIT: I am now reading the following on the receiver:

�������<0,0,45,37>������������������������������������������������������������������������������������<0,0,45,37>����

What’s with the blank characters in between messages? I’m not sending anything else??

450nick:
Hey sorry I have now set this option and got the monitor working correctly. I followed Bob’s advice and changed to double quotes and now if I run the following code on the transmitter:

Serial.print(’<’);
Serial.print(SPEED_MPH);
Serial.print(’,’);
Serial.print(RPM);
Serial.print(’,’);
Serial.print(“45”);
Serial.print(’,’);
Serial.print(“37”);
Serial.print(’>’);

I get a stream of:

<19,0,45,37>

Which is absolutely correct, so I will now change “Serial.print” to Serial1.print to transmit. So the transmitter is working. Just need to work out the receiver now!

EDIT: I am now reading the following on the receiver:

�������<0,0,45,37>������������������������������������������������������������������������������������<0,0,45,37>����

What’s with the blank characters in between messages? I’m not sending anything else??

You may not be sending them, but are you reading them?

"What's with the blank characters in between messages? I'm not sending anything else??"

Is your sending code sending something when you are not intending it to?

More likely the receiving code is reading stuff when it shouldn’t…

Ah no I'm reading blanks I see... Doh!

Ok so I have the correct data coming in... And it appears that MPH is coming through correctly but the other 3 numbers are not coming through. So it must be an issue with the data parsing code... Anyone spot it?

//-----------------------Receive Serial Data--------------------------------------------------------
void Get_Serial_Data() {
   //inChar = Serial1.read();
    
  if (Serial1.available() > 0) {
    //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;
        }
    }
}

//--------------Parse Data from Serial----------------
void Parse_Serial_Data() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(receivedChars,",");      // get the first part - the string
  SPEED_MPH = atoi(strtokIndx);
         Serial.print(strtokIndx); 
  strtokIndx = strtok(NULL, ",");
  RPM = atoi(strtokIndx);
  
  strtokIndx = strtok(NULL, ",");
  COOLANT_TEMP = atoi(strtokIndx);

  strtokIndx = strtok(NULL, ",");
  FUEL_LEVEL = atoi(strtokIndx);

}