For a simple sequencing counter loop, with LEDs turned on and off on button presses, if the power is turned off and on again how can I get it to resume from the last count sequence? I presume by writing to an eeprom, but how? What data is written?
The obvious data to write is your counter variable. What data type is it and how often do you anticipate it changing ?
I am using buttonPushCounter++ and if (buttonPushCounter == 1) {} etc for each count. Then ERPROM.write for each, and EEPROM.read in setup
I need to find a Win 10 pc because I can’t reply with Win 7, having to use my phone and unable to upload any code
Sorry, either step through the sequences until on the required one, may not change again that day, or, it may step through every 5 minutes
How many bytes need to be saved?
Good idea. What is the problem?
You might want to use put() and get() depending on the type of your counter
Something like this ?
#include <EEPROM.h>
constexpr byte buttonPin = 2;
constexpr byte ledPins[] = {3, 4, 5};
constexpr byte numLeds = sizeof ledPins / sizeof *ledPins;
constexpr int counterAddr = 0;
constexpr uint32_t markerVal = 0x600DC0DE;
constexpr int markerAddr = counterAddr + sizeof counter;
int counter = 0;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
constexpr unsigned long debounceDelay = 50;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
for (byte i = 0; i < numLeds; i++) pinMode(ledPins[i], OUTPUT);
uint32_t storedMarker = 0;
EEPROM.get(markerAddr, storedMarker);
if (storedMarker == markerVal) {
EEPROM.get(counterAddr, counter);
if (counter >= numLeds) counter = 0;
} else {
counter = 0;
EEPROM.put(counterAddr, counter);
EEPROM.put(markerAddr, markerVal);
}
for (byte i = 0; i < numLeds; i++) digitalWrite(ledPins[i], i == counter ? HIGH : LOW);
}
void loop() {
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) lastDebounceTime = millis();
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading == LOW && lastButtonState == HIGH) {
counter = (counter + 1) % numLeds;
for (byte i = 0; i < numLeds; i++) digitalWrite(ledPins[i], i == counter ? HIGH : LOW);
EEPROM.put(counterAddr, counter);
}
}
lastButtonState = reading;
}
Typed here on my iPhone, so mind typos
You can use Supermium (or Thorium Browser maybe) instead of Chrome or Firefox. It is up to date and works with the new forum flawlessly...
Asking you for feedback... because EEPROM has a 100,000 write/erase-life, would EEPROM.update() be a better choice over EEPROM.write()? ("update" reads, compares data, and only writes if data is different).
Well I know it’s different as I just incremented it.
Also it’s human driven, so hopefully OP won’t press the button 100,000 times ![]()
A better solution would be to add a strong enough capacity and monitor power supply. If power goes away, then you have the time to save the counter to eeprom before the arduino shuts down. This way you idont write very often to the eeprom.
I will try one of those browsers in the morning then I can upload my sketch that I have got so far. Thanks everyone
If the counter is a multi byte variable then using update() or put() would also prevent updating EEPROM bytes that have not changed even if the value of the variable has
If you want more than 100K write cycles, consider an FRAM module or an SD card to store the counter.
Also be aware that a (multibyte) counter written to any storage medium itself can be interrupted by the outage, so if you want to do it really foolproof…. it is not as simple as writing a counter.
Furthermore be aware of the semantics of your counter. Is it the last number used or is it the first free number to use?
Fair point
The counter cycles 0 1 2 0 1 2 0 1 2… so indeed as it’s an int the MSB never changes and is needlessly overwritten but as the LSB keeps changing anyway so after 100,000 button press you wasted two bytes instead of one.
Update() would solve that but I should have made the counter a byte anyway given its range.
This button counter stores the byte value in EEPROM and reloads the EEPROM data on reset.
// https://forum.arduino.cc/t/sequencing-counter-save-count-after-power-outage/1414317/
// Reads EEPROM address 0 for data < 255.
// Starts counter at stored value.
// Counts button short-presses (< 500ms).
// Stores single byte in EEPROM address with long press (> 1000ms).
// Terminates program
#include <EEPROM.h>
byte address = 0, count;
byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};
byte button = 2;
unsigned long shortPressTime = 500, longPressTime = 1000;
unsigned long timer, timeout = 50, timePressed, timeReleased;
bool buttonRead, buttonReadOld, buttonState;
bool shortPressed, longPressed, isPressed;
void setup() {
Serial.begin(115200);
instructions();
pinMode(button, INPUT_PULLUP); // configure button pin for INPUT using internal pullup resistor
for (byte i = 0; i < 8; i++)
pinMode(ledPin[i], OUTPUT); // configure LED pins for output
readEEPROM(); // read EEPROM address, display if not 0 or 255
}
void loop() {
readButton(); // read button press
}
void readButton() {
buttonRead = digitalRead(button); // store button state
if (buttonRead != buttonReadOld) { // when button state changes
timer = millis(); // ...start a timer
buttonReadOld = buttonRead; // ... store button reading
}
if ((millis() - timer) > timeout) { // if button change occured longer than debounce timeout...
if (buttonState == HIGH && buttonReadOld == LOW) { // button PRESSED
timePressed = millis(); // button PRESSED time
isPressed = true; // set button isPressed flag
shortPressed = true; // every button press starts as a short press
longPressed = false; // clear long press flag
}
if (buttonState == LOW && buttonReadOld == HIGH) { // button RELEASED
// timeReleased = millis(); // not used
isPressed = false; // clear button isPressed flag
if (shortPressed) { // only count short presses
shortPressed = false; // clear flag
updateLEDs(++count); // increment count and displayed on LEDs
}
}
if ((isPressed == true) && (longPressed == false)) {
unsigned long ispressingDuration = millis() - timePressed;
if (ispressingDuration > longPressTime ) {
storeValue(count); // store value in EEPROM
}
}
buttonState = buttonRead; // update button state
}
}
void updateLEDs(int count) {
for (byte i = 0; i < 10; i++) { // count ten bits
bool ledBit = bitRead(count, i); // test each bit in "count"
digitalWrite(ledPin[i], bitRead(count, i)); // set LED to bit value in "count"
// https://docs.arduino.cc/language-reference/en/functions/bits-and-bytes/bitRead/
}
}
void storeValue (int data) {
EEPROM.write(address, data);
Serial.print("EEPROM address: ");
Serial.print(address);
Serial.print(" value: ");
Serial.print(EEPROM.read(address));
Serial.print(" stored. ");
Serial.println("LEDs cleared. Program terminated.");
for (byte i = 0; i < 10; i++)
digitalWrite(ledPin[i], LOW); // all LEDs off
while (1) {}; // terminate program
// https://docs.arduino.cc/learn/programming/eeprom-guide/
// EEPROM.write() takes 3.3ms.
// EEPROM memory has 100,000 write/erase cycles.
// CAREFUL how often you write to it.
}
void readEEPROM() {
Serial.print("Data read from EEPROM, address: ");
Serial.print(address);
Serial.print(" value: ");
count = EEPROM.read(address);
if (count == 255) // addresses containing 255 never have been writen to.
count = 0;
else
updateLEDs(count); // show current EEPROM value stored at address
Serial.println(count);
}
void instructions() {
Serial.println("Short press (< 500ms) increments count.");
Serial.println("Long press (> 1000ms) store value, terminate program.");
}
diagram.json tab for wokwi nerds
{
"version": 1,
"author": "foreignpigdog x",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": -0.5, "attrs": {} },
{
"type": "wokwi-led-bar-graph",
"id": "bargraph1",
"top": -81.4,
"left": 43.4,
"rotate": 270,
"attrs": { "color": "lime" }
},
{
"type": "wokwi-pushbutton",
"id": "btn1",
"top": -51.4,
"left": 134.4,
"attrs": { "color": "yellow", "xray": "1" }
}
],
"connections": [
[ "nano:GND.2", "bargraph1:C10", "black", [ "v0" ] ],
[ "nano:3", "bargraph1:A10", "green", [ "v0" ] ],
[ "nano:4", "bargraph1:A9", "green", [ "v0" ] ],
[ "nano:5", "bargraph1:A8", "green", [ "v0" ] ],
[ "nano:6", "bargraph1:A7", "green", [ "v0" ] ],
[ "nano:7", "bargraph1:A6", "green", [ "v0" ] ],
[ "nano:8", "bargraph1:A5", "green", [ "v0" ] ],
[ "nano:9", "bargraph1:A4", "green", [ "v0" ] ],
[ "nano:10", "bargraph1:A3", "green", [ "v0" ] ],
[ "nano:GND.2", "btn1:2.l", "black", [ "v0" ] ],
[ "nano:2", "btn1:1.l", "yellow", [ "v0" ] ],
[ "bargraph1:C10", "bargraph1:C9", "green", [ "v0" ] ],
[ "bargraph1:C9", "bargraph1:C8", "green", [ "v0" ] ],
[ "bargraph1:C8", "bargraph1:C7", "green", [ "v0" ] ],
[ "bargraph1:C7", "bargraph1:C6", "green", [ "v0" ] ],
[ "bargraph1:C6", "bargraph1:C5", "green", [ "v0" ] ],
[ "bargraph1:C5", "bargraph1:C4", "green", [ "v0" ] ],
[ "bargraph1:C4", "bargraph1:C3", "green", [ "v0" ] ]
],
"dependencies": {}
}
How so ?
The EEPROM location where the LSB was stored might be toast but the one where the MSB was stored will still be OK as it will not have changed
Mind you, as @alanbrock has not answered my question as to the nature of the variable to be saved, who knows what the best solution is
With my code, not using update.
If you are referring to the fact that your code uses put() rather than update(), if I remember correctly the put() function calls update() so they are functionally equivalent
Update() stores new data only if different from old data... according to Arduino. https://docs.arduino.cc/learn/built-in-libraries/eeprom/#update
