Go Down

Topic: Writing float values to Eeprom (Read 16 times) previous topic - next topic

GordonEndersby

Hi guys,

Ive learnt a lot on the forum just by reading all the posts.

But now I have a little c question.
Im trying to save some temperature values to the onboard Eeprom.
I was using a float array to store the values.
But changed it to double to fit the example from:
http://www.openobject.org/opensourceurbanism/Storing_Data
It looks right and I assume hes had it working but Im getting an error when I build the code.
My code is below.

In function 'void EEPROMWriteDouble(int, double)':
error: invalid operands of types 'double' and 'int' to binary 'operator>>

So its telling me that I cant use the binary operator on the double p_value.

My question is how can I split a double or float to its 4 bytes to store on the eeprom?

Ive tried changing from double to long, binary operators work, but I lose the values after the decimal places.
Can I preserve the whole value or am I going to have to multiply the value by 100 to fit the long?
Theres no saving in bytes on the eeprom by using long as its still 4 bytes.

I hope that lot makes sense.

Thanks

Gordon

Code: [Select]
#include <EEPROM.h>

double testInt[12] = {
 -12.5, -10.00, -5.7, 0, 2.45, 2.90, 3.10, 4 , 5.6, 7.9, 5.5, 4};
byte noElem = 12;
unsigned int baseAddr = 0;

void setup() {
 Serial.begin(9600);

 // write float array to eeprom
 // float value takes 4 bytes
 // addresses are baseAddr + address every 4 bytes
 for (int i=0; i < noElem-1; i++){
   EEPROMWriteDouble( (i*4)+baseAddr, testInt[i]);
 }

 //read data back
 for (int i=0; i < noElem-1; i++){
   int addr = (i*4)+baseAddr;
   double val = EEPROMReadDouble( addr);
   Serial.print((long)val);
 }
}

void loop() {

}

void EEPROMWriteDouble(int p_address, double p_value)
{
 byte Byte1 = ((p_value >> 0) & 0xFF);
 byte Byte2 = ((p_value >> 8) & 0xFF);
 byte Byte3 = ((p_value >> 16) & 0xFF);
 byte Byte4 = ((p_value >> 24) & 0xFF);

 EEPROM.write(p_address, Byte1);
 EEPROM.write(p_address + 1, Byte2);
 EEPROM.write(p_address + 2, Byte3);
 EEPROM.write(p_address + 3, Byte4);
}

float EEPROMReadDouble(int p_address)
{
 byte Byte1 = EEPROM.read(p_address);
 byte Byte2 = EEPROM.read(p_address + 1);
 byte Byte3 = EEPROM.read(p_address + 2);
 byte Byte4 = EEPROM.read(p_address + 3);

 long firstTwoBytes = ((Byte1 << 0) & 0xFF) + ((Byte2 << 8) & 0xFF00);
 long secondTwoBytes = (((Byte3 << 0) & 0xFF) + ((Byte4 << 8) & 0xFF00));
 secondTwoBytes *= 65536; // multiply by 2 to power 16 - bit shift 24 to the left

 return (firstTwoBytes + secondTwoBytes);
}

mem

The safest thing would be to multiply the value by 100 or whatever to convert it into a long value.

If you really wanted to get dirty and retrieve the byte values you could use a union. Something like the following would return the double value as if it was a long.  

long doubleToLong(double value) {
 union { double d; long l; } n = {value};
 return n.d;
}

halley

The safest thing would be to treat the variable as a byte array in RAM, and transfer it byte-for-byte into EEPROM.

Untested.

Code: [Select]
void EEPROM_writeDouble(int ee, double value)
{
   byte* p = (byte*)(void*)&value;
   for (int i = 0; i < sizeof(value); i++)
       EEPROM.write(ee++, *p++);
}

double EEPROM_readDouble(int ee)
{
   double value = 0.0;
   byte* p = (byte*)(void*)&value;
   for (int i = 0; i < sizeof(value); i++)
       *p++ = EEPROM.read(ee++);
   return value;
}

halley

#3
Feb 13, 2009, 12:32 am Last Edit: Feb 13, 2009, 12:36 am by halley Reason: 1
Okay, I decided to go ahead and write the general templated functions and test them.  Read anything.  Write anything.  Each function returns the number of EEPROM bytes read or written to accomplish the data transfer.  Woo hoo.

Code: [Select]

#include <EEPROM.h>

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
   const byte* p = (const byte*)(const void*)&value;
   int i;
   for (i = 0; i < sizeof(value); i++)
       EEPROM.write(ee++, *p++);
   return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
   byte* p = (byte*)(void*)&value;
   int i;
   for (i = 0; i < sizeof(value); i++)
       *p++ = EEPROM.read(ee++);
   return i;
}


For testing and demonstrations:

Code: [Select]

// include the above EEPROM functions

struct st_t { long lo; byte by; double db; };

void setup()
{
   Serial.begin(9600);

   int n = 0;

   byte by = 0x33;
   Serial.println(by, HEX);
   n = EEPROM_writeAnything(0, by);
   Serial.print("Wrote bytes: ");
   Serial.println(n);
   by = 0xFF;
   Serial.println(by, HEX);
   n = EEPROM_readAnything(0, by);
   Serial.print("Read bytes: ");
   Serial.println(n);
   Serial.println(by, HEX);

   Serial.println("-------");

   long lo = 0xDEADBEEF;
   Serial.println(lo);
   n = EEPROM_writeAnything(23, lo);
   Serial.print("Wrote bytes: ");
   Serial.println(n);
   lo = 0xFFFFFFFF;
   Serial.println(lo);
   n = EEPROM_readAnything(23, lo);
   Serial.print("Read bytes: ");
   Serial.println(n);
   Serial.println(lo);

   Serial.println("-------");

   double pi = 3.1415926538;

   struct st_t st;
   st.lo = 0xABADF00D;
   st.by = 0x22;
   st.db = pi;
   Serial.println(st.lo);
   Serial.println(st.by, HEX);
   Serial.println(st.db == pi);
   n = EEPROM_writeAnything(221, st);
   Serial.print("Wrote bytes: ");
   Serial.println(n);
   st.lo = 0xFFFFFFFF;
   st.by = 0x11;
   st.db = 0.0;
   Serial.println(st.lo);
   Serial.println(st.by, HEX);
   Serial.println(st.db == pi);
   n = EEPROM_readAnything(221, st);
   Serial.print("Read bytes: ");
   Serial.println(n);
   Serial.println(st.lo);
   Serial.println(st.by, HEX);
   Serial.println(st.db == pi);
}

void loop()
{
}

mikalhart

Ok, I have to say that's pretty sweet. :)

Way to go template man.  Woo hoo! indeed.

Mikal

Go Up