Sending two Floats over serial between Arduinos

I'm pretty new to Arduino and coding in general, but I've been working on a project to take temperature and humidity readings. I've seen this asked before, but for some reason I haven't been able to get it working based on previous posts. I am trying to send two sensor readings from one Arduino to another and then save that reading on a SD card on the second Arduino. Both the sensor readings are floats and I've been having trouble getting the data on the other side.

I send the data with:

float lastINPUT1 = temperature;
float lastINPUT2 = humidity;



  byte* Data;
  INPUT1FloatPtr = (byte*) &lastINPUT1;
  INPUT2FloatPtr = (byte*) &lastINPUT2;
  Data[0] = INPUT1FloatPtr[0]; 
  Data[1] = INPUT1FloatPtr[1]; 
  Data[2] = INPUT1FloatPtr[2]; 
  Data[3] = INPUT1FloatPtr[3]; 
  Data[4] = INPUT2FloatPtr[0];
  Data[5] = INPUT2FloatPtr[1];
  Data[6] = INPUT2FloatPtr[2];
  Data[7] = INPUT2FloatPtr[3];
  Serial1.write(Data,8);

So I'm trying to send the floats as part of a byte array.

on the receiving end I've tried a couple of things:

 if(Serial1.available() >= 8)
    {
      int i = 0;
      while(Serial.available())    
      { 
        data[i] = Serial1.receive();  
        i = i + 1;
      }

    union Temp_tag {byte Temp_b[4]; float Temp_fval;} Temp_Union;    
      Temp_Union.Temp_b[0] = data[0];
      Temp_Union.Temp_b[1] = data[1];
      Temp_Union.Temp_b[2] = data[2];
      Temp_Union.Temp_b[3] = data[3];    
      temperature = Temp_Union.Temp_fval;
      
      union Hum_tag {byte Hum_b[4]; float Hum_fval;} Hum_Union;       
      Hum_Union.Hum_b[0] = data[4];
      Hum_Union.Hum_b[1] = data[5];
      Hum_Union.Hum_b[2] = data[6];
      Hum_Union.Hum_b[3] = data[7];    
      humidity = Hum_Union.Hum_fval;

this was based off of a post on sending floats over I2C so I wasn't sure if it works in serial.

I also tried using readBytes to make a buffer of 8 bytes, but I'm not sure if that's the right direction

if(Serial1.available() >0)
    {
     
      Serial1.readBytes(buf, BUFFER_SIZE);

for each method I tried I saved the data to the SD card with:

logfile.print("Room Temp *C: "); logfile.println(temperature);
logfile.flush();
logfile.print("Room Hum %: "); logfile.println(humidity);
logfile.flush();

but regardless of what I tried, I only got "Room Temp *C: 0.00" or "Room Hum %: 0.00" as the value for the temperature and humidity values when I checked the SD card. Thanks for any advice you may have!

Have You verified that the sensor readings are correct and sent correctly?
Please post the entire code of the receiver. Snippets are not enough. I smell mistakes but ask for the entire code instead of kicking Your code down now.

Why?

Why not just send, receive and store the character representation of the float values?

Be careful with the while (Serial.available()) on the receive end, you checked for 8 or more characters available in the buffer, you will exceed the bounds of the data array when there are too many characters.

Using a union for type punning may be confusing the compiler. Why not use pointers directly to temperature and humidity like you did for the sender?

memcpy would probably be a bit easier than the individual byte copies.

Personally, I would put the floats in a struct on the sender to avoid having to copy into the Data array.

Do you really need more than 1 or 2 decimal places for temperature and humidity? I would multiply the floats by 10 or 100 and put them into int data type. Then make a data packet using sprintf() or snprintf(). Send the packet. At the other end, parse the packet and use atof() and divide by 10 or 100 to return the values to floats (if necessary).

Example code
Sender:

#include <SoftwareSerial.h>

SoftwareSerial ss(4, 7);

float temp = 26.3257;
float humi = 34.2589;

void setup()
{
   Serial.begin(115200);
   ss.begin(9600);
}

void loop()
{
   // send  a packet every second
   static unsigned long timer = 0;
   unsigned long interval = 1000;
   if (millis() - timer >= interval)
   {
      timer = millis();
      // convert to int with rounding
      int temp_i = int((temp + 0.05) * 10); // ADD 0.005 FOR * 100
      int humi_i = int((humi + 0.05) * 10); // ADD 0.005 FOR * 100
      char buffer[11];
      snprintf(buffer, 10, "%d,%d", temp_i, humi_i);
      Serial.println(buffer);
      ss.println(buffer);
   }
}

Receive code

#include <SoftwareSerial.h>

SoftwareSerial ss(4, 7);

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

float temp = 0;
float humi = 0;

void setup()
{
   Serial.begin(115200);
   ss.begin(9600);
}

void loop()
{
   recvWithEndMarker();
   //showNewData();
   parseData();
}

void recvWithEndMarker()
{
   static byte ndx = 0;
   char endMarker = '\n';
   char rc;

   while (ss.available() > 0 && newData == false)
   {
      rc = ss.read();

      if (rc != endMarker)
      {
         receivedChars[ndx] = rc;
         ndx++;
         if (ndx >= numChars)
         {
            ndx = numChars - 1;
         }
      }
      else
      {
         receivedChars[ndx] = '\0'; // terminate the string
         ndx = 0;
         newData = true;
      }
   }
}

void showNewData()
{
   if (newData == true)
   {
      Serial.print("This just in ... ");
      Serial.println(receivedChars);
      //newData = false;
   }
}

void parseData()
{
   if (newData == true)
   {
      char *strings[3]; // an array of pointers to the pieces of the above array after strtok()
      char *ptr = NULL; byte index = 0;
      ptr = strtok(receivedChars, ",");  // delimiters, semicolon
      while (ptr != NULL)
      {
         strings[index] = ptr;
         index++;
         ptr = strtok(NULL, ",");
      }
      /*
      // print all the parts   
      Serial.println("The Pieces separated by strtok()");
      for (int n = 0; n < index; n++)
      {
         Serial.print("piece ");
         Serial.print(n);
         Serial.print(" = ");
         Serial.println(strings[n]);
      }
      */
      // convert string data to numbers
      temp = atof(strings[0]) / 10;
      humi = atof(strings[1]) / 10;

      Serial.print("temperature = ");
      Serial.print(temp, 1);
      Serial.print("   humidity = ");
      Serial.println(humi, 1);
      Serial.println();
      newData = false;
   }
}

For something like temperature and humidity, it makes more sense to send integer data.

You can multiply by (for example) 100 before conversion to integer, to avoid losing accuracy, although the fractional part of those particular measurements is probably meaningless.

Why are you using two arduinos to begin with? Is the second arduino only for saving the data to the SD card, or does it have some other function?

Isn't someone going to address the elephant in the room?

I would expect the compiler to be showing a warning that Data is used uninitialized. I had completely overlooked that no memory was ever allocated for wherever Data points to.

Hah! Beat me to the blindingly obvious question. :grin:

Possibly only if you increase the warning level in file -> preferences.