Writing numbers bigger than 1 byte to EEPROM

Hi, im just working on a simple project for adding a pitch bend wheel (via midi) to a korg microsampler. to get it to work properly, i need to be able to calibrate it. long story short, i need to store a number bigger than 1 byte in eeprom, or i need an easy way to convert a 2-byte number to two 1-byte numbers (with significance) to store in each their eeprom address.

i found this: http://arduino.cc/playground/Code/EEPROMWriteAnything

but it seems a little over the top for just storing one 16bit number.

anyone?

also the playground page on http://arduino.cc/playground/Code/EEPROMWriteAnything mentions plans of including those functions into future versions of arduino IDE has it happened? will it happen?

I'd just use EEPROMWriteAnything. If you really don't want to use it you're going to have to split your 16bit number apart using bit operations.

allright, then how do i use the write anything code?

if i simply add the code from the playgwound at the top of the sketch (as illustrated below) i get the following compliler error (the sketch is called “pitchbendwheel”):
pitchbendwheel:-1: error: expected ‘,’ or ‘…’ before ‘&’ token
pitchbendwheel:-1: error: ISO C++ forbids declaration of ‘T’ with no type
pitchbendwheel:0: error: ‘T’ has not been declared

#include <MIDI.h>

// Here is what is copy pasted from the playground page
#include <EEPROM.h>

template 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 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;
}

//End of code pasted from playground

const int PBpin = 0;
int PBval = 10000;
int oldPBval;
int ACTUALCENTER;
byte CHANNEL = 1;
int DIFF = 0;
boolean firstRun = true;
int deadZone = 300;
int onTime = 0;

void setup() {
MIDI.begin();
}
void loop(){
if (firstRun == true){
//eeprom read code goes here
}

PBval = map(analogRead(PBpin),50,1024-50,0,16383)-DIFF;
PBval = constrain(PBval, 0, 16383);
if ((PBval > (8192-deadZone/2))&& (PBval < (8192+(deadZone/2)))){
PBval = 8192;
}
if(PBval != oldPBval){
digitalWrite(13,HIGH);
MIDI.sendPitchBend((unsigned int) PBval,1);
oldPBval = PBval;
onTime = millis();
digitalWrite(13,LOW);
if (digitalRead(10)==HIGH){
digitalWrite(10,HIGH);
onTime = millis() - 1000;
ACTUALCENTER = map(analogRead(PBpin),50,1024-50,0,16383);
DIFF = ACTUALCENTER - 8192;
}
}
if (millis()>(onTime + 100)){
digitalWrite(13,LOW);
}
}

Use this code.

void EEPROM_writefloat(float value)
{
  byte* p = (byte*)(void*)&value;
  for (int i = 0; i < sizeof(value); i++)
    EEPROM.write(ee++, *p++);
}

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

If your variable is a double just replace “float” with “double”.

If all you need to store are two-byte integer values, then it can be simple.

You can convert the int to bytes and call EEPROM write function (twice) with those arguments. Then read the bytes back one at a time and combine them with shift and logical operations.

Be consistent. If you store lower byte first, read lower byte first. If you store upper byte first, read upper byte first. (Your choice.)

    int x = 23456;
    Serial.print("x = ");Serial.print(x);
    Serial.print(" = 0x");Serial.println(x,HEX);

    // Break x into upper and lower bytes
    byte xlo = x;      // It automatically stores the lower bits of x
    byte xhi = x >> 8; // It stores the upper bits of x

    // Here you would store the bytes one at a time by calling EEPROM write function
    // I'll just show what would be stored.
    
    Serial.print("Lower bits = 0x");Serial.println(xlo,HEX);
    Serial.print("Upper bits = 0x");Serial.println(xhi,HEX);
    
    // Put the bytes back together
    // Here you would read xloand xhi by separate calls to the EEPROM read routine.
    // I'll just use the previous values
    int y;
    y = (xhi << 8) | xlo;
    Serial.print("y = ");Serial.print(y);
    Serial.print(" = 0x");Serial.println(y, HEX);

Output would look something like


x = 23456 = 0x5BA0
Lower bits = 0xA0
Upper bits = 0x5B
y = 23456 = 0x5BA0

Regards,

Dave

Nice! thanks, thats just what i was looking for! I should probably try to wrap my head around the writeAnything code for later use but for now those simple bitwise operations will keep hings nice and simple! :)

@CptCredible: Your example posted earlier (minus the Midi library I don't have) compiles fine under 0021 - what are you using?

i am using 0022

what is "template " supposed to do?

It just anonymises whatever data type you want to write to the EEPROM, and makes the function transparent to the user - you simply provide the variable, and the compiler does the rest. Or it should do... I've used it since about 0016 without problems, but haven't yet updated to 0022 from 0021.

I'll try and post a simplified test program.

AWOL:
@CptCredible:
Your example posted earlier (minus the Midi library I don’t have) compiles fine under 0021 - what are you using?

Sigh…
Arduino compiles things in a different order in arduino-0022 than it did in previous releases, so that particular example requires a little more work. Crap!

Anyhow, here’s the drill for current users:
Open a new tab in your sketch. Give it an appropriate name, maybe EEPROMAnything.h

Paste the following into the tab window

#include <WProgram.h>
#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;
}

Now, back in your main sketch window your program looks like this:

#include <EEPROM.h>
#include "EEPROMAnything.h"
.
.
.
// Whatever you need to do with stuff into and out of eeprom

The playground example shows how to write and read some kind of struct.

Here’s how you would use it to read and write integers. The main sketch could look like:

#include <EEPROM.h>
#include "EEPROMAnything.h"

void setup()
{
    Serial.begin(9600);
    int x = 12345;
    EEPROM_writeAnything(0, x);
    x = -4321;
    EEPROM_writeAnything(2, x);
}

void loop()
{
    int z; // This will hold the value from EEPROM
    
    // I could just use 0 and 2 for addresses to read from,
    // but lots of times we use variables, so...
    int address = 0;

    EEPROM_readAnything(address, z);
    Serial.print("From address 0: z = ");Serial.println(z);
    
    address += 2;
    EEPROM_readAnything(address, z);
    Serial.print("From address 2: z = ");Serial.println(z);
    Serial.println();

    delay(10000);
}

Output:


[color=blue]From address 0: z = 12345
From address 2: z = -4321[/color]

Regards,

Dave

Footnote:
In “real C++” I ordinarily put templates in separate files, so creating a .h file for the function templates is no big deal. For new Arduino users, it’s too bad that the latest version of Arduino makes us have to do this (that’s what happens when we create a tab in a sketch), but that’s the way it goes…

Anyhow, whoever wrote the playground article is now faced with a task to update it so that it gives instructions (and, maybe ,reasons) that it’s not as simple as it seems. Oh, well…

Try:

#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;
}

float x = 355.0/113.0;
float y;

void setup() 
{
  Serial.begin (9600);
  EEPROM_writeAnything(0, x);
  EEPROM_readAnything (0, y);
  Serial.println (y);
}
void loop()
{
}

EDIT: Posted this while Dave was posting his - his looks better!

AWOL:
It just anonymises whatever data type you want to write to the EEPROM, and makes the function transparent to the user - you simply provide the variable, and the compiler does the rest.
Or it should do…
I’ve used it since about 0016 without problems, but haven’t yet updated to 0022 from 0021.

I’ll try and post a simplified test program.

For some unexplained reason WriteAnything won’t compile in IDE version 22. This came up about a month ago. Someone did come up with a work around, you have to add the class to a tabbed section and then include it in the main sketch, like so:

class put into a tabbed file called eetest.h

#include <WProgram.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;
}

Then main example sketch:

#include <EEPROM.h>
#include "eetest.h"

struct config_t
{
    long alarm;
    int mode;
} configuration;


void setup()
{
    Serial.begin(9600);
/*
    configuration.alarm = 12345678;  // comment out after inital eeprom written
    configuration.mode = 1;          // same

    // Write the configuration struct to EEPROM
   EEPROM_writeAnything(0, configuration);  // comment out after first written
   
// above three code lines could be a function in main sketch to save something away.
*/
}

void loop()
{
    // Read and print the contents of EEPROM
    EEPROM_readAnything(0, configuration);    
    Serial.print("alarm  = ");Serial.println(configuration.alarm);
    Serial.print("mode   = ");Serial.println(configuration.mode);

   // A "do nothing loop" where your real working code would be
    while(1)
     ;
}

Lefty

Instead of having to create a new tab and copy that template stuff for each and every sketch that is going to use this, you can do the following, as I have now done:

In your Arduino libraries directory, create a new subdirectory. Call it, say, EEPROMAnything. Navigate to that directory, and with your favorite programming editor (probably vim, right?), create a file named EEPROMAnything.h (For sanity’s sake, give it the same name as the directory, but with the .h suffix.)

Paste the template code from my previous example to EEPROMAnything.h Not the main sketch, just the template stuff. (Don’t forget the #include <WProgram.h> directive.)

If the Arduino IDE is open, close it.

Open the Arduino IDE and create a new sketch that is like the one that I showed. You don’t need the tab stuff here, because now you have a library that will be included when the sketch is compiled. (See Footnote.)

Ta-daa!

Regards,

Dave

Footnote: Here’s a way to make sure that Arduino can find your new library:

Create the main sketch without the #include “EEPROMAnything” directive (or comment it out), but, (And this is important. Really): You do still need the #include <EEPROM.h> directive in your main sketch. Really.

Now from Arduino Sketch->Import Library menu you should see your new library. Click on it and you will get the following statement at the top of your sketch:

#include <EEPROMAnything.h>

Ta-daa! (But I already said that.)

Let’s do one more thing.

Now, under the EEPROMAnything directory, create a subdirectory named examples

Navigate to that subdirectory and create another subdirectory. Name it, say Ints

Navigate to that subdirectory and use your text editor to create a file named Ints.pde (Must be same name as its directory, but with the .pde suffix.) Paste my little EEPROM integer write/read sketch into that file. You have already run this, so you know it works.

The next time you open the Arduino IDE, select the File->Examples menu item. You should see the EEPROMAnything library with a little triangle, and you should be able to select Ints and see the sketch open up.

(I won’t say “Ta-daa” again, but you know…)

Finally (I promise. Really):

Heck, since the EEPROM library is part of the standard Arduino distribution and the Anything functions are so handy (and can’t just be pasted directly in your main sketch anymore as documented in the playground), maybe the Arduino developers could even make the Anything functions part of the distribution. How about it? Would there be a downside to that?

Thanks! i think it would be a great idea to implement this into the Arduino IDE, but for now ill make a library like you said, hooray!!1