Data saved when power off

I am currently working on a project where my max output levels can be adjusted via 2 buttons, which change a motor output up and down. The motor speed is scaled from a potentiometer input, and those values are mapped to output values as a percent of the max value. I want to know if it is possible for the max value to be stored between Arduino power-offs. It’s for a simple car, and I want the max speed to not reset each time it is turned off. I was wondering if there was some kind of way to have the code re-save itself with the new max value. The code is attached below, and the max resets every startup at 255. I am running an Arduino Nano, and Arduino IDE 1.8.9 on macOS Mojave. Any help is appreciated, thanks.

//pin declarations
const int in1 = 2;
const int enA = 3;
const int in2 = 4;
const int reading = A0;
const int button1 = 5;
const int button2 = 6;
//variables
int maxValue = 255;
int outputValue;
bool button1pressed = false;
bool button2pressed = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(reading, INPUT);
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  outputValue = map(analogRead(reading), 0, 1023, 0, maxValue); // inputs digital read (0-1023) and outputs 0-the max value
  analogWrite(enA, outputValue); // pwm output to motor controller
  digitalWrite(in1, HIGH); // sending direction to motor controller
  digitalWrite(in2, LOW);
  
  if (digitalRead(button1) == HIGH && !button1pressed) // have to press and release for buttons to trigger
  {
    button1pressed = true;
  }
  if (digitalRead(button1) == LOW && button1pressed)
  {
    maxValue += 5; // increase max if pressed and released
    button1pressed = false;
  }
  if (digitalRead(button2) == HIGH && !button2pressed)
  {
    button2pressed = true;
  }
  if (digitalRead(button2) == LOW && button2pressed)
  {
    maxValue -= 5; // decrease max if pressed and released
    button2pressed = false;
  }
  if (maxValue < 0)
  {
    maxValue = 0; // lowest max can be
  }
  if (maxValue > 255)
  {
    maxValue = 255; // highest max can be
  }
}

During the execution of the sketch, sense the power failure and then save the maxValue into the internal EEPROM of the MCU. When power resumes (startup phase of the MCU), the first task would be to read the saved value from the EEPROM and update the maxValue variable.

How

GolamMostafa:
During the execution of the sketch, sense the power failure

How? Especially due to the OP to the best of my knowledge not having any form of backup power for the Arduino, even not for the 10-20 ms or so it takes to write to EEPROM.

Maybe better to write the new value to EEPROM every time it's changed (of the buttons, not the pot, as the pot is simply read directly upon startup).

You have at least 100,000 writes to a single sector of the EEPROM. That should be more than enough for your application, even when writing upon every single button press.

Thanks, for now I will just have it write after each button press. If you know how to have it read a power sense failure without any power failure systems in place that would be awesome, but I don't think it's possible. Thank you.

Sensing power failure is easy: measure the supply voltage.

Keeping running long enough after that supply voltage collapses is the tricky part. You also have to program for checking for power failure often enough so you can actually react to it.

Power supply >diode> big capacitor > Arduino .
Measure power supply upstream of the diode and when it falls write data to eeprom.

Might just do it with 100uF on the 5v input ?

Mmm… Might do indeed.

An EEPROM write takes 3.3 ms per byte. OP would have to write one byte, so that’s the time needed. Plus reading the analog input, 3.4 ms for this process. Add a few ms for the loop() to run and do the measurement. To be safe, 10 ms.

Now assume the battery supplies 12V, after the diode 11.3V left. The cap has to keep the supply voltage at over 6.5V for the regulator to continue working properly (I assume using the internal regulator). At 25 mA current draw (crude estimate) that 100µF cap would offer 20-30 ms of current.

That should be enough indeed.

Actually, instead of reading an analog input, maybe better to use a digital read. After all upon power disconnection the reading drops to zero, and with power the reading is almost 5V (I’d aim for ~4V at the pin). This even allows the use of an interrupt which gets triggered when the power goes out. 4 ms of remaining power is then enough to write that single byte to EEPROM.

wvmarle:
How?

1. The following circuit could be exercised to see that the MCU does save data in its internal EEPROM during power fail/switch OFF. The power failure/switch OFF condition could be detected either by polling the PD2-pin or being interrupted.
pwrF.png

2. However, another issue is to kept in mind that the EEPROM is prone to get erratically written at random locations when the Vcc supply goes below about 3.4V. Brown out detection level could be properly chosen via fuse bit setting of the MCU so that the MCU enters into reset condition when the Vcc supply falls below 3.4V and thus prevents the EEPROM from getting written erratically.

pwrF.png

That 3.4V must have to do with the 16 MHz clock frequency (which requires >4.3V or so according to the data sheet), as the EEPROM works just fine for 3.3V projects.

ian-northpb:
Thanks, for now I will just have it write after each button press.

Advanced move would be to just update the stored max value in eeprom after a suitable time frame when the buttons are no longer being pressed. I generally view 5-10 seconds of inactivity as a good “store” point. If your project has some sort of display, start blinking while in “program” mode and after you do the eeprom write, switch back to solid.

If the power goes out while your adjusting the speed, it’s pretty clear your going to need to continue to adjust after power comes back on.

No extra hardware needed.

Also, good to have the first button press simply put the program into program mode, start the blinking and ignore button pushes for 1-2 seconds. That help minimize accidental hits on the buttons from adjusting speed unintentionally.