Issue sending float between 2 Arduinos over SPI

Hi,

I am building a system with the two Arduinos (UNO and Nano).

Nano has 2 x DHT22, ADS1115 and MPRLS connected over I2C. Once all the readings gathered it suppose to send the data (7 float values) over SPI to UNO.

Arduino Nano is master and just transmitts the data while UNO keeps looking and just listening…

Master code:

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include "Adafruit_MPRLS.h"
#include <DHT.h>
#include <SPI.h>

Adafruit_MPRLS mpr = Adafruit_MPRLS(-1, -1);

DHT dht1(2, DHT22); 
DHT dht2(3, DHT22); 

Adafruit_ADS1115 ads(0x48);

float hum1;
float temp1; 
float hum2; 
float temp2;
float Voltage = 0.0;
float Voltage2 = 0.0;
int16_t adc0; 
int16_t adc1;

uint8_t storage_out [28];


void setup(void) 
{
  Serial.begin(9600);  
  ads.begin();
  mpr.begin();
  dht1.begin();
  dht2.begin();

  digitalWrite(SS, HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);
}


void loop(void) 
{
  adc0 = ads.readADC_SingleEnded(0);
  Voltage = (adc0 * 0.1875)/200;
  
  adc1 = ads.readADC_SingleEnded(1);
  Voltage2 = (adc1 * 0.1875)/200;
  
  hum1 = dht1.readHumidity();
  temp1= dht1.readTemperature();

  hum2 = dht2.readHumidity();
  temp2= dht2.readTemperature();
  
  float pressure_hPa = mpr.readPressure();

  float out[7] = {hum1, temp1, hum2, temp2, Voltage, Voltage2, pressure_hPa};

  digitalWrite(SS, LOW);
  memcpy(storage_out, &out, 28);
  SPI.transfer(storage_out, sizeof storage_out );
  digitalWrite(SS, HIGH);
  delay(3000);


  
}

Slave code:

#include <SPI.h>

byte storage [28];
volatile byte pos;
volatile boolean process;
float out_temp;
float out_hum;
float in_temp;
float in_hum; 
float voltage1;
float voltage2;
float pressure;
float buff[7];

void setup()
{
  pinMode(MISO,OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
  pos = 0;
  process = false;
  Serial.begin(9600);

}

ISR(SPI_STC_vect)
{
  byte gathered = SPDR;
  if( pos < sizeof storage)
    {
      storage[pos++] = gathered;
    }
    else 
    process = true;
}



void loop()
{

if( process )
  {

    memcpy(buff,&storage,28);
    out_temp = buff[0];
    out_hum = buff[1];
    in_temp = buff[2];
    in_hum = buff[3];
    voltage1 = buff[4];
    voltage2 = buff[5];
    pressure = buff[6];
    storage[pos] = 0;
    pos = 0;
    process = false;


  Serial.print("Voltage 1 (Volts): ");
  Serial.println(voltage1, 7);  

  Serial.print("Voltage 2 (Volts): ");
  Serial.println(voltage2, 7); 
  Serial.print("Pressure (hPa): "); Serial.println(pressure);
  
  //Print temp and humidity values to serial monitor
  Serial.print("Humidity 1: ");
  Serial.print(out_hum);
  Serial.print(" %, Temp 1: ");
  Serial.print(out_temp);
  Serial.println(" Celsius");

  Serial.print("Humidity 2: ");
  Serial.print(in_hum);
  Serial.print(" %, Temp 2: ");
  Serial.print(in_temp);
  Serial.println(" Celsius");
  Serial.println();

  }
}

The problem is that only every second reading is good, while other one is scrambled… Serial monitor results below:

Voltage 1 (Volts): 0.0000000
Voltage 2 (Volts): -0.0000000
Pressure (hPa): ovf
Humidity 1: -0.00 %, Temp 1: ovf Celsius
Humidity 2: -0.00 %, Temp 2: ovf Celsius

Voltage 1 (Volts): 13.3706245
Voltage 2 (Volts): 13.3696870
Pressure (hPa): 1025.42
Humidity 1: 21.80 %, Temp 1: 26.60 Celsius
Humidity 2: 21.70 %, Temp 2: 33.30 Celsius

Voltage 1 (Volts): -0.0000000
Voltage 2 (Volts): -0.0000000
Pressure (hPa): 0.05
Humidity 1: 0.00 %, Temp 1: 0.00 Celsius
Humidity 2: ovf %, Temp 2: -0.00 Celsius

Voltage 1 (Volts): 13.3696870
Voltage 2 (Volts): 13.3706245
Pressure (hPa): 1025.72
Humidity 1: 21.80 %, Temp 1: 26.70 Celsius
Humidity 2: 21.70 %, Temp 2: 33.40 Celsius

Voltage 1 (Volts): 0.0000000
Voltage 2 (Volts): -0.0000000
Pressure (hPa): 0.05
Humidity 1: 0.00 %, Temp 1: 0.00 Celsius
Humidity 2: ovf %, Temp 2: -0.00 Celsius

Voltage 1 (Volts): 13.3696870
Voltage 2 (Volts): 13.3706245
Pressure (hPa): 1025.41
Humidity 1: 21.80 %, Temp 1: 26.73 Celsius
Humidity 2: 21.70 %, Temp 2: 33.30 Celsius

I can’t get my head around where is the fault…

Anybody can help me and advise what I am missing?

Best Regards,

Darijus

Not related to your problem, but

  float out[7] = {hum1, temp1, hum2, temp2, Voltage, Voltage2, pressure_hPa};

Why don't you just store the data in the out array in the first place? Why do you need 7 scalars and an array of 7 values?

  memcpy(storage_out, &out, 28);

It is completely unnecessary to copy the 28 bytes from one array to another.

But, since you are doing this, print the contents of the storage_out array on both ends. I'm guessing that they are not the same. I'm also guessing that you are receiving data twice for every send. One is the data sent, the other is all zeros.

    memcpy(buff,&storage,28);

should be

   memcpy(buff, storage, 28);

and

 memcpy(storage_out, &out, 28);

should be

 memcpy(storage_out, out, 28);

PaulS:
Not related to your problem, but

  float out[7] = {hum1, temp1, hum2, temp2, Voltage, Voltage2, pressure_hPa};

Why don’t you just store the data in the out array in the first place? Why do you need 7 scalars and an array of 7 values?

  memcpy(storage_out, &out, 28);

It is completely unnecessary to copy the 28 bytes from one array to another.

But, since you are doing this, print the contents of the storage_out array on both ends. I’m guessing that they are not the same. I’m also guessing that you are receiving data twice for every send. One is the data sent, the other is all zeros.

Tried to print in both ends, and yes - it seems arrays are not the same. Could you please advise how to prevent that? I tried not to copy arrays and send straight the first array but the result is the same.

Ok, tried once more to rewrite the code in simpler way…

Master node code:

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include "Adafruit_MPRLS.h"
#include <DHT.h>
#include <SPI.h>

Adafruit_MPRLS mpr = Adafruit_MPRLS(-1, -1);

DHT dht1(2, DHT22); 
DHT dht2(3, DHT22); 

Adafruit_ADS1115 ads(0x48);

uint8_t storage_out [42];
float out[7];

void setup(void) 
{
  ads.begin();
  mpr.begin();
  dht1.begin();
  dht2.begin();

  digitalWrite(SS, HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);
}


void loop(void) 
{
  out[4] = (ads.readADC_SingleEnded(0) * 0.1875)/200;
  
  out[5] = (ads.readADC_SingleEnded(1) * 0.1875)/200;
  
  out[0] = dht1.readHumidity();
  out[1]= dht1.readTemperature();

  out[2] = dht2.readHumidity();
  out[3]= dht2.readTemperature();
  
  out[6] = mpr.readPressure();



  digitalWrite(SS, LOW);
  memcpy(storage_out, out, 28);
  SPI.transfer(storage_out, sizeof storage_out);
  digitalWrite(SS, HIGH);

  
 delay(3000);


  
}

Slave node code:

#include <SPI.h>

byte storage [42];
volatile byte pos;
volatile boolean process;
float buff[7];

void setup()
{
  pinMode(MISO,OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= _BV(SPIE);
  pos = 0;
  process = false;
  Serial.begin(9600);

}

ISR(SPI_STC_vect)
{
  byte gathered = SPDR;
  if( pos < sizeof storage)
    {
      storage[pos++] = gathered;
    }
    else 
    process = true;
}

void loop()
{
  if( process )
  {
    memcpy(buff, storage, 28);
    Serial.print("Main Battery (Volts): ");
    Serial.println(buff[4], 7);  

   Serial.print("Leisure Battery (Volts): ");
   Serial.println(buff[5], 7); 
   Serial.print("Pressure (hPa): "); Serial.println(buff[6]);
  
   Serial.print("Humidity Inside: ");
   Serial.print(buff[0]);
   Serial.print(" %, Temp Inside: ");
   Serial.print(buff[1]);
   Serial.println(" Celsius");

   Serial.print("Humidity Outside: ");
   Serial.print(buff[2]);
   Serial.print(" %, Temp Outside: "); 
   Serial.print(buff[3]);
   Serial.println(" Celsius");
   Serial.println();
    
    storage[pos] = 0;
    pos = 0;
    process = false;


  }
}

Now communication is much more reliable but I still very occasionally see some missed data. For example, bellow everything was working until suddenly pressure reading went from 1015 down to 785. And it seems always drops to the same value.

Main Battery (Volts): 13.1559371
Leisure Battery (Volts): 13.1043748
Pressure (hPa): 1015.62
Humidity Inside: 27.10 %, Temp Inside: 22.30 Celsius
Humidity Outside: 36.80 %, Temp Outside: 21.40 Celsius

Main Battery (Volts): 13.1549997
Leisure Battery (Volts): 13.1043748
Pressure (hPa): 1015.55
Humidity Inside: 27.10 %, Temp Inside: 22.30 Celsius
Humidity Outside: 37.10 %, Temp Outside: 21.40 Celsius

Main Battery (Volts): 13.1559371
Leisure Battery (Volts): 13.1043748
Pressure (hPa): 785.96
Humidity Inside: 27.10 %, Temp Inside: 22.30 Celsius
Humidity Outside: 36.90 %, Temp Outside: 21.40 Celsius

Main Battery (Volts): 13.1549997
Leisure Battery (Volts): 13.1043748
Pressure (hPa): 1015.57
Humidity Inside: 27.10 %, Temp Inside: 22.30 Celsius
Humidity Outside: 36.90 %, Temp Outside: 21.40 Celsius

Tried not to copy arrays but it didn’t work for some reason. Actually, it did work if I am directly sending array from the master but if not using memcpy(buff, storage, 28); in slave, it wouldn’t work.

How long are the wires between the two Arduinos? SPI is made for communication on a PCB, a bus longer than about 40-50cm won't work reliably, in a noisy environment you won't even get to that length.

pylon:
How long are the wires between the two Arduinos? SPI is made for communication on a PCB, a bus longer than about 40-50cm won’t work reliably, in a noisy environment you won’t even get to that length.

Wires are around 7 cm long. Would twisted cable help in this case?

Would twisted cable help in this case?

No. A good shielding might help if you're in a noisy environment but I would search for bad cables, breadboards are often a source of bad connections, and so on.

What would be the best way to connect 2 arduinos if they 3-4 meters apart? Would serial like rs232 work well?

What would be the best way to connect 2 arduinos if they 3-4 meters apart? Would serial like rs232 work well?

That might work if the environment is electrically not noisy. I prefer using RS-485, the signal is submitted differentially which makes it immune to catching up induced signals on it's way. You can use full-duplex RS-485 if you need concurrent traffic in both directions. CAN bus interfaces are another way that works very well for such distances (although I never tried that myself) and of course Ethernet although that mgiht be an overkill for your project.

Does arduino support 485 without any additional converters?

Does arduino support 485 without any additional converters?

No, that was not part of your specification. Without external components there's no way to reliably connect 2 Arduinos over 4m.