Countdown Millis to HH MM SS

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);




        }




}


Topic moved ! Please do not post in "Uncategorized"; see the sticky topics in Uncategorized - Arduino Forum.

ok sorry!

if you are on a small AVR like the UNO, this math

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!

This is wrong. You see why?

you either let the loop run doing nothing

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.

J-M-L thank you so much! I learned a lot this morning! I LOVE doing arduino projects!

Eventually you can avoid a lot of problems with aritmetics like this:

  int seconds;
  int minutes;
  int hours;
  unsigned long previousMillis;
  unsigned long currentMillis;
  unsigned long interval = 1000;
void setup() {
  Serial.begin(9600);
  Serial.print("                                                        ");
  previousMillis = 0;

// time left
  hours = 36;
  minutes = 0;
  seconds = 0;

}

void loop() {
  currentMillis = millis(); // get current Millis
  // every second that passes execute the IF
  if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
     // minus 1 second
     if (seconds > 0) {
        seconds --; // decrement
     } else {
        seconds = 59;
        if (minutes > 0) {
           minutes -- ; // decrement
        } else {
           minutes = 59;
           if (hours > 0) {
               hours --;
            }; // h
        }; // m
      };  // s
   }; // ms
  if ( (hours==0) && (minutes==0) && (seconds==0)) {
     Serial.println(" Fermentation DONE");
     while (1){}; // infinite loop
  } else {
      Serial.print(hours);  Serial.print(" : "); Serial.print(minutes);  Serial.print(" : "); Serial.println(seconds);
   };
}

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.");
  }
}

You might want to have a look at my CountDown class.

GitHub - RobTillaart/CountDown: Arduino library to implement a countdown clock (in software by polling, no hardware timer).

Thank you! Good yo know.

Thank you!