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