Print out remaining time from "millis" timers

Hello Everyone,

I'm working on a code which uses millis to work with.

Here is what it does:

  1. Fixed intervals set for each action.
  2. Does an action, and adds its time to a variable.
  3. The loop constatly checking the variables, and when a variable reaches its intervals maximum time, it does an other action and adds its time to a variable.

Example: Turns on a LED, wait until given time, and then turns it off. The reason of millis of course to be able to do anything else during this switching.

I succesfully set everything, works good, BUT... Then it was time to add FEEDBACK, so I tried to add the print function to print out times remaining until each event to the serial port. I have different variables for turn off times and turn on times.

The feedback from event works great (says its on/off), but the time is constantly rising (I suppose thats how millis work) I set it to get a print from times every one second.

This is how it looks like: (LED on for 2 sec, off for 1 sec)

Time until LED turning on: 1 Time until LED turning on: 2 LED ON Time until LED turning off: 3 LED OFF Time until LED turning on: 4 Time until LED turning on: 5 .....

Do you guys have any idea how can I make it work like this:

Time until LED turning on: 2 Time until LED turning on: 1 LED ON Time until LED turning off: 1 LED OFF Time until LED turning on: 2 Time until LED turning on: 1 LED ON .....

Thank you in advance. Have a nice day :)

What have you tried with the code you haven't posted?

Do you guys have any idea how can I make it work like this:

Time until LED turning on: 2

You know when the timing period started. Let's call it startTime You know what the time is now. Let's call it currentTime You know what the period is. Let's call it timingPeriod You know the elapsed time since the start. Let's call it elapsedTime

elapsedTime = currentTime - startTime So remainingTime = timingPeriod - elapsedTime

AWOL: What have you tried with the code you haven't posted?

It is just full of comments and it's very long. I thought it would be more clear if I explain what it does.

Sp1k33:
. I thought it would be more clear if I explain what it does.

It wasn’t

UKHeliBob: You know when the timing period started. Let's call it startTime You know what the time is now. Let's call it currentTime You know what the period is. Let's call it timingPeriod You know the elapsed time since the start. Let's call it elapsedTime

elapsedTime = currentTime - startTime So remainingTime = timingPeriod - elapsedTime

Logic. Nice idea, maybe I'm too tired now to think logically :D First thing tomorrow I'll try this. Thank you.

You can use this as a generalized template:

const int pinLED = 13;

bool
    bstateLED;      //a way to track the on/off state of the LED
unsigned long
    timeDelay;      //the time we want to delay
unsigned long
    timeLED;        //the time the delay starts
unsigned long
    timeDiff,       //the difference in the current time from when we started
    timeLeft,       //the difference between the delay value and the difference
    timeNow;        //the time now


void setup() 
{
    //start the serial port
    Serial.begin(9600);
    Serial.print( "\n\n\n" );
    //set up the LED pin
    pinMode( pinLED, OUTPUT );
    digitalWrite( pinLED, LOW );
    //set the initial LED conditions: off with a delay of 5-seconds
    timeLED = millis();
    timeDelay = 5000;   //5-second initial off time
    bstateLED = false;    
    
}//setup

void loop() 
{
    //get the current time and calc the elapsed (diff) and remaining (left)
    timeNow = millis();
    timeDiff = timeNow - timeLED;
    timeLeft = timeDelay - timeDiff;

    //print the time left
    PrintTimeLeft( timeLeft );

    //just toggle the LED after each delay period
    if( (timeNow - timeLED) >= timeDelay )
    { 
        //toggle the tracking bool
        bstateLED ^= 1;
        //set the LED
        digitalWrite( pinLED, bstateLED?HIGH:LOW );
        //grab the time
        timeLED = millis();
        //set an on/off delay (2min on, 30-sec off)
        timeDelay = bstateLED?120000ul:30000ul;
    
    }//if
    
}//loop

void PrintTimeLeft( unsigned long timeLeft )
{
    char
        szStr[30];
    static int
        lastmins = -1,          //only want to print when one or more has changed
        lastsecs = -1, 
        lasttenths = -1;
    int
        mins,
        seconds,
        tenths;
    //calculation example: Suppose time left is 114567 mS (114.567 seconds)
    //
    // In floating point math, 114567/60000 = 1.90945
    // In integer math, 114567/60000 = 1 (the 0.90945 is stripped away)
    //      - mins = timeLeft / 60000
    //      - this is the minutes value
    //
    // When the mins is stripped away, what's left?
    //      - timeLeft = timeLeft - (mins * 60000) = 114567 - 60000 = 54567
    //
    // 54567 / 1000 = 54 (integer)
    //      - seconds = timeLeft / 1000 = 54
    //      - this is seconds value
    //  
    //  timeLeft = timeLeft - (seconds * 1000) = 567
    //      - tenths = timeLeft / 100 = 5
    //      - this is the tenths value
    //      - could be more accurate with rounding up (ignored here)    
    mins = (int)(timeLeft / 60000ul);
    timeLeft = timeLeft - (mins * 60000ul);
    seconds = (int)(timeLeft / 1000ul);
    timeLeft = timeLeft - (seconds * 1000ul);
    tenths = (int)(timeLeft / 100ul);

    //only update the countdown when something has changed
    if( lastmins != mins || 
            lastsecs != seconds || 
                lasttenths != tenths )
    {
        //easy to format with sprintf
        sprintf( szStr, "%02d:%02d.%1d",
            mins,
            seconds,
            tenths );
        Serial.println( szStr );

        //make a copy of the current as last
        lastmins = mins;
        lastsecs = seconds;
        lasttenths = tenths;
        
    }//if
        
}//PrintTimeLeft

UKHeliBob: You know when the timing period started. Let's call it startTime You know what the time is now. Let's call it currentTime You know what the period is. Let's call it timingPeriod You know the elapsed time since the start. Let's call it elapsedTime

elapsedTime = currentTime - startTime So remainingTime = timingPeriod - elapsedTime

So I have tried this.

Constants:

const unsigned long TimetoPrint = 1000;
const unsigned long LEDONinterval = 10000;
const unsigned long LEDOFFinterval = 5000;

Variables:

unsigned long TimerPrint_V;
unsigned long LEDONtimer;
unsigned long LEDOFFtimer;

Print code:

 if  (((millis () - TimerPrint_V) >= TimetoPrint) && (digitalRead (LED) == LOW))
        {
         Serial.println(" Time until LED is turning ON: ");
         Serial.println( (LEDOFFinterval / 1000) - (((millis ()) / 1000) - (LEDOFFinterval / 1000)) -5 );
         TimerPrint_V = millis ();
        }

 if  (((millis () - TimerPrint_V) >= TimetoPrint) && (digitalRead (LED) == HIGH))         
         {
         Serial.println(" Time until LED is turning OFF: ");
         Serial.println( (LEDONinterval / 1000) - (((millis ()) / 1000) - (LEDOFFtimer / 1000)) +5 );
         TimerPrint_V = millis ();
         }

The +5 and -5 there is needed for some reason, I did not get it why tho.

The serial print is the following:

LED OFF
Time until LED is turning ON:
5
Time until LED is turning ON:
4
Time until LED is turning ON:
3
Time until LED is turning ON:
2
Time until LED is turning ON:
1
Time until LED is turning ON:
0
LED ON
Time until LED is turning OFF:
9
Time until LED is turning OFF:
8
Time until LED is turning OFF:
7
Time until LED is turning OFF:
6
Time until LED is turning OFF:
5
Time until LED is turning OFF:
4
Time until LED is turning OFF:
3
Time until LED is turning OFF:
2
Time until LED is turning OFF:
1
LED OFF
Time until LED is turning ON:
4294967286
Time until LED is turning ON:
4294967285
Time until LED is turning ON:
4294967284
Time until LED is turning ON:
4294967283
Time until LED is turning ON:
4294967282
LED ON
Time until LED is turning OFF:
10
Time until LED is turning OFF:
9

As you can see, In the beggining everything is fine, after one loop the "time until turning off" returns to 10 as it is supposed to be, but the on timer not. Did I miss something?

The first thing that I would do is to simplify the calculation. Do not divide each part by 1000, use the native figures and divide the result by 1000 before printing.

For debugging I would split the calculation into stages as I did in my example and print the intermediate results

Blackfin: You can use this as a generalized template:

const int pinLED = 13;

bool    bstateLED;      //a way to track the on/off state of the LED unsigned long    timeDelay;      //the time we want to delay unsigned long    timeLED;        //the time the delay starts unsigned long    timeDiff,       //the difference in the current time from when we started    timeLeft,       //the difference between the delay value and the difference    timeNow;        //the time now

void setup() {    //start the serial port    Serial.begin(9600);    Serial.print( "\n\n\n" );    //set up the LED pin    pinMode( pinLED, OUTPUT );    digitalWrite( pinLED, LOW );    //set the initial LED conditions: off with a delay of 5-seconds    timeLED = millis();    timeDelay = 5000;   //5-second initial off time    bstateLED = false;         }//setup

void loop() {    //get the current time and calc the elapsed (diff) and remaining (left)    timeNow = millis();    timeDiff = timeNow - timeLED;    timeLeft = timeDelay - timeDiff;

   //print the time left    PrintTimeLeft( timeLeft );

   //just toggle the LED after each delay period    if( (timeNow - timeLED) >= timeDelay )    {        //toggle the tracking bool        bstateLED ^= 1;        //set the LED        digitalWrite( pinLED, bstateLED?HIGH:LOW );        //grab the time        timeLED = millis();        //set an on/off delay (2min on, 30-sec off)        timeDelay = bstateLED?120000ul:30000ul;        }//if     }//loop

void PrintTimeLeft( unsigned long timeLeft ) {    char        szStr[30];    static int        lastmins = -1,          //only want to print when one or more has changed        lastsecs = -1,        lasttenths = -1;    int        mins,        seconds,        tenths;    //calculation example: Suppose time left is 114567 mS (114.567 seconds)    //    // In floating point math, 114567/60000 = 1.90945    // In integer math, 114567/60000 = 1 (the 0.90945 is stripped away)    //      - mins = timeLeft / 60000    //      - this is the minutes value    //    // When the mins is stripped away, what's left?    //      - timeLeft = timeLeft - (mins * 60000) = 114567 - 60000 = 54567    //    // 54567 / 1000 = 54 (integer)    //      - seconds = timeLeft / 1000 = 54    //      - this is seconds value    //      //  timeLeft = timeLeft - (seconds * 1000) = 567    //      - tenths = timeLeft / 100 = 5    //      - this is the tenths value    //      - could be more accurate with rounding up (ignored here)        mins = (int)(timeLeft / 60000ul);    timeLeft = timeLeft - (mins * 60000ul);    seconds = (int)(timeLeft / 1000ul);    timeLeft = timeLeft - (seconds * 1000ul);    tenths = (int)(timeLeft / 100ul);

   //only update the countdown when something has changed    if( lastmins != mins ||            lastsecs != seconds ||                lasttenths != tenths )    {        //easy to format with sprintf        sprintf( szStr, "%02d:%02d.%1d",            mins,            seconds,            tenths );        Serial.println( szStr );

       //make a copy of the current as last        lastmins = mins;        lastsecs = seconds;        lasttenths = tenths;            }//if         }//PrintTimeLeft

Thank you very much. This is a helpful example. My code is working now. Have a nice day :)

UKHeliBob: The first thing that I would do is to simplify the calculation. Do not divide each part by 1000, use the native figures and divide the result by 1000 before printing.

For debugging I would split the calculation into stages as I did in my example and print the intermediate results

Yes, when I saw the example code in on other answer, I saw that it makes it easier, if You split the calculations, and voala, it is working now, no +5 -5 things :D

Thank you for your help :)