/*
Forum:https://forum.arduino.cc/t/countdown-with-eprom/1454384
Wokwi: https://wokwi.com/projects/471457976353763329
Changes to the original:
In loop -> delay (2000); // Changed from 20000 to 2000 ms to speed up the counting of "reading"
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd (0x27, 16, 2);
const uint32_t INITIAL_READING = 2870000UL; // Displays 28700.00
const uint32_t MAX_READING = 99999900UL; // Displays 999999.00
const uint16_t RECORD_MAGIC = 0xA55A;
uint32_t reading;
uint32_t currentSequence = 0;
int currentSlot = -1;
// Information stored in EEPROM
struct SavedRecord {
uint32_t sequence;
uint32_t reading;
uint16_t magic;
uint16_t checksum;
};
// -----------------------------------------------------------------------------
uint16_t calculateChecksum (
uint32_t sequence, uint32_t savedReading)
{
uint32_t value = sequence ^ savedReading ^ 0xA55A5A5UL;
value ^= value >> 16;
return static_cast<uint16_t> (value);
}
bool isValidRecord (
const SavedRecord &record)
{
return record.magic == RECORD_MAGIC
&& record.reading >= INITIAL_READING
&& record.reading <= MAX_READING
&& record.checksum ==
calculateChecksum (record.sequence, record.reading);
}
int getNumberOfSlots () {
return EEPROM.length () / sizeof(SavedRecord);
}
void loadLastReading () {
SavedRecord record;
bool validReadingFound = false;
int numberOfSlots = getNumberOfSlots ();
// Search EEPROM for the most recently saved valid reading
for (int slot = 0; slot < numberOfSlots; slot++) {
int address = slot * sizeof (SavedRecord);
EEPROM.get (address, record);
if (isValidRecord(record)) {
bool isNewer =
!validReadingFound ||
static_cast<int32_t> (record.sequence -
currentSequence) > 0;
if (isNewer) {
reading = record.reading;
currentSequence = record.sequence;
currentSlot = slot;
validReadingFound = true;
}
}
} // Use the initial value only if EEPROM has no saved reading
if (!validReadingFound) {
reading = INITIAL_READING;
currentSequence = 0;
currentSlot = -1;
}
}
void saveReading () {
int numberOfSlots = getNumberOfSlots ();
// Move to the next EEPROM location
currentSlot = (currentSlot + 1) %
numberOfSlots;
currentSequence++;
SavedRecord record;
record.sequence = currentSequence;
record.reading = reading;
record.magic = RECORD_MAGIC;
record.checksum = calculateChecksum (record.sequence, record.reading);
int address = currentSlot * sizeof (SavedRecord);
EEPROM.put (address, record);
}
void displayReading () {
uint32_t whole = reading / 100;
uint16_t decimal = reading % 100;
// Clear the second LCD row
lcd.setCursor (0, 1);
lcd.print (" ");
lcd.setCursor (1, 1);
lcd.print (whole);
lcd.print (".");
if (decimal < 10) {
lcd.print ("0");
}
lcd.print (decimal);
}
void setup () {
lcd.init ();
lcd.backlight ();
lcd.setCursor (0, 0);
lcd.print ("TOTAL KWh L1L2L3");
// Recover the last value stored in
// EEPROMloadLastReading ();
loadLastReading ();
}
void loop () {
displayReading ();
// Save the currently displayed reading
saveReading ();
// Stop increasing when the maximum reading is reached
if (reading >= MAX_READING) {
while (true) {
delay (1000);
}
}
delay (2000); // Changed from 20000 to 2000 ms to speed up the counting of "reading"
reading++;
}