Send Strings via SPI both ways using two Arduino UNOs

I need to create a two way String exchanger via SPI with two Arduino UNOs. Strings and their lengths are independent variables of the main loop and they can change with every iteration. I need both of the Arduinos to communicate with each other regardless of what the strings contain. I want to see basically the same screen with the serial monitor.

It is kind of working. I am not sure how to explain it, I'll just show it below.

Basically the main idea for both of the Arduino's is like this:

Master: hey
Slave: hi

Instead I get this on the master:

Slave: 
Slave: 
Master: hey
Slave: y
Slave: 
Slave: 
.
.
.
Slave: i
Slave: 
Slave: 
.
.

And the slave displays only itself:

Slave: hi

I have created for loops to transfer every char of the string seperately and respectively but this is still the case. I couldn't find any sample code online for independent strings transfering via SPI. I know I probably have many mistakes but how can I fix them to work just as I intend to?


Connections:

Arduino1.pin13 --- Arduino2.pin13

Arduino1.pin12 --- Arduino2.pin12

Arduino1.pin11 --- Arduino2.pin11

Arduino1.pin10 --- Arduino2.pin10


Master Code

//MASTER

#include<SPI.h>

String textSend="", textReceive="";

void setup(){

  Serial.begin(115200);

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);    //Sets clock for SPI communication at 8 (16/8=2Mhz)
  digitalWrite(SS,LOW);
}

void loop(){

  textSend=""; textReceive="";
  textSend = Serial.readString();
  if(textSend != ""){
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds (20);
      SPI.transfer(textSend[i]);
    }

    Serial.print ("Master: ");
    Serial.println (textSend);
  }else{
    int i = 0;
    char c;
    do{
      delayMicroseconds (20);
      c = SPI.transfer(1);
      textReceive += c;
      i++;
    }while(textReceive[i] != 0);

    if(textReceive[i] == 0){
      Serial.print ("Slave: ");
      Serial.println (textReceive);
      textReceive = "";
    }
  }
}

Slave Code

//SLAVE

#include<SPI.h>

String textSend="";
String textReceive="";

void setup (void){
  Serial.begin(115200);
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
  SPI.attachInterrupt();

}

ISR (SPI_STC_vect){ //Interrupt Service Routine

  byte c = SPDR;

  if(c != 1){ //Slave receives
    for(int i = 0; i < textReceive.length(); i++){
      textReceive += SPDR;
    }
    if(textReceive.length() > 0){
      Serial.print("Master: ");
      Serial.println(textReceive);
      textReceive = "";
    }
  }else{
    for(int i = 0; i < textSend.length(); i++){
      delayMicroseconds(20);
      SPDR = textSend[i];
    }
    if(textSend != ""){
      Serial.print("Slave: ");
      Serial.println(textSend);
      textSend = "";
    }
  }
}

void loop() {
  if(textSend == "")
    textSend = Serial.readString();


}

PS: I am using different computers for each arduino

Master.ino (1.11 KB)

Slave.ino (836 Bytes)

This is how I manage to send string data (Arduino!) from Master SPI UNO to Slave SPI NANO.

1. The connection diagram
spi328z.png

2. Master SPI UNO codes:

#include<SPI.h>
char txMsg[] = "Arduino!";
char rxMasg[20] = "";

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV128); //16 MHz/128
  pinMode(SS, OUTPUT);    //SS is DPin-10
  digitalWrite(SS, LOW);   //Slave is selected
}

void loop()
{
  SPI.transfer('<'); //start mark
  for(int i=0; i< sizeof(txMsg); i++)
  {
    SPI.transfer(txMsg[i]);//SPI transfer is byte-by-byte
  }
  SPI.transfer('>');  //end mark 
  //---------------------------------------------------
  delay(1000);         //test interval
}

3. Slave SPI NANO codes:

#include<SPI.h>
char rxMsg[20] = "";
volatile bool flag1 = false;
bool flag2 = false;
int i = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(SS, INPUT_PULLUP);  //SPI.h helps to get the meaning of SS
  pinMode(MOSI, OUTPUT);      //should be made output to send data to Master
  SPCR |= _BV(SPE);         //SPI Port is enabled
  SPI.attachInterrupt();    //SPI interrupt is enabled
}

void loop()
{
  if (flag1 == true)  //SPDR has data
  {
    if (flag2 == false) //start mark of message not yet received
    {
      char q = SPDR;
      if (q == '<')
      {
        flag2 = true;   //start mark is detected
        flag1 = false;  //must be made false for the next cycle
      }
    }
    else
    {
      if (SPDR == '>')  //checking if end mark has arived
      {
        flag1 = false;
        flag2 = false;
        i = 0;
        Serial.print(rxMsg);  //end mark has arrived; show the received message
        Serial.println();     //insert newline
      }
      else
      {
        rxMsg[i] = SPDR;    //save received charcater/data byte in array
        i++;                //adjust array pointer
        flag1 = false;      //must be false for next cycle
      }
    }
  }
}


ISR (SPI_STC_vect)   //MCU comes here when there is a data byte in SPDR
{
  flag1 = true;   //flag to indicate there is data in the SPDR register
}

4. Slave's Serial Monitor
spi328zSM.png

5. Let us add codes with the sketches of Master and Slave so that the Master can collect/recievs the string Forum! from the Slave.

spi328z.png

spi328zSM.png

2 Likes

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R