Communicating 2 Arduinos Nano

hey guys

I need to communicate 2 Arduinos Nano and I’m currently with idea of using Tx/Rx method via SoftwareSerial. I have already coded some lines, but it hasn’t produced a good result so far. Here are my codes:
Sender -

void sendData(){
  mySerial.write(delayPeriod);

void receivedData(){
   if(Serial.available() > 0) {

    char x = Serial.read();

      // the order of these IF clauses is significant
      
    if (x == endMarker) {
      readInProgress = false;
      newDataFromPC = true;
      inputBuffer[bytesRecvd] = 0;
      parseData();
    }
    
    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd ++;
      if (bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if (x == startMarker) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }
  }
  
}

void parseData() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(inputBuffer,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  delayPeriod = atoi(strtokIndx);     // convert this part to an integer

}

Receiver

char send2Ard[40];
uint16_t delayPeriod;  

void receivedData(){
   if(mySerial.available() > 0) {
      mySerial.readBytes(send2Ard,6);
      delayPeriod = atoi(send2Ard);
  }
  
}

My question is regarding how to transfer the value that it is coming from the Serial USB (delayPeriod) to the second Arduino. The incoming data from Python is like testData.append(’<DELAY,4692,>’), where the number represents my delayPeriod.

Code incomplete

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

…R

@OP

Let us acquire some basic learning (with the help of the following diagram) on Serial Communication between two Arduino before we sit to write programs for the Sender (UNO/NANO) and Receiver NANO. (It is really hard for me to study the codes that you have posted, and then show you the directions of change/modifications.)
uart-9.png
Figure-1: Connection diagram between UNO and NANO using Software UART Ports

Let us see how the character/digit 5 (entered from the InputBox of Serial Monitor-1(UNO) appears in the OutputBox of the Serial Monitor-2 (NANO).

1. Let us connect UNO/NANO (the Sender) and NANO (the Receiver) as per Fig-1. Connect both Arduino with the PC using the respective connecting cables.

2. Upload the following sketch into the Sender Arduino.

#include<SoftwareSerial.h>
SoftwareSerial SUART(2, 3); //DPin-2 = SRX; DPin-3 = STX
void setup()
{
  Serial.begin(9600); //bit transfer rate (Bd) between PC and UNO
  SUART.begin(9600); //Bd (Baud Rate) between UNO and NANO
}

void loop()
{
  byte n = Serial.available(); //checking if FIFO has data
  if (n != 0 )
  {
    byte x = Serial.read();    //gettiing data byte from FIFO
    Serial.write(x);   //5 appears on SM-1
    SUART.write(x);    //ASCII Code is written to SUART Port
  }
}

3. Upload the following sketch into Arduno NANO

#include<SoftwareSerial.h>
SoftwareSerial SUART(2,3); //DPin-2 = SRX; DPin-3 = STX

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte n = SUART.available(); //checking if FIFO has data
  if (n != 0 )
  {
    byte x = SUART.read(); //getting data byte from FIFO
    Serial.write(x);  //5 appears on SM-2
  }
}

4. Open SM-1 and SM-2. Disable Line ending tab in both SM (Serial Monitor).

5. Enter 5 in the InputBox of SM-1 and click on the Send Button.

6. Check that the character 5 has appeared on the OutputBox of SM-2.

7. Accept the above two sketches as the 'Building Blocks', and now add codes to transfer your name or another complex data to NANO.

8 Theory of Serial Communication using UART Ports
Could be included/described on demand.

uart-9.png

Thank you all for the replies.

I took both examples as ideas and I tried a different code, but it seems like the message is not being sent from Ard1 to Ard2.

Below you can find the sketches for sender and receiver, respectively:

void loop() {
 
 receivedData();
 replyToPC();

}
 

void receivedData(){
   if(Serial.available() > 0) {

       char x = Serial.read();
       testSerial.print('x');

      // the order of these IF clauses is significant
      
    if (x == endMarker) {
      readInProgress = false;
      newDataFromPC = true;
      inputBuffer[bytesRecvd] = 0;
      parseData();
    }
    
    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd ++;
      if (bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if (x == startMarker) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }

   
    
  }

  
  
}

void parseData() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(inputBuffer,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  delayPeriod = atoi(strtokIndx);     // convert this part to an integer



}
void loop() {
 
 receivedData();
 replyToPC();

}
 

void receivedData(){
 if(testSerial.available() > 0) {

    char x = testSerial.read();

      // the order of these IF clauses is significant
      
    if (x == endMarker) {
      readInProgress = false;
      newDataFromPC = true;
      inputBuffer[bytesRecvd] = 0;
      testSerial.print(inputBuffer);
      parseData();
      
    }
    
    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd ++;
      if (bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if (x == startMarker) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }

  }

  
  
}

void parseData() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(inputBuffer,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  
  strtokIndx = strtok(NULL,","); // this continues where the previous call left off
  delayPeriod = atoi(strtokIndx);     // convert this part to an integer

}

Type of message from Python: <DELAY,12500,>

The idea is to receive every single char and store it into an array inputBuff. After > is recognized, a function called parseData() is called to parse the content and the important part of it consists of the int value(e.g 12500) which is assigned to delayPeriod (declared as uint16_t)

Crespo94: I took both examples as ideas and I tried a different code,

Have you tried the examples in my Tutorial without ANY changes other than those necessary to use SoftwareSerial?

If you have, and they did not work then please post the pair of programs that you uploaded to your Arduino and an example of the output from each of them.

...R

Hi Robin, now it is all going well! I could manage the communication.

I know that it’s not related to this thread but regarding timer1 prescaler: I’m using prescaler equals to 1024 and I notice that when I set the delay less than 150ms(<2346 - based on 16MHz/(1024*f)), the count becomes strange. I feel that because of the calculation speed of timer1, it’s unable to deal with small values. Do you know how could I handle that?

Entire code

//Sender Ard1

#include "Arduino.h"
#include <SoftwareSerial.h>

SoftwareSerial testSerial (5,6);


const int16_t pulseWidth = 1 ;      //(16MHz/(PSC*f) -> 10:50us with PSC = 64    3:50us with PSC = 256   1:64us with PSC = 1024
const uint8_t logFifoSize = 3;
const uint8_t fifoSize = 1 << logFifoSize;
const uint8_t fifoMask = fifoSize - 1;
const uint8_t ICP = 8;      // Input capture pin

volatile uint16_t fifo[fifoSize];
//volatile uint16_t delayPeriod = 25000;// delayPeriod = 16MHz/(PSC*f) -> 400ms with PSC = 256

uint16_t delayPeriod;         // delayMax: PSC(64)=260ms, jitter max 4us  PSC(256) = 1052ms, jitter max 20us  PSC(1024) = > 150ms until 4166ms, jitter max 100us

volatile uint8_t writeHead = 0;
volatile uint8_t readHead = 0;
volatile bool waitingForRising = false;
volatile bool waitingForFalling = false;

const byte buffSize = 40;
char inputBuffer[buffSize];
const char startMarker = '<';
const char endMarker = '>';
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newDataFromPC = false;
char messageFromPC[buffSize] = {0};



void setup() {
  pinMode(ICP, INPUT);
  TCCR1B = (1 << ICES1);    // Stop counter, waveform generator Mode 0, capture input on rising edge of ICP
  TCCR1A = 0;         // waveform generator Mode 0
  TCNT1 = 0;          // reset counter
  OCR1A = 0xFFFF;       // park output compare value here for now
  TCCR1A = (1 << COM1A1);   // OC1A low on A-match, waveform generator Mode 0
  TCCR1C = (1 << FOC1A);    // Force A-match, OC1A Low
  TCCR1A = 0;         // disconnect OC1A
  PORTB &= ~(1 << PB1);   // PB1 (Pin 9) to 0 when switched to output
  DDRB |= (1 << DDB1);    // PB1 (Pin 9) as output
  TIMSK1 = (1 << ICIE1);    // interrupt on input capture
  TCCR1B |= (1 << CS10) | (1 << CS12); // Start counter PSC = 1024
//TCCR1B |= (1 << CS10) | (1 << CS11);  // Start counter PSC = 64
//TCCR1B |= (1 << CS12); // Start counter PSC = 256
  Serial.begin(57600);
  testSerial.begin(57600);
  // tell the PC we are ready
  Serial.println("<Arduino is ready>");
}

void loop() {
 
 receivedData();
 replyToPC();

}
 

void receivedData(){
   if(Serial.available() > 0) {

       char x = Serial.read();
       testSerial.write(x);

      // the order of these IF clauses is significant
      
    if (x == endMarker) {
      readInProgress = false;
      newDataFromPC = true;
      inputBuffer[bytesRecvd] = 0;
      parseData();
    }
    
    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd ++;
      if (bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if (x == startMarker) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }

   
    
  }

  
  
}

void parseData() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(inputBuffer,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  delayPeriod = atoi(strtokIndx);     // convert this part to an integer



}

void replyToPC() {

  if (newDataFromPC) {
    newDataFromPC = false;
    Serial.print("Delay");
    Serial.print(messageFromPC);
    Serial.print(" Value ");
    Serial.print(delayPeriod);
  }
}

ISR(TIMER1_CAPT_vect) {
  bool fifoEmpty = false;
  uint16_t timeStamp = ICR1;
  uint16_t risingEdgeTime = timeStamp + delayPeriod;  // counter value for rising edge
  if ((readHead == writeHead) && !waitingForRising && !waitingForFalling) { // same values at the same position and bool variables are false
    fifoEmpty = true;
  }
  fifo[writeHead++] = risingEdgeTime; //write to FiFo - FIRST IN
  writeHead &= fifoMask; // writeHead = writeHead & fifoMask
  if (fifoEmpty) {
    readHead = writeHead;            // read from Fifo - FIRST OUT
    OCR1A = risingEdgeTime;          // set next compare time
    TIMSK1 |= (1 << OCIE1A);         // Enable interrupt on match
    TCCR1A = (1 << COM1A1) | (1 << COM1A0); // OC1A high on A-match
    waitingForRising = true;
    waitingForFalling = false;
  }
}

ISR(TIMER1_COMPA_vect) {
  if (waitingForRising) { //reaches OCR1A = risingEdgeTime
    OCR1A += pulseWidth;    // set time for output to go low
    TCCR1A = (1 << COM1A1);   // OC1A low on A-match
    waitingForRising = false;
    waitingForFalling = true;
    return;
  }

  if (waitingForFalling) { //reaches OCR1A += pulseWidth
    if (readHead == writeHead) {
      // FIFO is empty
      TIMSK1 &= ~(1 << OCIE1A); // disable interrupt on match
      TCCR1A = 0;              // disconnect OC1A
      waitingForFalling = false;
      waitingForRising = false;
      return;
    }

    // still events left in FIFO
    waitingForRising = true;
    waitingForFalling = false;
    OCR1A = fifo[readHead++];
    readHead &= fifoMask;
    TCCR1A = (1 << COM1A1) | (1 << COM1A0); // OC1A high on A-match
  }
}

Crespo94: Do you know how could I handle that?

No.

Assuming this Timer problem has nothing to do with serial communication I suggest you start a new Topic with a suitable title.

...R