Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

Thread: Simple Countdown, but something is amiss.

  1. #1
    Senior Member
    Join Date
    Sep 2016
    Posts
    174

    Simple Countdown, but something is amiss.

    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 tftTest_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 by Bastiaan; 04-01-2021 at 12:39 PM.

  2. #2
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    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.

  3. #3
    Senior Member
    Join Date
    Oct 2019
    Location
    Calgary
    Posts
    109
    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;
          }
    
        }

  4. #4
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    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

  5. #5
    Senior Member
    Join Date
    Oct 2019
    Location
    Calgary
    Posts
    109
    If you didn't change Sec from being an unsigned long, the test
    Code:
    if (Sec >= 0)
    will always be true.

  6. #6
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,281
    Yes, and normally the compiler should warn about this. Does it not?

  7. #7
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    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;

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,913
    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.

  9. #9
    Senior Member
    Join Date
    Oct 2019
    Location
    Calgary
    Posts
    109
    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).

  10. #10
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    Ok , ill write you tomorrow evening.

  11. #11
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    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.

  12. #12
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,281
    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?

  13. #13
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,281
    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.

  14. #14
    Senior Member
    Join Date
    Oct 2019
    Location
    Calgary
    Posts
    109
    Quote Originally Posted by Bastiaan View Post
    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.

  15. #15
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    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

  16. #16
    Senior Member
    Join Date
    Apr 2020
    Location
    DFW area in Texas
    Posts
    244

    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 by kd5rxt-mark; 04-16-2021 at 02:37 PM. Reason: added comment about efficiency vs complexity

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •