I have recently been trying to save data to an EEPROM for a flight computer I'm developing. I have had some success saving float values to the EEPROM, but they seemingly come back as random characters when interpreted by the Arduino serial monitor. In trying to save floats in an intelligible manner, I have been trying to convert them to char arrays. However, in the use of a union function to convert them I encounter an error stating that I am attempting to use a deleted constructor function. After much troubleshooting I have no idea why a constructor function would be deleted by this union. My complete code is below.
#include <Wire.h>
#define address 0x54
long eepromadd = 0;
void setup() {
// put your setup code here, to run once:
float f = 42.42;
union {
String sometext;
byte storehere [20];
}data;
data.sometext = (String)f;
Wire.begin();
Wire.beginTransmission(address);
Wire.write((int)(eepromadd >> 8));
Wire.write((int)(eepromadd & 0xFF));
for (byte x = 0; x < 20; x++) {
Wire.write(data.bytes[x]);
}
Wire.endTransmission();
}
void loop() {
}
Here is the complete error message:
exit status 1
use of deleted function 'setup()::<anonymous union>::<constructor>()'
Any help you can offer would be greatly appreciated.
If this flight computer is going to run on an Arduino, forget that String (capital S) exists. Good chance that your application and plane will crash sooner or later if you make (heavy) use of concatenations.
I have recently been trying to save data to an EEPROM for a flight computer I'm developing. I have had some success saving float values to the EEPROM, but they seemingly come back as random characters when interpreted by the Arduino serial monitor.
You are doing something wrong. Please post the code which is performing as you state.
See this example sketch
#include <Wire.h>
#define ADDRESS 0x57 //Address of EEPROM
union float_bytes{
float f;
byte b[4];
};
void setup() {
Serial.begin(9600);
Wire.begin();
float_bytes dataStored;//declare union for store
float_bytes dataRetrieved;//declare union for retrieve
dataStored.f = 1234.567;
Serial.print("Value to be stored in eeprom as bytes ");
Serial.println(dataStored.f, 3);
Serial.println("Writing bytes to eeprom");
for (int i = 0; i < 4; i++)
{
writeByte(ADDRESS, i, dataStored.b[i]);
}
Serial.println("Reading bytes from eeprom");
for (int i = 0; i < 4; i++)
{
dataRetrieved.b[i] = readByte(ADDRESS, i);
}
Serial.print("Data Retrieved ");
Serial.println(dataRetrieved.f, 3);
}
void loop() {}
void writeByte(int device, unsigned int add, byte data)
{
Wire.beginTransmission(device);
Wire.write((int)(add >> 8)); // left-part of pointer address
Wire.write((int)(add & 0xFF)); // and the right
Wire.write(data);
Wire.endTransmission();
delay(5);//small delay for eeprom to save data
}
// reads a byte of data to the I2C address 'device', in memory location 'add'
byte readByte(int device, unsigned int add)
{
Wire.beginTransmission(device); // I2C address
Wire.write((int)(add >> 8)); // bit shift for high byte of pointer address
Wire.write((int)(add & 0xFF)); // mask for the low byte
Wire.endTransmission();
Wire.requestFrom(device, 1);
return Wire.read();
}
Why not adapt the put() and get() methods from the Arduino EEPROM.h library to access your I2C EEPROM instead of the processor's internal EEPROM? That would give you type (and size) - agnostic save and retrieve functions. You'd be able to store and retrieve any datatype you wanted -- int, float, array, struct,...
AWOL:
You're onto a losing proposition trying to convert between a String representation of a float and back.
Store the four bytes of the float and maintain precision.
The purpose of the EEPROM in the final flight computer is to log the flight data collected over 180 seconds. The code I posted is simply a test program to try and pinpoint the problems I have had in my more complicated programs. The problem I initially encountered with this method was that the float values would save correctly to the EEPROM, but would come back as random symbols when I tried to read them using the Arduino serial monitor. If you know of a way to convert the byte values that encode a float back to the original floating point value that would be wonderful.
The problem I initially encountered with this method was that the float values would save correctly to the EEPROM, but would come back as random symbols when I tried to read them using the Arduino serial monitor. If you know of a way to convert the byte values that encode a float back to the original floating point value that would be wonderful.
The example code using a union which was provided in reply#3 does provide the original floating point value from the stored bytes when retrieved.
Can you post the code that gives the "random symbols" with when trying to retrieve the float value?
You have an external EEPROM with device address 1010100 (0x54) and you want to save the number 42.42 into it starting at location 0x0000.
1. What is the equivalent bit pattern (considering UNO) for the number 42.42? Ans: 01000010 00101001 10101110 00010100 (0x4229AE14). This is not a magic number; it can be easily obtained by executing the following code.
float f = 42.42;
long m = *(long*)&f;
Serial.println(m, HEX); //shows: 4229AE14
2. How many memory locations do you need to store the number 42.42? Ans: 4. The answer has come from the result of Step-1.
3. Separate the 32-bit data of Step-1 into 4 bytes as the I2C Bus handles data byte by byte.
4. Execute the following codes to write 42.42 into the EEPROM.
Wire.beginTransmission(0b1010100);
Wire.write(highByte(eepromadd)); //high byte of address = 0x00
Wire.write(lowByte(eepromadd)); //low byte of address = 0x00
Wire.write(data.myArray, sizeof(data.myArray));
Wire.endTransmission();
delay(5); //delay for write time into the EEPROM
5. Read data from from EEPROM using Wire.requestFrom() function and show them on Serial Monitor. (But, don't forget to point the beginning location of the EEPROM - 0x0000.)
I'm not a fan of the union method as it can be non-portable and implementation-dependent. For some reason, @itemboxes ignored my first suggestion to customize the EEPROM.h library. So, here's another Data Type - Agnostic method. Untested, but it compiles.
I'm not so sure. These external i2c eeproms have page boundary issues with block writes.
If the byte casts or pointers are more portable than unions, that's good, but I'd stick with the individual byte write unless you address the page boundary issue.
cattledog:
I'm not so sure. These external i2c eeproms have page boundary issues with block writes.
If the byte casts or pointers are more portable than unions, that's good, but I'd stick with the individual byte write unless you address the page boundary issue.
what do you think Wire.write(buffer, size) does?
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
if(transmitting){
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i){
write(data[i]);
}
}else{
// in slave send mode
// reply to master
twi_transmit(data, quantity);
}
return quantity;
}
The code you posted does not call end transmission after each byte, and I think that the boundary overwrite issue is there without that. It's easy enough to test.
Every library for writing to external eeproms which uses block writes addresses the boundary issue.