writing and reading min and max analog values to and from eeprom

Right now I am reading 0-5v value on A0 and converting them to analog output of 0-1v. The input values can start at anything, example .5v and max value could be 3.5v. Right now I am running 2 POTs to set my min and max values and it works great. I'd like to know if I can write min and max values to the eeprom when arduino gets powered up and lets say calibration button is pressed and then able to read those values and not have to calibrate min and max values every time the unit powers up?

Thanks.

Welcome on the forum,

Yes of course you can read and write them to EEPROM.

There are a number of things to consider:

  1. you should be able to detect that there is in fact a valid min max in EEPROM. EEPROM contains by default 255 on all addresses so that should be relative easy to detect.

  2. you can store the raw analogRead values in EEPROM (2 integers = 4 bytes in total) or you can store the voltage (2 floats = 8 bytes in total. Both make sense.

  3. you should think when the values are read from EEPROM. in setup() or in loop() . The code needed will be quite different.

For EEPROM code you should read - Arduino Playground - EEPROMWriteAnything -

hope this helpes,

@Rob, OP

The EEPROM library now contains put() & get(), these functions allow writing and reading objects of any size, producing the same functionality as EEPROMWriteAnything.

Once you have the button code and your program flow sorted out, the EEPROM usage is an easy addition.

Here is a simple look at whats needed to utilize the EEPROM.

#include <EEPROM.h>

struct EEPROMData{
  int analogMin;
  int analogMax;
};

EEPROMData settings; //Instance of data, does not need to be global (re-read when needed).

int index = 0; //EEPROM address.

void setup(){

  //Get calibration
  EEPROM.get( index, settings );

  //Do something with data.
  Serial.println( settings.analogMin );
  Serial.println( settings.analogMax );

  //Input new settings
  settings.analogMin = ?; //Wherever you obtain your values
  settings.analogMax = ?; //Wherever you obtain your values

  //Save calibration.
  EEPROM.put( index, settings );
}

void loop(){}

Thanks, did not see put get before. learned something today :wink:

update: in 1.5.8 (which I use) put & get() is not supported yet ...

No, I re-wrote the library when 1.6.0 was released, and it was added in 1.6.2

The reference is still currently incomplete. The lib also contains EEPROM.length()

link to the complete library?

https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/libraries/EEPROM

If you scroll down, there is documentation and links to the examples.

@Pyro
Some examples "exhaust" the EEPROM within a few days (e.g. update example).
Think moving tests from loop() to setup() - run once - might be wise.

I'd read the EEPROM in setup() only, and write it only when a calibration command (button...) is given. The calibration routine will know how to obtain the new calibration values.

robtillaart:
@Pyro
Some examples "exhaust" the EEPROM within a few days (e.g. update example).
Think moving tests from loop() to setup() - run once - might be wise.

The ones that are important do use setup (no delay), however the update example is a simple copy of the already existing write example. I can add a change into the update which is waiting to be merged in.

nice, will work on it!!

I couldn't figure it out so ended up sticking with 2 potentiometers to dial min and max value. Now it is working, but there is a variation on the analog output of about 5%, it jumps around back and forth, is there any way to get it down to 1% or so?

Here's my code using 2 potentiometers to set min and max value. How do I go about implementing eeprom write with a button aka calibrating, and then reading the values? Thanks.

code.txt (1.23 KB)

Start a new sketch get a button working how you want, use Serial.print to print out when you are expecting to read and write the EEPROM. The EEPROM is the easy part, you'll need your button working correctly before you continue.

Start a new sketch, try the EEPROM examples, including the one I posted above.
In the IDE you'll find the examples:

eeprom_get
eeprom_put

Once again, keeping it simple, combine the too in a third sketch.

If you do not understand whats happening, or does not work, repeat!

I don't think anyone is going to write your sketch for you if you aren't going to understand it.

This one only stores 255 in min and max

*/
#include <EEPROM.h>

int addr = 0;
// These constants won't change:
const int sensorPin = A0; // pin that the sensor is attached to
const int ledPin = 9; // pin that the LED is attached to
const int buttonPin = 8; // pin that button attached to
int buttonState =0;
// variables:
int sensorValue = 0; // the sensor value
int sensorMin = 1023; // minimum sensor value
int sensorMax = 0; // maximum sensor value

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

// turn on LED to signal the start of the calibration period:

pinMode(buttonPin, INPUT);
buttonState = digitalRead(buttonPin);
// calibrate during the first five seconds
while(buttonState ==HIGH) {
sensorValue = analogRead(sensorPin);

// record the maximum sensor value
if (sensorValue > sensorMax) {
sensorMax = sensorValue;
}

// record the minimum sensor value
if (sensorValue < sensorMin) {
sensorMin = sensorValue;
}
}
EEPROM.write(0, (sensorMin)/4);
delay(100);
EEPROM.write(1, (sensorMax)/4);
delay(100);

}

void loop() {
// read the sensor:
sensorValue = analogRead(sensorPin);
sensorMin=EEPROM.read(0)*4;
sensorMax=EEPROM.read(1)*4;
// apply the calibration to the sensor reading
sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 51);

// in case the sensor value is outside the range seen during calibration
sensorValue = constrain(sensorValue, sensorMin, sensorMax);

// fade the LED using the calibrated value:
analogWrite(ledPin, sensorValue);
}

I have modified your code and added some comments.

The change to using EEPROM.get()/put() was quite easy.

The only big thing to note is the addresses used to read/write the data have to be spaced, as an int is two bytes it'll occupy both cell 0 and 1.

I have used #defines to separate the elements and make it easy to reference them in code.

#include <EEPROM.h>

int addr = 0; 
// These constants won't change:
const int sensorPin = A0;    // pin that the sensor is attached to
const int ledPin = 9;        // pin that the LED is attached to
const int buttonPin = 8;  // pin that button attached to
int buttonState =0;
// variables:
int sensorValue = 0;         // the sensor value
int sensorMin = 1023;        // minimum sensor value
int sensorMax = 0;           // maximum sensor value

/***
  These defines contain the addresses for the EEPROM.

  As the data is greater than 1 byte, using a chain of defines
  can help ensure no data is overlapping something else.
***/

#define ADDR_MIN_VAL         0 //Starts at address zero.
#define ADDR_MAX_VAL         ADDR_MIN_VAL + sizeof(sensorMin) // Use the next free space.
#define ADDR_SOMETHING_ELSE  ADDR_MAX_VAL + sizeof(sensorMax) // Continue chain increasing the offset


void setup() {
  Serial.begin(9600);
  
  // turn on LED to signal the start of the calibration period:

  pinMode(buttonPin, INPUT);
  buttonState = digitalRead(buttonPin);
  // calibrate during the first five seconds
  while(buttonState ==HIGH) {
    sensorValue = analogRead(sensorPin);

    // record the maximum sensor value
    if (sensorValue > sensorMax) {
      sensorMax = sensorValue;
    }

    // record the minimum sensor value
    if (sensorValue < sensorMin) {
      sensorMin = sensorValue;
    }
  }

  /***
  EEPROM.write(0, (sensorMin)/4);
  delay(100);
  EEPROM.write(1, (sensorMax)/4); 
  ***/
   
  EEPROM.put(ADDR_MIN_VAL, sensorMin);
  delay(100);
  EEPROM.put(ADDR_MAX_VAL, sensorMax);

  delay(100);
 
}

void loop() {
  // read the sensor:
  sensorValue = analogRead(sensorPin);

  
 /*** sensorMin=EEPROM.read(0)*4; ***/
 /*** sensorMax=EEPROM.read(1)*4; ***/

  EEPROM.get(ADDR_MIN_VAL, sensorMin);
  EEPROM.get(ADDR_MAX_VAL, sensorMax);
  
  // apply the calibration to the sensor reading
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 51);

  // in case the sensor value is outside the range seen during calibration
  sensorValue = constrain(sensorValue, sensorMin, sensorMax);

  // fade the LED using the calibrated value:
  analogWrite(ledPin, sensorValue);
}

I saw what you did that, that was pretty smooth. I have few questions, there won't be anything else written on the eeprom besides min and max values, they might be getting re written once I move it to another sensor with different mix and max values, what is the reason for using

#define ADDR_SOMETHING_ELSE ADDR_MAX_VAL + sizeof(sensorMax) // Continue chain increasing the offset
?
I understand what it does. If I am going to calibrate it 2nd time or so, is the data written to 0 address and the next available address? or is it going to go as a string till it reaches 512 and then resets?

Thanks.

It didn't work.

What does not work?
Was it working before?

I only changed the EEPROM stuff, I didn't read through the rest of your code, however you do have a problem with it.

Here is what I see:

If you aren't pressing the button on startup, the setup function still writes the EEPROM data (you need to move it into the calibration routine).
Because of this, the minimum is 1023, while the max is 0.
Then in the loop, you map the sensor value to min and max, which are the wrong way around.

If you are holding the button, then some valid readings are set (but are overwritten the next time you restart without pressing the button).

I am redoing the code, it wasn't working before, but I think I am on the right track now.

I went back to basics and did calibration only without eeprom, and it worked on the serial, now I am implementing eeprom into that.

Thanks for your help, I will update it as soon as I am done with it.