Problems with data transfer via SPI between two Arduinos

Hello!

I have a problem transferring data via SPI between two Arduinos. I try to send temperature, humidity and current from one Arduino (master) to another Arduino (slave) and display them on an LCD.

#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

#define DHTPIN A1
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#define SS 10

void setup() {
    Serial.begin(9600);
    dht.begin();
    pinMode(SS, OUTPUT);
    digitalWrite(SS, HIGH);
    SPI.begin();
    
}

void sendFloat(float value) {
    byte *data = (byte*)&value;
    for (int i = 0; i < sizeof(float); i++) {
        SPI.transfer(data[i]);
    }
}

void loop() {
    float temperature = dht.readTemperature();
    float humidity = dht.readHumidity();
    float current = analogRead(A0) * (5.0 / 1023.0); // Reading voltage from ACS712

    // Debugging output
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.print(", Humidity: ");
    Serial.print(humidity);
    Serial.print(", Current: ");
    Serial.println(current);

    digitalWrite(SS, LOW);
    delay(10);

    // Transfer each float
    sendFloat(temperature);
    sendFloat(humidity);
    sendFloat(current);

    digitalWrite(SS, HIGH);
    delay(1000);
}


Code slave:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

#define SS 10

void setup() {
    Serial.begin(9600);
    lcd.init();
    lcd.backlight();
    pinMode(SS, INPUT);
    SPI.begin();
}

float receiveFloat() {
    byte data[sizeof(float)];
    for (int i = 0; i < sizeof(float); i++) {
        data[i] = SPI.transfer(0x00);
        delay(1);  // Mică întârziere pentru a stabiliza transferul
    }
    return *(float*)data;
}

void loop() {
    if (digitalRead(SS) == LOW) {
        float temperature = receiveFloat();
        float humidity = receiveFloat();
        float current = receiveFloat();

        // Debugging output
        Serial.print("Received Temperature: ");
        Serial.print(temperature);
        Serial.print(", Humidity: ");
        Serial.print(humidity);
        Serial.print(", Current: ");
        Serial.println(current);

        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("T: ");
        lcd.print(temperature);
        lcd.print(" H: ");
        lcd.print(humidity);

        lcd.setCursor(0, 1);
        lcd.print("C: ");
        lcd.print(current);

        delay(1000);
    }
}

Master Serial monitor:Temperature: 28.00, Humidity: 69.00, Current: 2.49
Temperature: 28.00, Humidity: 69.00, Current: 2.48
Slave serial monitor:Received Temperature: 0.00, Humidity: ovf, Current: 0.00
Received Temperature: nan, Humidity: nan, Current: nan
Received Temperature: 0.00, Humidity: 0.00, Current: 0.00
Basically, in my project I read the data from the 2 sensors using Arduino master, then transmit them through spi to arduino slave which transmits them through i2c to lcd and displays them. What's the problem?

  1. Wiring Issues:
  • Ensure MISO, MOSI, SCK, and SS pins are correctly connected between the master and slave Arduinos.
  • Check for loose connections, as they can cause intermittent communication problems.
  1. SPI Modes and Clock Settings:
  • Both Arduinos must use the same SPI mode (combination of clock polarity and phase).
  • Ensure the SPI clock speed is not too high for the slave to handle, which can cause data errors.

for spi i have cinectated pins 13,12,11,10 of arduino connected between master and slave
I tink the code is problem .

how to check these things?
"Spi modes and clock settings.

And a ground wire?

Ground wire is not conected between master and slave

Ground wire is not conected between master and slave

It won't work unless it is!

I mention that the 2 arduinos are powered separately from the laptop with a USB cable for each

Won't work without a ground connection!

for the parasitic characters that appear on the LCD, I should connect two resistors to the sda ​​and scl pins of the i2c, I suspect. Regarding the power supply, if I also connect ground to ground between master and slave, it will be necessary to power both Arduinos with a USB cable or will it be enough to feed only one of the 2 arduino?

If the LCD does not have pull-up then yes you need to connect a 4.7K resistor between SCl and Vcc and SDA and Vcc.

it will be necessary to power both Arduinos with a USB cable

Yes, both arduinos need power. The ground wire is for the SPI signals not power

I understand, thanks for the advice.
I think there is a problem in the slave code as well considering what is displayed on the slave serial monitor. I think the master code is fine considering what it transmits through the serial monitor. In the slave code I think the problem would be in the way the slave receives the data from the master via spi and how it transfers it to the lcd via i2c.

I also connected the master to the slave and for nothing on the display I still see 0 for the 3 parameters, what could I do?
makes me think that the slave code is to blame

Try this for the slave

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define SS 10

void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(SS, INPUT_PULLUP);
  pinMode(SCK, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(MISO, OUTPUT);
  SPCR = (1 << SPE); // Enable SPI slave
}

float receiveFloat() {
  byte data[sizeof(float)];
  while (!(SPSR & (1 << SPIF))) // Wait for reception complete
    data[0] = SPDR;
  while (!(SPSR & (1 << SPIF)))
    data[1] = SPDR;
  while (!(SPSR & (1 << SPIF)))
    data[2] = SPDR;
  while (!(SPSR & (1 << SPIF)))
    data[3] = SPDR;
  return *(float*)data;
}

void loop()
{
  while (digitalRead(SS)) delay(1); // Wait for SS to go LOW

  float temperature = receiveFloat();
  float humidity = receiveFloat();
  float current = receiveFloat();

  // Debugging output
  Serial.print("Received Temperature: ");
  Serial.print(temperature);
  Serial.print(", Humidity: ");
  Serial.print(humidity);
  Serial.print(", Current: ");
  Serial.println(current);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("T: ");
  lcd.print(temperature);
  lcd.print(" H: ");
  lcd.print(humidity);

  lcd.setCursor(0, 1);
  lcd.print("C: ");
  lcd.print(current);

  while (!digitalRead(SS)) delay(1); // wait for SS to go HIGH

}

With this slave code on serial monitor I display:Received Temperature: 0.00, Humidity: 0.00, Current: 0.00
Received Temperature: 0.00, Humidity: 0.00, Current: 0.00
On the LCD displays all 3 parameters with value 0

For debugging try this for the master
The Slave Arduino MUST be started before the Master


#include <SPI.h>
//#include <Adafruit_Sensor.h>
//#include <DHT.h>

//#define DHTPIN A1
//#define DHTTYPE DHT11
//DHT dht(DHTPIN, DHTTYPE);

#define SS 10

void setup() {
  Serial.begin(9600);
  //dht.begin();
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);
  SPI.begin();
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
}

void sendFloat(float value) {
  byte *data = (byte*)&value;
  for (int i = 0; i < sizeof(float); i++) {
    SPI.transfer(data[i]);
  }
}

void loop() {
  float temperature = 25.6;
  float humidity = 69.5;
  float current = 512.0;

  // Debugging output
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(", Humidity: ");
  Serial.print(humidity);
  Serial.print(", Current: ");
  Serial.println(current);

  digitalWrite(SS, LOW);
  delay(5);

  // Transfer each float
  sendFloat(temperature);
  delay(1);
  sendFloat(humidity);
  delay(1);
  sendFloat(current);
  delay(1);

  digitalWrite(SS, HIGH);
  delay(1000);
}

I solved, thanks a lot, what other components could I add to the project to make it more complex?

Why do you want to make it more complex?

because this practical part will be part of a diploma thesis that should highlight the study and the way serial communication interfaces work
.I think the practical realization is a bit simplistic, in essence I only have 2 Arduinos, an LCD, i2c, spi, acs712 and dht11, but it should be more complex.

Try the following sketches (compiled and NOT tested) which are made based on post #69 @J-M-L of this thread. You may ask any question relating to these sketches and SPI Protocol.

Master Sketch:

// SENDER CODE
#include <SPI.h>
#include <DHT.h>
#include <Adafruit_Sensor.h>

#define DHTPIN A1
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

struct __attribute__((packed, aligned(1))) myData
{
  float temperature;
  float humidity;
  float current;
};

myData data;

const byte syncHeader[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Synchronization header

byte *dataPtr = (byte*)&data;

void setup()
{
  pinMode(SS, OUTPUT);
  Serial.begin(115200);
  SPI.begin();
  digitalWrite(SS, LOW);  // enable Slave Select
}

void loop()
{
  for (int i = 0; i < sizeof syncHeader; i++)
  {
    SPI.transfer(syncHeader[i]);
    delayMicroseconds(1000); // adjust time against the time the ISR needs on the other side to process the byte
  }
  data.temperature = dht.readTemperature();
  data.humidity = dht.readHumidity();
  data.current = analogRead(A0) * (5.0 / 1023.0);

  // Send sensor data
  for (int i = 0; i < sizeof(data); i++)
  {
    SPI.transfer(dataPtr[i]);
    delayMicroseconds(1000); // adjust time against the time the ISR needs on the other side to process the byte
  }
  delay(1000);
}

Slave Sketch:

// RECEIVER CODE
#include <SPI.h>

struct __attribute__((packed, aligned(1))) myData
{
  float temperature;
  float humidity;
  float current;
};

myData data;

const byte syncHeader[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Synchronization header

byte *dataPtr = (byte*)&data;

volatile bool dataIsReady = false;

void setup()
{
  pinMode(SS, INPUT_PULLUP);  // EDIT ==> start with SS HIGH (see discussion further)
  pinMode(MISO, OUTPUT);      // pin on which to send info out
  Serial.begin(115200);
  SPCR |= bit(SPE);  // turn on SPI in slave mode
  SPI.attachInterrupt();
}

void loop() 
{
  if (dataIsReady)
  {
    // critical section
    noInterrupts();
    myData dataCopy = data;
    dataIsReady = false;
    interrupts();
    // end of critical section

    // Debugging output
    Serial.print("Received Temperature: ");
    Serial.println(dataCopy.temperature);
    //-------------------------------
    Serial.print("Received Humidity: ");
    Serial.print(dataCopy.humidity);
    //----------------------------------
    Serial.print("Received Current: ");
    Serial.println(dataCopy.current);
  }
}

// SPI interrupt routine
ISR(SPI_STC_vect)
{
  static const uint8_t syncHeader[] = { 0xDE, 0xAD, 0xBE, 0xEF };  // Synchronization header
  static int syncPos = 0;
  static int pos = 0;

  uint8_t receivedByte = SPDR;

  if (syncPos < sizeof syncHeader)
  {
    if (receivedByte == syncHeader[syncPos])
    {
      syncPos++;
    }
    else
    {
      syncPos = 0;
    }
  }
  else
  {
    dataPtr[pos++] = receivedByte;
    if (pos >= sizeof(data))
    {
      pos = 0;
      syncPos = 0;
      dataIsReady = true;
    }
  }
}