Need to save data to EEPROM on power off

Good afternoon,
I am making a model of a dishwasher (using 12V components) using Arduino
I have written all the code so far, but I am missing the save to eeprom function. Well, in reality it is already written, but it doesn't seem to work reliably
I am powering everything off an LM7805 and I have connected a diode and bulk cap to the Arduino 5V supply like shown in the picture

I then read the Vcc using the secret voltmeter code. If this goes below 4 volts, I save to EEPROM and prepare for shutdown
Attached below is the code for the whole machine. However, I noticed that while the capacitor is able to keep the Arduino LED powered on for a few seconds, the cycle doesn't always resume since no data gets saved, or at least not always. I do have to say I have made an experimentation board with some relays and when 2 of these are on the total consumption is around 250mA at 12V. Still, given the circuit, it shouldn't really matter, right? Could anyone help me out with the project and tell me what I'm doing wrong? Thanks in advance

Arduino_Dishwasher_7SEG.zip (14.9 KB)

If the current draw is draining the capacitor too fast to complete the save, then you might simply need to increase the capacitance.

But I am already using a 4700uF capacitor, and the Arduino stays on for quite some time after power off

Diagram please.
I would have used 12volt relays powered from the 12volt supply, with the diode/cap powering the 7805. And a voltage detector on the cap on the input of the 7805.
That will keep the 5volt supply constant until shutdown.
A buck converter could have been a better alternative to the ancient 7805.
Leo..

As the voltage on the Cap drops after power loss, so does the analog reference voltage.

Search for a better approach: I did a quick Google and found 2 YouTube videos and numerous articles; I did not critique but the approaches span between polling an analog pin to an interrupt-driven procedure to write state to EEPROM.

Thanks for all the suggestions
I have watched a YouTube video where a similar procedure was implemented with timer2. I have done the same, attaching an interrupt every 10 ms, and it works wonderfully

Is the internal 1.1V reference voltage not the same regardless of whether the supply voltage is 3V or 5V?

@Mattia9914 Could you not probe the voltage before the diode? The voltage there would go low when the power is cut and the cap is still fully charged.

The default Vr is the Vin which for UNO/Mega is 5.0 Volts. I did not download & verify your source code. Kind-of why we ask for code to be put into the post using code-tags.

This article gives a fair example of determining Vcc from the 1.1V internal bandgap reference:
» Measuring VCC via the bandgap » JeeLabs

Perhaps your "magic" code uses a similar technique.

could there be a cap on the supply from VCC that is holding it up longer than expected and only gets pulled down further as the voltage on C1 drops.

would it be better to somehow detect that the drop across D1 is < 0.7V?

@gcjr I have not thought about that possibility, it could very well be just like that
ANyways, the code to save to EEPROM now works

Now I need help in order to restore the cycle state: looking at the code, all I should need to do is to save the cycle number (progIndex), the macro state (is the cycle running or is it paused or is delay timer counting down etc. etc.) and finally the cycle state (in which of the 27 steps is the cycle?).
However I am having difficulty doing this. I have also saved the output states before power down and I am able to keep these in memory, everything gets saved correctly. But let's say I interrupt the cycle at stage 2, well what happens at restart is that the outputs get written correctly (according to the outputs that should be written in that state) but the cycle doesn't then advance to the subsequent stages after that particular stage is done. What am I doing wrong?

@mrburnette I know, I simply have not copied the code as it contains many header files

You could consider something like this:

#define MACHINE_STATE_ADDRESS 0

struct {
  byte progIndex;
  byte macroState;
  byte cycleState;
} machineState;

void power_off_detected()
{
  EEPROM.put(MACHINE_STATE_ADDRESS, machineState);
}

void setup()
{
  EEPROM.get(MACHINE_STATE_ADDRESS, machineState);
  //Resume
}

void loop()
{
  //Do something
  machineState.progState = someValue;
  //Do something else
  machineState.macroState = someOtherValue;
  //Do something exiting
  machineState.cycleState = someExitingValue;
}

I do not hope that you use Timer2 to save the data every 10ms..

Usually, you would create a minimal sample to illustrate your problem. Most ppl (including me) do not want to download files, extract them and then try to figure out the contents..

Thank you for your suggestion
But how could I implement something like that struct without rewriting the whole code?
No, I don't write every 10 ms. I check every 10 ms and write only when necessary

The only one who can answer that question is your self.. :wink:

I have written this in the setup function:

    progIndex = EEPROM.read(1);
    currentCycleState = EEPROM.read(1 + sizeof(progIndex));
    currentMacroState = EEPROM.read(1 + sizeof(progIndex) + sizeof(currentCycleState));

but it doesn't seem to work. Why? Isn't it the same thing as suggested here above?

I have implemented a struct just like the one shown here.
However I am having difficulty understanding how to retrieve data at startup.
What I want to do is check for a bit in position 0 of the EEPROM (I call this the "Do I have to resume?" bit) and if this is true copy macroState, cycleState and progIndex to from EEPROM to the actual variables

This is what I have written:

if (EEPROM.read(0) == true) { 
    EEPROM.write(0, false);
    EEPROM.get(1, machineState);
    EEPROM.get(1 + sizeof(machineState), outputStateBeforePowerFailure);

    for (int i = 4; i <= 11; i++) {
      digitalWrite(i, outputStateBeforePowerFailure[i - 4]);//rewrite pins to the state they originally were before power down
    }

Thing is that I don't know whether this is correct writing or if I should use:

machineState = EEPROM.get(1, machineState);

IIRC AVR's at 16MHz are not stable below 4.5V.

With a Zener diode and a resistor you can make a pullup that turns off when V drops, why not test the Supply before the regulator? And for all that, the regulator needs almost 7V to operate correctly or it destabilizes, hard to tell when VCC can be 4V.

Thanks @GoForSmoke , but the Arduino manages to save data to EEPROM, I simply need to understand how to retrieve it then

Your IDE has examples for clear (16 byte page), read and write.
Note that Libraries are supposed to come with examples.

File->Examples->EEPROM

You would look at the EEPROM documentation to figure it out.. Basically, EEPROM "put" & "get" will store and retrieve specialized data types such as structures in one operation, whereas "read" and "write" will work with single bytes, so you are doing it wrong..

So even for unsigned longs I need to use get and put?