*WARNING : LONG TOPIC"
Hi everyone,
I am continuing my Arduino dishwasher project. It is 95% completed, I was able to resolve my issue with the electromagnetic noises and have reorganized the code a little better. Howerver I am having an issue
First of all, let me introduce how the code works: each cycle can be comprised of 27 steps AT MOST. Shorter cycles, such as the "Rinse Only" will have fewer steps (in this case 6) and the same goes for the quick wash cycles.
The steps are as follows:
0-> initial drain
1-> resin regeneration (if necessary)
2-> prewash water fill
3-> prewash with cold water
4-> prewash heating
5-> prewash with hot water
6-> prewash drain
7-> main wash fill
8-> main wash with cold water
9-> main wash heating to 45°C
10-> main wash at 45°C
and so on and so forth. I won't list all of them since the problem happens here.
I have written a special function that, every 20ms (thanks to a timer 2 library, MsTimer2), checks to see if the voltage of the Arduino drops below 4.25 volts. If it does, it will save a few variables to EEPROM in order to prepare for a blackout. These variables are, namely:
-> the cycle number (eg. 1 = Pots And Pans, 2 = Regular, 3 = ECO ...)
-> the cycle phase (eg. phase number 6 = prewash drain)
-> the program state (eg. is the cycle running, is it paused, has an error occurred?)
-> the flowmeter pulses (so that, if the machine gets stopped during fill, it will resume from where it was stopped)
->the elapsed stage time before power failure (eg. phase 5 has started 2 minutes ago, this means that when the power is resumed the software will have to remember that this stage must last 2 minutes less)
-> the state of the outputs before power failure (so that they can be switched on when power is resumed)
Here is where the problem happens: if I run the "Rinse Only" cycle, which goes through steps 0,1,2,5,6 then if I simulate a black out by unplugging the machine, everything works fine. The cycle is resumed EXACTLY from where it left off
BUT, if I select the "Quick Wash" cycle which goes through steps 0,1,7,9,10 and unplug the machine during or after step 9, the machine won't restart the cycle correctly. I noticed that this happens due to the fact that the variable "elapsedTimeBeforePowerFailure" is not correctly updated. By switching the machine off and reading my EEPROM, here's what I found:
19:56:49.938 -> progIndex: 3
19:56:49.938 -> currentCycleState: 9
19:56:49.978 -> currentMacroState: 2
19:56:49.978 -> flowMeterPulses: 0
19:56:49.978 -> elapsedTimeBeforePowerFailure: 22
19:56:50.018 -> 0
19:56:50.018 -> 0
19:56:50.018 -> 1
19:56:50.018 -> 1
19:56:50.018 -> 1
19:56:50.057 -> 0
So the cycle number was saved correctly, the cycle state as well, same goes for the macro state (2= cycle running, 1 = delay timer countdown, 0 = cycle in selection phase). Thing is, I switched the machine off way after 22 milliseconds from the stage start time. In fact, the machine counts the time correctly, since stage 9 starts with opening the dispenser for 1.5 seconds and then shutting it off. This happens correctly and the time is counted down right, but WHY doesn't it save the elapsed time correctly?
AND, if I wait until the temperature has reached 45°C and the cycle advances to stage 10, if I switch it off then it will resume from stage 9. This happens every time stages go over 7 or 8 (I have not been able to pinpoint this exactly), which makes me think of some variables overflowing (?). If I stop the machine while it is filling for the main wash, as an example, the stage is 7 and it resumes correctly
Here's the code that updates the array that containt the output states before power failure (also used when pausing the cycle via the Start/Pause button)
void updateOutputStates() {
for (byte m = 0; m <= regenSolenoid - drainPump; m++) {
if (digitalRead(m + drainPump) != statesInWhichOutputsShouldBe[m] && currentMacroState != CYCLEPAUSED && currentMacroState != BLOCKINGERRORMODE) {
statesInWhichOutputsShouldBe[m] = digitalRead(m + drainPump);
}
}
}
Here's the code that saves data to EEPROM if voltage goes below 4.25V
void powerFailure() {
long VCC = readVcc();
if (VCC < 4250 && prevVCC > VCC && doneWriting == false && (currentMacroState == DELAYCOUNT || currentMacroState == CYCLERUNNING || currentMacroState == CYCLEPAUSED)) {
elapsedTimeBeforePowerFailure = millis() - stageStartTime;
updateOutputStates();
EEPROM.put(0, true); //flag for cycle interrupted while running due to power failure
EEPROM.put(1, progIndex); //save selected program
EEPROM.put(1 + sizeof(progIndex), currentCycleState); // save current cycle state
EEPROM.put(1 + sizeof(progIndex) + sizeof(currentCycleState), currentMacroState); // save current macro state (eg. cycle running or others)
EEPROM.put(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState), flowMeterPulses);
EEPROM.put(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState) + sizeof(flowMeterPulses), elapsedTimeBeforePowerFailure);
EEPROM.put(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState) + sizeof(flowMeterPulses) + sizeof(elapsedTimeBeforePowerFailure), statesInWhichOutputsShouldBe);
doneWriting = true;
//used for debugging short cycle not saving data
Serial.println(elapsedTimeBeforePowerFailure);
}
prevVCC = VCC;
}
Here's the code that resumes data when starting again:
if (EEPROM.read(0) == true) { // for next iteration
EEPROM.put(0, false);
EEPROM.get(1, progIndex);
EEPROM.get(1 + sizeof(progIndex), currentCycleState);
EEPROM.get(1 + sizeof(progIndex) + sizeof(currentCycleState), currentMacroState);
EEPROM.get(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState), flowMeterPulses);
EEPROM.get(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState) + sizeof(flowMeterPulses), elapsedTimeBeforePowerFailure);
//for (byte j = 0; j <= regenSolenoid - drainPump; j++) {
//statesInWhichOutputsShouldBe[j] = EEPROM.get(4 + sizeof(flowMeterPulses) + sizeof(elapsedTimeBeforePowerFailure) + j, statesInWhichOutputsShouldBe[j]);
EEPROM.get(1 + sizeof(progIndex) + sizeof(currentCycleState) + sizeof(currentMacroState) + sizeof(flowMeterPulses) + sizeof(elapsedTimeBeforePowerFailure), statesInWhichOutputsShouldBe);
//}
initTimeArray(); // do it here as it might be that the data from eeprom must initialize them
assignParameters();
isItPossibleToStart = true;
stageStartTime = millis() - elapsedTimeBeforePowerFailure;
elapsedTime = elapsedTimeBeforePowerFailure;//used when the cycle resumes after a pause, this way the machine resumes from where it left off once the door is closed again
//timeDispenserWasOpened = millis();
//isDispenserOpened = true;
countDownFunction();
if (currentMacroState != CYCLEPAUSED) {
for (byte i = drainPump; i <= regenSolenoid; i++) {
digitalWrite(i, statesInWhichOutputsShouldBe[i - drainPump]);//rewrite pins to the state they originally were before pausing the cycle
}
}
}
Finally, here's the complete code attached
I want to thank everybody who will be able to help me in the slightest, I apologize for the topic length and wish you a good evening/morning/afternoon. Thanks
Arduino_Dishwasher_7SEG_CANDY.zip (21.0 KB)