I am a novice programmer and have been trying to store some various user settings for controlling into the EEPROM on the Arduino. essentially I would like to be able to define a structure as is done in the following link: http://playground.arduino.cc/Code/EEPROMWriteAnything
Ideally I would like to use the library that is already available (avr/eeprom) since I couldn't seem to figure out how to get Atmel Studio to recognize the .h file when I made it. I implemented the latter code in the link with no errors, but am not quite sure if it is actually changing the data in the structure. I am making some sort of temperature monitoring station and would like to be able to store a handful of integer or float values. Essentially I have something like this, the code is an approximation as I do not have mine in front of me and is 30 some pages long:
#include <avr/eeprom.h>
volatile int Temp = 55;
volatile int Hu = 50;
struct settings_t
{
volatile int Temp;
volatile int TempC;
volatile int Hu;
} settings;
void setup()
{
eeprom_read_block((void*)&settings, (void*)0, sizeof(settings));
Serial.begin(9600);
// the rest of my setup
}
void loop()
{
Serial.println(Temp);
Serial.println(Hu);
//Here the temps will be set and saved on the touch of a button something like this
if (xxxxxx)
{
volatile int Temp = 87;
volatile int TempC = (((Temp -32)*5)/9); //whatever the appropriate conversion is i cannot remember it ever off the top of my head.
volatile float Hu = 67.3;
}
// if they push the "Save" button, save their configuration
if (digitalRead(13) == HIGH)
{
eeprom_write_block((const void*)&settings, (void*)0, sizeof(settings));
Serial.print("Settings Saved");
}
I am not only new to using the EEPROM on the ATMEGAs but also to working with structs but I am trying to learn so bare with me.
I am unsure how to access this read data, or assure it is read/written. In my code I set some of these temps, then save the data which in turn writes to the EEPROM and I get a confirm on the Serial, then when I unpower the Arduino and restore power, it powers up and then prints the set values in the beginning again. I clearly do not understand how this works and have been reading the documentation on structs and EEPROM all evening. If someone could please give me some guidance on how to make this function that would be great.
Essentially I don't know if this is working --> eeprom_read_block((void*)&settings, (void*)0, sizeof(settings));
And if it is (if there are no errors I am assuming it is) how do I now read this struct into my program again to use these values or use these values in my program after power off. Thanks for any help.
You are on the right track. Here is a modified snippet that may guide you closer. There are still things to consider, like changing Temp to a float as you assign it a decimal. Your vars do not need to be volatile in this scenario either.
I removed some stuff and added my own changes.
#include <avr/eeprom.h>
struct settings_t{
int Temp;
int TempC;
int Hu;
};
const void * const settingsAddress = ( void* ) 0x00;
settings_t settings;
void setup(){
pinMode( 13, INPUT );
eeprom_read_block((void*)&settings, settingsAddress, sizeof(settings));
Serial.begin(9600);
}
void loop(){
//Here the temps will be set and saved on the touch of a button something like this
if( true ){
settings.Temp = 87;
settings.TempC = (((settings.Temp -32)*5)/9);
settings.Hu = 67.3; //Hu is an int.
}
// if they push the "Save" button, save their configuration
if (digitalRead(13) == HIGH){
eeprom_write_block((const void*)&settings, (void*)0, sizeof(settings));
Serial.print("Settings Saved");
}
}
Another way you could use the EEPROM is to follow the PROGMEM way, and give it some default values.
settings_t settings EEMEM = { 1, 2, 3 };
settings is now in EEPROM, you use the standard eeprom_read_word, eeprom_write_word functions and &settings is the address you use. You can use this method to read and write individual members.
Thanks so much! Pyro, those few simple lines showed me about everything I needed to know for this. One final question however: Say I wanted to have a starting temperature pre-stored in the EEPROM Take, 80 degrees for example. Essentially I keep running into issues when I load the EEPROM on a fresh start or new variable that doesnt have a value pre-saved in the EEPROM and it either ouputs a "-" or a "-1" in those places. Ideally I would like to set the Temp to 80 if there is no reasonable value in the EEPROM. If there is a reasonable value I'd like to read it.
I have managed to get it to work with a bunch of nested if loops but believe there has to be a simpler way.
Another way of thinking of this would be to just simply put a value into the EEPROM only if there isn't one there already in the code somehow. I am not quite sure how to go about implementing this so that it starts with a beginning value. Thanks so much the replies have been helpful.
It appears that EEMEM doesn't store the initial values under the IDE, using an ISP will work as someone else pointed out in another thread. I can see the data in the .eep file.
Your suggestion of using a separate variable to check for a first run is probably the easiest. However use something that is at least a few bytes. The longer the better as it will greatly reduce the chances of eeprom data from a previous sketch being a match.
You also do not need to store tempC, it can be calculated on the fly.
settings.Temp = 87;
settings.TempC = (((settings.Temp -32)*5)/9);
settings.Hu = 67.3; //Hu is an int.
Here is what it could look like.
struct settings_t{
int TempC(){ return ( ( ( eeprom_read_word( &this->Temp ) -32 ) * 5 ) / 9 ) };
int Temp;
int Hu;
};
You can wrap all the eeprom functionality into the object:
enum EREF{ ETEMP, EHU, ETEMPC };
struct settings_t{
int Read( EREF e ){
switch( e ){
case 0:
case 1:
return eeprom_read_word( ( uint16_t* ) &this->Data[ e ] );
default:
return ( ( ( Read( ETEMP ) -32 ) * 5 ) / 9 );
}
}
void Write( int Temp, int Hu ){
eeprom_write_word( ( uint16_t* ) &this->Data[ 0 ], Temp );
eeprom_write_word( ( uint16_t* ) &this->Data[ 1 ], Hu );
}
int Data[ 2 ];
};
One way to deal with the issue of EEPROM initialisation/validity is to include a checksum in the stored data, calculate (and store) the checksum when saving, and read and validate when reading. The default values would be returned if the checksum test fails.