Hi everyone, I am trying my best to do a countdown with millis and not delay. As many tutorials explained the reasons why it is better to use millis. I want to display on a 7 segments how many hours min sec left of the 36 hours of my yogurt fermentation. I know how to manage the display. For now I am just trying to get clean results on the serial monitor. Can someone please point out my error? Why I am getting a countdown no where near close reality? Thank you. Here is my code.
int seconds;
int minutes;
int hours;
unsigned long previousMillis;
unsigned long currentMillis;
unsigned long interval = 1000;
unsigned long fermentationTime; // 36 hours
void setup() {
Serial.begin(9600);
Serial.print(" ");
previousMillis = 0;
fermentationTime = 129600000; // 36 hours
}
void loop() {
currentMillis = millis(); // get current Millis
// every second that passes execute the IF
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
fermentationTime = fermentationTime - currentMillis; // 36 hours minus 1 second
hours = ((fermentationTime / (1000*60*60)) % 24);
minutes = ((fermentationTime / (1000*60)) % 60);
seconds = (fermentationTime / 1000) % 60 ;
Serial.print(hours); Serial.print(" : "); Serial.print(minutes); Serial.print(" : "); Serial.println(seconds);
}
}
is conducted using int, on 2 bytes and will overflow .
try something like this (typed here)
const unsigned long interval = 1000;
unsigned long previousMillis = 0;
unsigned long fermentationTime = 36UL * 3600; // 36 hours in seconds. NOTE THE UL to force unsigned long
void setup() {
Serial.begin(115200);
}
void loop() {
if (fermentationTime == 0) return; // we are done, don't do anything anymore.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
fermentationTime--;
unsigned long hours = fermentationTime / 3600; // no need for ul as fermentationTime is already ul
unsigned long minutes = (fermentationTime % 3600) / 60;
unsigned long seconds = fermentationTime % 60;
Serial.print(hours);
Serial.print(":");
if (minutes < 10) Serial.print('0');
Serial.print(minutes);
Serial.print(":");
if (seconds < 10) Serial.print('0');
Serial.println(seconds);
}
}
Wow! Thank you so much! Works perfectly! When it reaches 0 i will make a buzzer beep and no longer turn on the relay that controls the heater. (that I know how) what is the best method to exit the loop? Thank you again! The best reuteri yogurt machine ever!
void loop() {
if (fermentationTime == 0) return; // we are done, don't do anything anymore.
...
or you create a empty loop like
void loop() {
if (fermentationTime == 0) {
// we are done, stop the heater
digitalWrite(heaterPin, OFF); // whatever
Serial.println("Done !");
while (true) yield(); // infinite loop, stuck here
}
// if you arrive here then the countdown is still running
...
Usuallly it's not best practice to loose the loop, you might want to add other buttons, like restart etc... so keeping the code active even if doing nothing is nice.
alternatively you can add a module to control the power supply of your gig and once it's done, it auto-shut off everything, including the arduino after doing the beep.
I like to use flags.... to NOT enter an action/call a function.
bool weAreStillCountingDown = true; // set flag
int count = 5;
void setup() {
Serial.begin(115200);
Serial.print("Start. ");
}
void loop() {
if (weAreStillCountingDown) { // check flag
countDown(); // flag indicates, yes, we are still counting down
}
// flag check failed...
// do other stuff or nothing
}
void countDown() {
Serial.print(count);
count--;
delay(1000);
if (count < 0) {
weAreStillCountingDown = false; // clear flag
Serial.print(" Fin.");
}
}