Simple Countdown, but something is amiss.

Status
Not open for further replies.

Bastiaan

Well-known member
hi guys,

i am trying to build a simple countdown with a teensy3.2 with the millis function: but somehow the code is not responding properly could you see where the problem is? the code runs fine if the days is set to 1, but if i put all the values to Zero i get 6:28:9 and then it starts to countdown. i stripped the previous code which includes an encoder + pushbutton a menu and a st7735 tftView attachment Test_CountdownMillisAG.ino

best regards

Bastiaan

Code:
Int long Days    = 1;
Int long Hours   = 0;
Int long Min      = 0;
Int long Sec_add     = 0;

unsigned long Sec;

unsigned long DisplaySec;
unsigned long DisplayMin;
unsigned long DisplayHours;
unsigned long DisplayDays;



unsigned long startTime;
unsigned long oneSecond = 1000UL;


void Setup()
{
Sec = Sec_add + round(60 * Min) + round(60 * 60 * Hours) + round(60 * 60 * 24 * Days);
}


void Loop()
{


 if (millis() - startTime >= oneSecond)
    {
      Sec--;
      startTime += oneSecond;
      if (Sec <= 0)
      DisplayDays  = Sec / 86400;
      DisplayHours = Sec / 3600;
      DisplayMin   = Sec / 60;
      DisplaySec   = Sec % 60;

    }

  Serial.print((DisplayHours % 60) % 60);
    Serial.print(":");
    Serial.print(DisplayMin % 60);
    Serial.print(":");
    Serial.print(DisplaySec);



}
 
Last edited:
i think i know the problem where it occurs, its the sec =sec+ part that adds extra seconds to the loop and thus creates a mismatch.
 
Sec is an unsigned long, so it will never be less than zero. When you set all your Days, Hours, Min, Sec_add variables to zero, Sec will start at zero, but when you decrement it, it will be a really big positive number.

And are you not missing {} around the lines where you're setting your display variables? I'm not entirely sure what your intent was there, but it looks like you might have meant:
Code:
if (millis() - startTime >= oneSecond)
    {
      Sec--;
      startTime += oneSecond;
      if (Sec <= 0)
      {
        DisplayDays  = Sec / 86400;
        DisplayHours = Sec / 3600;
        DisplayMin   = Sec / 60;
        DisplaySec   = Sec % 60;
      }

    }
 
i changed it to
Code:
    if (millis() - startTime >= oneSecond)
    {
      Sec--;
      startTime += oneSecond;
      if (Sec >= 0)
      {
        

        DisplayDays  = Sec / 86400;
        DisplayHours = Sec / 3600;
        DisplayMin   = Sec / 60;
        DisplaySec   = Sec % 60;

      }
      else
      {
        menuCount == 1;
      }
    }

so i get if i set it for one day, 1hour and 12min and some seconds, i get 25:12:10 seconds. ok but the last seconds are counted to Zero each time the countdown starts.

does his have to do with Sec%60; is there a solution for this?

best


B
 
Probably a warning, no error, program runs.

I’ll switch the if statement so that the condition is changed.

still I think the problem is here? DisplaySec=Sec%60;
 
the : Sec % 60

Should work as expected AFAIK - as it has been used regularly.

It will only result in ZERO when SEC is a multiple of 60.

Expect problem is elsewhere.
 
I'm going to approach this from a slightly different direction.

If you set:
Code:
Int long Days    = 0;
Int long Hours   = 0;
Int long Min      = 0;
Int long Sec_add     = 3;

What exactly would you expect to see printed?

Next, if you set:
Code:
Int long Days    = 0;
Int long Hours   = 0;
Int long Min      = 1;
Int long Sec_add     = 3;

again, what exactly would you expect to see (you can leave out the bits in the middle, but please show at least a few lines at the beginning and end of what you expect to see).
 
so i tried the stuff you recommended.

Code:
Int long Days    = 0;
Int long Hours   = 0;
Int long Min      = 0;
Int long Sec_add     = 3;

i get 6:28:00 and it starts counting down.

Code:
Int long Days    = 0;
Int long Hours   = 0;
Int long Min      =1;
Int long Sec_add     = 3;

it starts at 1minute and 3 seconds. and it counts down.

i see a problem but not the answer at the moment. the 6:28:00 = 23280 seconds

what is 3 seconds % 60

i also changed the Sec to a unsigned long and Sec_add to. but it doesnt seems to make a difference.
 
No it starts with 3, counts down to zero ,and _after_that_ it prints your 6:28. That's correct.
What do you expect to happen when the time is over?
Currently, its an underflow.
Do you want the program to stop?
Or, what should it do?
 
Think about that:
if (Sec <= 0) {
DisplayDays = Sec / 86400;
...
So, if Sec is negative, it calculates DisplayDays = -1 / 86400
I don't think you want that.
 
so i tried the stuff you recommended.

No, actually you didn't.

I didn't say to change and run the program.

I'm saying: if you set those variables to those values, what output would you expect to see from the program? Write that down and show us.
 
hi silverlock,

had some other stuff to do.
id expect that it would countdown from 3,2,1,0.
but then it goes to 6:28:15.

Code:
unsigned long Days    = 0;
unsigned long Hours   = 0;
unsigned long Min     = 0;
unsigned long Sec_add = 3;

unsigned long DisplaySec;
unsigned long DisplayMin;
unsigned long DisplayHours;
unsigned long DisplayDays;

unsigned long Sec=0;

unsigned long startTime;
unsigned long oneSecond = 1000UL;


void setup()
{

  Sec = round(Sec_add * 1) + round(60 * Min) + round(60 * 60 * Hours) + round(60 * 60 * 24 * Days);
  Serial.begin(9600);
}


void loop()
{


  if (millis() - startTime >= oneSecond)
  {
   
    startTime += oneSecond;

    if (Sec < 0)//clearly i dont have a clue, i pondered about it, i first th
    {
      Sec=0;
      
    }
    else
    {
      DisplayDays  = Sec / 86400;
      DisplayHours = Sec / 3600;
      DisplayMin   = Sec / 60;
      DisplaySec   = Sec % 60;//end of countdown
      
    }
 

      Serial.print((DisplayHours % 60) % 60);
      Serial.print(":");
      Serial.print(DisplayMin % 60);
      Serial.print(":");
      Serial.print(DisplaySec);
      Serial.println("end");
      Sec--;
    }
}

first i thought i had to set a condition on the Sec<0 so that it becomes Zero.
anyway i feel stupid. have this feeling i am almost there.

if the Sec requires to be signed long= 2,1,0 it will stay Zero after that. but what will happen if absolute minus is reached? isnt there a limit for signed long? what will happen then?

adding the Sec--; further down the line would be better because as i start the Serial monitor i only see the 2,1,0 but i dont see the 3.

best regards

B
 
A simpler countdown timer

@Bastiaan:

I would suggest a major simplification. Note that I am not somewhere where I can actually test this on a Teensy, so this is all "conceptual" off the top of my head. Normally, I don't think it is really useful/helpful to just write a sketch for someone else . . . it is much more educational to guide someone thru writing their own sketch. However, in this case, writing a description to guide you might not necessarily help you to write exactly what's intended, so I am going to make an exception to my own rule !!

Take a look at this code & try to understand what it is doing & why. Play with changing the initial values & see how the output changes. Walk thru the logic with different starting values & understand how it is doing the math & how the logic is working.

Code:
// normally (for actual time), these variables will never be negative, so we will use them going negative to decide when to decrement the next higher one
long Days;
long Hours;
long Minutes;
long Seconds;

// define the one second ticker
unsigned long oneSecondTick = millis();

bool weAreCountingDown = true;

const int ONE_SECOND_IN_MILLIS = 1000;

void setup()
{
   Days = 1;
   Hours = 0;
   Minutes = 0;
   Seconds = 0;

   Serial.begin(9600);

   // wait for serial to initalize
   delay(3000);

   Serial.print("Start duration: ");
   if (Days < 100)
   {
      Serial.print("0");

      if (Days < 10)
      {
         Serial.print("0");
      }
   }
   Serial.print(Days);
   Serial.print(" days ");
   if (Hours < 10)
   {
      Serial.print("0");
   }
   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);

   // initialize the one second ticker
   oneSecondTick = millis();
}  // setup()

void loop()
{
   // see if we are still counting down
   if (weAreCountingDown)
   {
      // see if it's time to process the one second ticker
      if (millis() > (oneSecondTick + ONE_SECOND_IN_MILLIS))
      {
         // reset the one second ticker for the next interval
         oneSecondTick = millis();

         // only count down if we haven't reached 00:00:00.00 yet
         if ((Days > 0) || (Hours > 0) || (Minutes > 0) || (Seconds > 0))
         {
            // decrement the seconds counter & see if it "rolled over"
            if (--Seconds < 0)
            {
               // reset seconds to 59
               Seconds = 59;

               // decrement the minutes counter & see if it "rolled over"
               if (--Minutes < 0)
               {
                  // reset minutes to 59
                  Minutes = 59;

                  // decrement the hours counter & see if it "rolled over"
                  if (--Hours < 0)
                  {
                     // reset hours to 23
                     Hours = 23;

                     // decrement the days counter & see if it "rolled over"
                     if (--Days < 0)
                     {
                        // reset everything to 0 - we're donw
                        Seconds = 0;
                        Minutes = 0;
                        Hours = 0;
                        Days = 0;
                     }
                  }
               }
            }
         }

         Serial.print("Remaining duration: ");
         if (Days < 100)
         {
            Serial.print("0");
      
            if (Days < 10)
            {
               Serial.print("0");
            }
         }
         Serial.print(Days);
         Serial.print(" days ");
         if (Hours < 10)
         {
            Serial.print("0");
         }
         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);

         // if everything just went to zero, then we're done counting down
         if ((Days == 0) && (Hours == 0) && (Minutes == 0) && (Seconds == 0))
         {
            Serial.println("Done !!");

            // stop the counting down
            weAreCountingDown = false;
         }
      }
   }
}  // loop()

Note that this may not be the most efficient way to write every line (e.g. adding extra zeros when printing each of the variables, etc.), but I have tried to minimize the complexity for ease of understanding.

Feel free to ask any questions & I will do my best to answer them !!

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Last edited:
Status
Not open for further replies.
Back
Top