Arduino Using EEPROM

hi, im thinking about sotre some variable in the EEPROM so when i change them while the program is running i can use those same variables when the system restarts. my question is how long will the EEPROM last doing something like this. this is what i want to store in the EEPROM

unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;
unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;
unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;
unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;
unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;
unsigned long 1ontimeDAY = 10700; /////
unsigned long 1offtimeDAY = 10000;

these are not the exact variable names but this gives an idea. is this too much for the eeprom?

How do you mean "too much for the EEPROM"? You have 1k of EEPROM on a Uno and a unsigned long takes 4 bytes. So 12 unsigned longs is 48 bytes aka will fit plenty.

BUT the number of write cycles is limited to 100.000 (but you can read it as often as you like). So only change the value if you really need to.

And uhm, you do know you need unique variable names? :wink:

septillion:
How do you mean “too much for the EEPROM”? You have 1k of EEPROM on a Uno and a unsigned long takes 4 bytes. So 12 unsigned longs is 48 bytes aka will fit plenty.

BUT the number of write cycles is limited to 100.000 (but you can read it as often as you like). So only change the value if you really need to.

And uhm, you do know you need unique variable names? :wink:

thanks, do you mean 100k? "100.000 ", and yes i know i need unique variable names.i hate to be a burden but is there any chance i could get you or someone to show me an example of saving 2 variables in the eeprom with this example code?

#include <EEPROM.h>
#define CONFIG_VERSION "ls1"
#define CONFIG_START 32

struct StoreStruct {
  char version[4];
  // The variables of your settings
  int a, b;
  char c;
  long d;
  float e[6];
} storage = {
  CONFIG_VERSION,
  // The default values
  220, 1884,
  'c',
  10000,
  {4.5, 5.5, 7, 8.5, 10, 12}
};

void loadConfig() {
  // To make sure there are settings, and they are YOURS!
  // If nothing is found it will use the default settings.
  if (EEPROM.read(CONFIG_START + 0) == CONFIG_VERSION[0] &&
      EEPROM.read(CONFIG_START + 1) == CONFIG_VERSION[1] &&
      EEPROM.read(CONFIG_START + 2) == CONFIG_VERSION[2])
    for (unsigned int t=0; t<sizeof(storage); t++)
      *((char*)&storage + t) = EEPROM.read(CONFIG_START + t);
}
void saveConfig() {
  for (unsigned int t=0; t<sizeof(storage); t++)
    EEPROM.write(CONFIG_START + t, *((char*)&storage + t));
}
void setup() {
  loadConfig();
}

void loop() {
  int i = storage.c - 'a';
  storage.c = 'a';
  if (ok)
    saveConfig();
}

this stuff is a little advanced for me. if i seen it with one of the variables i could probably take it from there. thanks again.

im not sure why this example sketch has 2 void loops and setups?

/* LoadAndSaveSettings
 * footswitch 2012-03-05, original code by Joghurt (2010)
 * Demonstrates how to load and save settings to the EEPROM
 * Tested on Arduino Uno R2 with Arduino 0023
 */
// Contains EEPROM.read() and EEPROM.write()
#include <EEPROM.h>

// ID of the settings block
#define CONFIG_VERSION "ls1"

// Tell it where to store your config data in EEPROM
#define CONFIG_START 32

// Example settings structure
struct StoreStruct {
  // The variables of your settings
  int a, b;
  char c;
  long d;
  float e[6];
  // This is for mere detection if they are your settings
  char version_of_program[4]; // it is the last variable of the struct
  // so when settings are saved, they will only be validated if
  // they are stored completely.
} settings = {
  // The default values
  220, 1884,
  'c',
  10000,
  {4.5, 5.5, 7, 8.5, 10, 12},
  CONFIG_VERSION
};

void loadConfig() {
  // To make sure there are settings, and they are YOURS!
  // If nothing is found it will use the default settings.
  if (//EEPROM.read(CONFIG_START + sizeof(settings) - 1) == settings.version_of_program[3] // this is '\0'
      EEPROM.read(CONFIG_START + sizeof(settings) - 2) == settings.version_of_program[2] &&
      EEPROM.read(CONFIG_START + sizeof(settings) - 3) == settings.version_of_program[1] &&
      EEPROM.read(CONFIG_START + sizeof(settings) - 4) == settings.version_of_program[0])
  { // reads settings from EEPROM
    for (unsigned int t=0; t<sizeof(settings); t++)
      *((char*)&settings + t) = EEPROM.read(CONFIG_START + t);
  } else {
    // settings aren't valid! will overwrite with default settings
    saveConfig();
  }
}

void saveConfig() {
  for (unsigned int t=0; t<sizeof(settings); t++)
  { // writes to EEPROM
    EEPROM.write(CONFIG_START + t, *((char*)&settings + t));
    // and verifies the data
    if (EEPROM.read(CONFIG_START + t) != *((char*)&settings + t))
    {
      // error writing to EEPROM
    }
  }
}


void setup() {
  loadConfig();
}

void loop() {
  // [...]
  int i = settings.c - 'a';
  // [...]

  // [...]
  settings.c = 'a';
  if (some_condition)
    saveConfig();
  // [...]
}

(Yes 100000 write cycles is usually what the EEPROM cell can take before being considered as untrusted)

Have you checked the EEPROM Library documentation? --> you'll see examples there

If what you want to manage are defaults parameters for your program, I usually store them in a structure and I read or update that structure in EEPROM every time needed (see the put() function that will only write what has changed). There is a trick to know if the memory has been initialized the first you run your program to ensure the EEPROM has meaningful value --> write in the first 4 bytes of the EEPROM a known key (like 0xDEADBEEF) and if it's there you can safely assume a structure has been saved in memory, if not this is the first use on that arduino and you need to establish default values

Yeah, 100k. 100.000 as in European notation :wink:

Drop those examples and have a look at EEPROM.put() and EEPROM.get(). They're part of the IDE examples.

And if a piece of code has two loops()'s or setup()'s etc someone just messed up completely... Delete it and don't look at it.

J-M-L:
Have you checked the EEPROM Library documentation?

→ you’ll see examples there

(Yes 100000 write cycles is usually what the EEPROM cell can take before being considered as untrusted)

right now im reading “https://playground.arduino.cc/Code/EEPROMReadWriteLong” but im not sure whats going on here. it is way ahead of my education level. i dont even know how this works. especially this part,

void EEPROMWritelong(int address, long value)
      {
      //Decomposition from a long to 4 bytes by using bitshift.
      //One = Most significant -> Four = Least significant byte
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);

      //Write the 4 bytes into the eeprom memory.
      EEPROM.write(address, four);
      EEPROM.write(address + 1, three);
      EEPROM.write(address + 2, two);
      EEPROM.write(address + 3, one);
      }

//This function will return a 4 byte (32bit) long from the eeprom
//at the specified address to address + 3.
long EEPROMReadlong(long address)
      {
      //Read the 4 bytes from the eeprom memory.
      long four = EEPROM.read(address);
      long three = EEPROM.read(address + 1);
      long two = EEPROM.read(address + 2);
      long one = EEPROM.read(address + 3);

      //Return the recomposed long by using bitshift.
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);

Don't drop it. Look at EEPROM.get(0 and EEPROM.put(). Quick and easy :wink:

don't worry about that part if you don't understand it. Just use the put() method - that will write any data (and read using get)

okay im looking at the arduino ide example sket, focusing on this part of the code,,

float f = 123.456f; //Variable to store in EEPROM.
int eeAddress = 0; //Location we want the data to be put.

do i need a different "int eeAddress = 0 for each vaariable?"

int eeAddress = 0
int eeAddress = 1
int eeAddress = 2?

and if im using longs is it valid to use

eeAddress += sizeof(long); //Move address to the next byte after float 'f'.
instead of
eeAddress += sizeof(float); //Move address to the next byte after float 'f'.

you can see the EEPROM as a line of boxes - each box can hold 1 byte. The put() function will look at how many bytes are needed for your parameter (for example 4 bytes for your float on a UNO) and if you ask to save your float starting at box #0 then it will fill Boxes #0 #1 #2 and #3.

if you want to save a second element you want to make sure you don't store it in a box that has already a value, you need to start in box #4.

when you do eeAddress += sizeof(float); this is exactly what you do: you take into account how many boxes were needed to store your float and you set the eeAddress to the next available box

so depending on the data type you store, you need to add the right number of bytes to the address (so indeed use long if what you stored is a long)

this becomes tedious, that's why if you put everything in a structure, then you can just put() the structure in EEPROM and all will be taken care of for you

J-M-L:
you can see the EEPROM as a line of boxes - each box can hold 1 byte. The put() function will look at how many bytes are needed for your parameter (for example 4 bytes for your float on a UNO) and if you ask to save your float starting at box #0 then it will fill Boxes #0 #1 #2 and #3.

if you want to save a second element you want to make sure you don’t store it in a box that has already a value, you need to start in box #4.

when you do eeAddress += sizeof(float); this is exactly what you do: you take into account how many boxes were needed to store your float and you set the eeAddress to the next available box

thankyou for clearing that up, so far with the EEPROM.put() i have come up with this is this okay? im not sure because i know originally it was designed for use of floats in this example?

/***
    eeprom_put example.

    This shows how to use the EEPROM.put() method.
    Also, this sketch will pre-set the EEPROM data for the
    example sketch eeprom_get.

    Note, unlike the single byte version EEPROM.write(),
    the put method will use update semantics. As in a byte
    will only be written to the EEPROM if the data is actually
    different.

    Written by Christopher Andrews 2015
    Released under MIT licence.
***/

#include <EEPROM.h>

struct MyObject {
  float field1;
  byte field2;
  char name[10];
};

void setup() {

  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

unsigned long t1ontimeDAY = 10700;                       /////
unsigned long t1offtimeDAY = 10000;  
unsigned long t2ontimeDAY = 13400;                       /////
unsigned long t2offtimeDAY = 10000; 
unsigned long t3ontimeDAY = 0;                           /////
unsigned long t3offtimeDAY = 0;  
unsigned long t1ontimeNIGHT = 10000;                     /////
unsigned long t1offtimeNIGHT = 50000;  
unsigned long t2ontimeNIGHT = 12400;                     /////
unsigned long t2offtimeNIGHT = 50000; 
unsigned long t3ontimeNIGHT = 10;                         /////
unsigned long t3offtimeNIGHT = 10;  //Variable to store in EEPROM
  int eeAddress = 0;   //Location we want the data to be put.


  //One simple call, with the address first and the object second.
  EEPROM.put(eeAddress, t1ontimeDAY);
  EEPROM.put(eeAddress, t1offtimeDAY);
  EEPROM.put(eeAddress, t2ontimeDAY);
  EEPROM.put(eeAddress, t2offtimeDAY);
  EEPROM.put(eeAddress, t3ontimeDAY);
  EEPROM.put(eeAddress, t3offtimeDAY);
  EEPROM.put(eeAddress, t1ontimeNIGHT);
  EEPROM.put(eeAddress, t1offtimeNIGHT);
  EEPROM.put(eeAddress, t2ontimeNIGHT);
  EEPROM.put(eeAddress, t2offtimeNIGHT);
  EEPROM.put(eeAddress, t3ontimeNIGHT);
  EEPROM.put(eeAddress, t3offtimeNIGHT);

  Serial.println("Written float data type!");

  eeAddress += sizeof(long); //Move address to the next byte after float 'f'.

}

void loop() {
  /* Empty loop */
}

okay so i stored the long variables in the eeprom with the first eeprom.put() i posted right above. but now when i read them it dont display the correct value?

#include <EEPROM.h>

void setup() {

 unsigned long t1ontimeDAY = 10700;                       /////
unsigned long t1offtimeDAY = 10000;  
unsigned long t2ontimeDAY = 13400;                       /////
unsigned long t2offtimeDAY = 10000; 
unsigned long t3ontimeDAY = 0;                           /////
unsigned long t3offtimeDAY = 0;  
unsigned long t1ontimeNIGHT = 10000;                     /////
unsigned long t1offtimeNIGHT = 50000;  
unsigned long t2ontimeNIGHT = 12400;                     /////
unsigned long t2offtimeNIGHT = 50000; 
unsigned long t3ontimeNIGHT = 10;                         /////
unsigned long t3offtimeNIGHT = 10;  //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from

  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Read float from EEPROM: ");

  //Get the float data from the EEPROM at position 'eeAddress'
  EEPROM.get(eeAddress, t1ontimeDAY);
  EEPROM.get(eeAddress, t1offtimeDAY);
  EEPROM.get(eeAddress, t2ontimeDAY);
  EEPROM.get(eeAddress, t2offtimeDAY);
  EEPROM.get(eeAddress, t3ontimeDAY);
  EEPROM.get(eeAddress, t3offtimeDAY);
  EEPROM.get(eeAddress, t1ontimeNIGHT);
  EEPROM.get(eeAddress, t1offtimeNIGHT);
  EEPROM.get(eeAddress, t2ontimeNIGHT);
  EEPROM.get(eeAddress, t2offtimeNIGHT);
  EEPROM.get(eeAddress, t3ontimeNIGHT);
  EEPROM.get(eeAddress, t3offtimeNIGHT);
  Serial.println(t1ontimeDAY);    //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
}
  /***
    As get also returns a reference to 'f', you can use it inline.
    E.g: Serial.print( EEPROM.get( eeAddress, f ) );
  ***/

  /***
    Get can be used with custom structures too.
    I have separated this into an extra function.
  ***/



void loop() {
  /* Empty loop */
}

J-M-L:
you can see the EEPROM as a line of boxes - each box can hold 1 byte. The put() function will look at how many bytes are needed for your parameter (for example 4 bytes for your float on a UNO) and if you ask to save your float starting at box #0 then it will fill Boxes #0 #1 #2 and #3.

if you want to save a second element you want to make sure you don't store it in a box that has already a value, you need to start in box #4.

when you do eeAddress += sizeof(float); this is exactly what you do: you take into account how many boxes were needed to store your float and you set the eeAddress to the next available box

so depending on the data type you store, you need to add the right number of bytes to the address (so indeed use long if what you stored is a long)

this becomes tedious, that's why if you put everything in a structure, then you can just put() the structure in EEPROM and all will be taken care of for you

you make it sound so easy i have no idea what im doing

Here is a quick example showing how I deal with this

#include <EEPROM.h>
// __attribute__ ((packed)) is to force the compiler to use the minimum required memory to represent the type
// see https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html
struct __attribute__ ((packed)) _paramS {
  int16_t minimumT;
  int16_t maximumT;
} myParamters;

const uint32_t keyword = 0xDEADBEEF;
const uint16_t keywordAddress = 0x00;
const uint16_t paramAddress = keywordAddress + sizeof(keyword);

void printParam()
{
  Serial.println(F("\n************* PARAMS *************"));
  Serial.print(F("Temp min =\t")); Serial.println(myParamters.minimumT);
  Serial.print(F("Temp max =\t")); Serial.println(myParamters.maximumT);
}

void saveParam()
{
  EEPROM.put(keywordAddress, keyword);
  EEPROM.put(paramAddress, myParamters);
}

void getParam()
{
  uint32_t tmpKey;

  EEPROM.get(keywordAddress, tmpKey);
  if (tmpKey == keyword) {
    EEPROM.get(paramAddress, myParamters);    // EEPROM was already initialized OK to read
  } else {
    // First run on this arduino, memory was never initialized. so establish default values
    myParamters.minimumT = -22;
    myParamters.maximumT = 44;
    saveParam();
  }
}


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

  getParam();  // first run will establish the defaults in EEPROM
  printParam(); // see what the values are

  myParamters.minimumT = -55;  // change one of the parameters
  saveParam(); // save it
  printParam(); // show it has been saved
}

void loop() {}

all the values I want to save are in the myParamters structure. in the setup() you call the getParam() function which will either read what is already there in EEPROM if the memory was already initialized or will write there default values and initialize the structure

every time you change the structure (one of your parameter) you just call saveParam() to update the EEPROM.

→ run the program with your serial console opened at 115200 bauds. first time you run the program you’ll see that default values are written, then the minimumT param is updated to -55° and if you run the code a second time (close and re-open the serial console for example) you’ll see that the second time the minimumT param will already be at -55° instead of -22°

  EEPROM.put(eeAddress, t1ontimeDAY);
  EEPROM.put(eeAddress, t1offtimeDAY);
  EEPROM.put(eeAddress, t2ontimeDAY);

Do you understand the concept of putting different values at different addresses?

J-M-L:
Here is a quick example showing how I deal with this

#include <EEPROM.h>

// attribute ((packed)) is to force the compiler to use the minimum required memory to represent the type
// see Using the GNU Compiler Collection (GCC)
struct attribute ((packed)) _paramS {
 int16_t minimumT;
 int16_t maximumT;
} myParamters;

const uint32_t keyword = 0xDEADBEEF;
const uint16_t keywordAddress = 0x00;
const uint16_t paramAddress = keywordAddress + sizeof(keyword);

void printParam()
{
 Serial.println(F("\n************* PARAMS *************"));
 Serial.print(F(“Temp min =\t”)); Serial.println(myParamters.minimumT);
 Serial.print(F(“Temp max =\t”)); Serial.println(myParamters.maximumT);
}

void saveParam()
{
 EEPROM.put(keywordAddress, keyword);
 EEPROM.put(paramAddress, myParamters);
}

void getParam()
{
 uint32_t tmpKey;

EEPROM.get(keywordAddress, tmpKey);
 if (tmpKey == keyword) {
   EEPROM.get(paramAddress, myParamters);    // EEPROM was already initialized OK to read
 } else {
   // First run on this arduino, memory was never initialized. so establish default values
   myParamters.minimumT = -22;
   myParamters.maximumT = 44;
   saveParam();
 }
}

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

getParam();  // first run will establish the defaults in EEPROM
 printParam(); // see what the values are

myParamters.minimumT = -55;  // change one of the parameters
 saveParam(); // save it
 printParam(); // show it has been saved
}

void loop() {}




all the values I want to save are in the `myParamters` structure. in the setup() you call the `getParam()` function which will either read what is already there in EEPROM if the memory was already initialized or will write there default values and initialize the structure

every time you change the structure (one of your parameter) you just call `saveParam()` to update the EEPROM. 

--> run the program with your serial console opened at 115200 bauds. first time you run the program you'll see that default values are written, then the `minimumT` param is updated to -55° and if you run the code a second time (close and re-open the serial console for example) you'll see that the second time the `minimumT` param will already be at -55° instead of -22°

i ran your example code but both times it printed the same thing on the console. can you show me an example with an unsigned long please?

TolpuddleSartre:

  EEPROM.put(eeAddress, t1ontimeDAY);

EEPROM.put(eeAddress, t1offtimeDAY);
  EEPROM.put(eeAddress, t2ontimeDAY);



Do you understand the concept of putting different values at different addresses?

i do not. i know nothing about memory addresses or byte arrays structure arrays or any of that.

what i need is an example using 2 different unsigned longs that when changed i can call a function and update them. i could probably work from something like that. i could call the update function from a serial command.

notsolowki:
i ran your example code but both times it printed the same thing on the console.

Probably the code ran once without you noticing (ie the serial console was not opened when you first uploaded)

notsolowki:
can you show me an example with an unsigned long please?

Well just put unsigned long in the structure...

struct __attribute__ ((packed)) _paramS {
  unsigned long minimumT;
  unsigned long maximumT;
} myParamters;

of course you need to adjust the values as you can't store -22 or -55 in an unsigned...

change the keyword to something else so that default values are written again

J-M-L:
Probably the code ran once without you noticing (ie the serial console was not opened when you first uploaded)

Well just put unsigned long in the structure...

struct __attribute__ ((packed)) _paramS {

unsigned long minimumT;
  unsigned long maximumT;
} myParamters;


of course you need to adjust the values as you can't store -22 or -55 in an unsigned...


change the keyword to something else so that default values are written again

your right it is working. i'm starting to figure it out i'm going to spend some time trial and error. thanks again

hey im back, when i run this code none of the default values are correct?

#include <EEPROM.h>
// __attribute__ ((packed)) is to force the compiler to use the minimum required memory to represent the type
// see https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html
struct __attribute__ ((packed)) _paramS {
  unsigned long minimumT;
  unsigned long maximumT;
  unsigned long maximumA;
  unsigned long maximumB;
  unsigned long t1ontimeDAY;                       /////
  unsigned long t1offtimeDAY;  
  unsigned long t2ontimeDAY;                       /////
  unsigned long t2offtimeDAY; 
  unsigned long t3ontimeDAY;                           /////
  unsigned long t3offtimeDAY; 
   
  unsigned long t1ontimeNIGHT;                     /////
  unsigned long t1offtimeNIGHT;  
  unsigned long t2ontimeNIGHT;                     /////
  unsigned long t2offtimeNIGHT; 
  unsigned long t3ontimeNIGHT;                         /////
  unsigned long t3offtimeNIGHT;
} myParamters;

const uint32_t keyword = 0xDEADBEEF;
const uint16_t keywordAddress = 0x00;
const uint16_t paramAddress = keywordAddress + sizeof(keyword);

void printParam()
{
  Serial.println(F("\n************* PARAMS *************"));
  Serial.print(F("Temp minn =\t")); Serial.println(myParamters.t1ontimeDAY);
  Serial.print(F("Temp maxx =\t")); Serial.println(myParamters.t2ontimeDAY);
  Serial.print(F("Temp max =\t")); Serial.println(myParamters.maximumB);
}

void saveParam()
{
  EEPROM.put(keywordAddress, keyword);
  EEPROM.put(paramAddress, myParamters);
}

void getParam()
{
  uint32_t tmpKey;

  EEPROM.get(keywordAddress, tmpKey);
  if (tmpKey == keyword) {
    EEPROM.get(paramAddress, myParamters);    // EEPROM was already initialized OK to read
  } else {
    // First run on this arduino, memory was never initialized. so establish default values
    myParamters.t1ontimeDAY = 1002001;
    myParamters.t1offtimeDAY = 1002002;
     myParamters.t2ontimeDAY = 1002001;
    myParamters.t2offtimeDAY = 1002002;
        myParamters.t3ontimeDAY = 1002001;
    myParamters.t3offtimeDAY = 1002002;
        myParamters.t1ontimeNIGHT = 1002001;
    myParamters.t1offtimeNIGHT = 1002002;
        myParamters.t2ontimeNIGHT = 1002001;
    myParamters.t2offtimeNIGHT = 1002002;
        myParamters.t3ontimeNIGHT = 1002001;
    myParamters.t3offtimeNIGHT = 1002002;
    saveParam();
  }
}


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

  getParam();  // first run will establish the defaults in EEPROM
  printParam(); // see what the values are

  myParamters.minimumT = 1002001;  // change one of the parameters
  myParamters.maximumB = 1002011;  // change one of the parameters
  saveParam(); // save it
  printParam(); // show it has been saved
}

void loop() {}

or is it that this part don’t run unless there is a problem reading from eeprom?

  EEPROM.get(keywordAddress, tmpKey);
  if (tmpKey == keyword) {
    EEPROM.get(paramAddress, myParamters);    // EEPROM was already initialized OK to read
  } else {