Saving to internal eeprom

Hi,

I have about 40 Byte variables, each with quiet different names for clarity.
They can all be user modified and when thats done I need to save them all to internal eeprom.

I can write each variable using EEPROM.write(addr, var); but that need repeating 40 times for each variable.

Seems I would have to do the same to Read back / restore them as well.

Is there an easier way ?

thanks

Direct, no. Are those 40 bytes really all different variables? Or do you have a lot of setting1, setting 2 etc? In other words, an array is the answer. But if you think all the settings are really different you can fake an array but it will take some memory by making a pointer array to all variables

byte myByte = 5;
byte anotherByte = 10;
byte yetAnother = 100;

byte *const myArray[] = {&myByte, &anotherByte, &yetAnother};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  for(byte i = 0; i < sizeof(myArray) / sizeof(myArray[0]); i++){
    Serial.println(*myArray[i]);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Did use Serial to loop trough them as a demo but you can use EEPROM.update or something there. (Please use update instead of just writing everything to extend EEPROM life.) Now you can use the pointer array to loop through all of them but you have to make (thus type) an array with all the variable names and it will take 80 bytes in progmem.

Not really. You could do something like this:

enum
{
    myFirstVar = 0,
    mySecondVar,
    anotherVar,
    moarVars,
    numVars // <-- keep this one last
};

byte    allMyVars[numVars];

void setup()
{
    restoreVars();
}


void loop()
{
    // ...
    
    doSomething(allMyVars[myFirstVar]);
    allMyVars[mySecondVar] = 4;
    
    if (something)
        storeVars();
    // ...
}

void storeVars()
{
    int i;
    
    for (i = 0;i < numVars;i++)
        EEPROM.write(i,allMyVars[i]);
}

void restoreVars()
{
    int    i;

    for (i = 0;i < numVars;i++)
        allMyVars[i] = EEPROM.read(i);
}

Altho this makes your store/restore functions very small and clean, the extra clutter it brings to the rest of your code is probably not worth it.

Along the lines suggested by Jobi-Wan, you could use symbolic constants for the index names:

#define ELEMENTS(x)   (sizeof(x) / sizeof(x[0]))   // typeless macro for array element count

#define FIRSTVAR          0
#define SECONDVAR         1
#define THIRDVAR          2
// ...more in list
#define LASTVAR          39

and then stuff the array suggested by septillion with the values. It doesn't change anything in terms of memory, but is simply an alternative. Also, I think the definition of allMyVars[] needs to be changed to:

byte    allMyVars[numVars + 1];

Otherwise, the desired array count is off by one.

If you want to use macro’s I would change it to:

byte allMyVars[] = {5, 10, 100};

#define ELEMENTS(x)   (sizeof(x) / sizeof(x[0]))   // typeless macro for array element count
#define myByte      allMyVars[0]
#define anotherByte allMyVars[1]
#define yetAnother  allMyVars[2]

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  for(byte i = 0; i < ELEMENTS(allMyVars); i++){
    Serial.println(allMyVars[i]);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

By making a list of macro’s to the variable name now it’s easy to modify. You don’t need to modify the rest of the code. But as var as readability, mm.

You could put all the different type variables in a struct, and use the EEPROM_readAnything and EEPROM_writeAnything functions to read/write the struct.

http://playground.arduino.cc/Code/EEPROMWriteAnything

@septillion: Clearly, that will work, but what if you want to change the name of the array at some future time? Then you end up with a lot of edits or global search-and-replace, which always seems to bite me in the butt whenever I use it.

Why would you want to do that? And changing the name of the array is not harder then changing any variable name now. I even think it's easier because it's only used in the list of define and in the EEPROM store/recover part. As where the rest of the vars may be spread across the code. So I don't see the problem...

Thanks all, plenty of options for me to try there.

@septillion: There are many reasons why I might change the name of an array (conflicts with other modules or libraries, coding style requirements of stakeholder, etc.). With your style,

byte allMyVars[] = {5, 10, 100};

#define ELEMENTS(x)   (sizeof(x) / sizeof(x[0]))   // typeless macro for array element count
#define myByte      allMyVars[0]
#define anotherByte allMyVars[1]
#define yetAnother  allMyVars[2]

if I change the array name, I must also edit each #define in the program. To me, the fewer the number of times I touch the source code during an edit, the better. Also, using the symbolic constants focuses the attention on the fact that all of the data are stored in a single array, but it is the elements of the array that hold the distinctions. Your approach makes it appear that the data are stored in different variables. In a large, complex, program, this makes debugging more difficult.

But you should not see my code as source code, it's an example. The real source is the program of ricky. So the choice of variable names is just for the example. And for the variable name in the real program, just use a name that you find okay and use it. After writing more code (like making all the macros) it's as hear as any variable to rename it. So again, I don't see why the "it's hard to rename the array" is of any value here....

econjack:
Your approach makes it appear that the data are stored in different variables. In a large, complex, program, this makes debugging more difficult.

That's true, that's why I mentioned the readability. But it's easy to implement in current code and does not consume memory. If I would have to start from scratch I would have thought of a different way. I think I would use your way with an array and macro's as pointers. But for now THAT option means a lot of variable renaming...

The struct way is cool but a disadvantage is that it always writes all. At least when you use get() and put(). If you follow the write anything way you can make it use a read before write style (like the update()). But in this case, you still have to rename the current variables...

econjack:
Also, I think the definition of allMyVars[] needs to be changed to:

byte    allMyVars[numVars + 1];

Otherwise, the desired array count is off by one.

Nope. Only if you want to use numVars as one of the variables. That is not the intention.
Then you would also need to change the loops in the (re)store functions to include numVars (change the < into a <= ).

@Jobi-Wan:

Nope. Only if you want to use numVars as one of the variables.

…which would be the normal use for a member of an enum. If you plan on using it as an “element counter”, then at least change your comment to make its use more clear:

enum
{
    myFirstVar = 0,
    mySecondVar,
    anotherVar,
    moarVars,
    numVars // <--- This member tracks the number of "usable" enums in the array
};

I did not see its usage in your code…I could not compile it.