Elapsed time class

Posted by Nick Gammon on Wed 11 May 2011 02:54 AM — 7 posts, 31,257 views.

Australia Forum Administrator #0
One thing that seems to trip up beginners to the Arduino is the idea of implementing delays without using delay(). Hence the "blink without delay" example sketch. But that sketch is a bit confusing. You have to set up a "start" variable, assign the time to it, check it by doing subtraction rather than addition, and so on. And it gets more confusing if you want two time intervals.

The "elapsed" class below tries to simplify that. The class has a couple of member variables (startus and startms) which remember when you last "reset the timer". Then you simply call intervalMs (for milliseconds) or intervalUs (for microseconds) to see if your required time period is up. When it is, you can do something, like flash a LED. Then you can reset the timer if you want to.

Example snippet:


if (t2.intervalMs () > 200)   // time up?
    {
    digitalWrite(2, !digitalRead (2));   // toggle the LED
    t2.reset ();   // reset the timer
    }  // end if time up



The Arduino library can be downloaded from here:

http://www.gammon.com.au/Arduino/Elapsed.zip (4 Kb)

Unzip the file into your Arduino sketch "libraries" folder.

To use it just:


#include <Elapsed.h>


Example code that flashes two LEDs at different rates:


#include <Elapsed.h>

void setup() 
  {                
  pinMode (2, OUTPUT);     
  pinMode (3, OUTPUT);     
  }  // end of setup

static Elapsed t2, t3;

void loop() {

  if (t2.intervalMs () > 200)
    {
    digitalWrite(2, !digitalRead (2)); 
    t2.reset ();
    }

 if (t3.intervalMs () > 500)
    {
    digitalWrite(3, !digitalRead (3)); 
    t3.reset ();
    }
 
}  // end of loop



The example code flashes two LEDs at different intervals. The variables t2 (for pin 2) and t3 (for pin 3) are used to see if the time is up to toggle the LED state.

Note that the millisecond interval wraps around after about 50 days, and the microsecond interval wraps around after about 70 minutes. The wrap-around itself is handled correctly, but if you need to time an interval longer than 70 minutes you would need to check intervalMs rather than intervalUs.

As with millis() and micros() if you turn off interrupts the times may be out.

Warning: If you try to move the variables inside a function you will probably need to make them static (or they will reset each time the function is entered), like this:


void loop() {
static Elapsed t2, t3;  // must have static here
  // ...
}


Amended on Sun 22 Jan 2012 06:40 PM by Nick Gammon
#1
hey nick, thanks for the many examples.
i *think* there is a typo in the closing code box
it has a void loop() in there.

also i would like to explore ways of dynamicly creating this elapsed timers. what is missing in this code?

void setup(){
}

void loop(){
  for(int i=0;i<10;i++){
    pulse(i);
  }
}

void pulse(int pin){
  if(time[pin].intervalMs() > 100) //how can i dynamicly create time01?
  {
     digitalWrite(pushPin[pin], LOW);
    time[pin].reset();
  }
}
Amended on Sun 22 Jan 2012 01:46 PM by Yair
Australia Forum Administrator #2
I was illustrating that the timer was inside loop. I've modified the post to make that clearer.

As for dynamically creating timers, you mean an array, like this?


#include <Elapsed.h>

Elapsed time [10];  // array of timers
const byte pushPin [10] =  { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };

void setup(){
}

void loop(){
  for(int i=0;i<10;i++){
    pulse(i);
  }
}

void pulse(int pin){
  if(time[pin].intervalMs() > 100) //how can i dynamicly create time01?
  {
     digitalWrite(pushPin[pin], LOW);
    time[pin].reset();
  }
}


I don't see what you really get here that you couldn't just be using a single timer though.
#3
my understanding was that loop itself is a function, being called every "cycle".
i was sure it a typo as i used function with the 500ms code , without the static inside the loop() and it seems to work.


#include <Elapsed.h>
int goo;
void setup() 
{                
  Serial.begin (115200);   
}  // end of setup

static Elapsed time, time2;

void loop() {

  if (time2.intervalMs () > 500)
  {
    Serial.println ("tick2\n"); 
    H_pulseNod();
    time2.reset ();
  }
}  // end of loop

void H_pulseNod(){

  Serial.print("aaa > ");
  Serial.println(millis());
  if(time.intervalMs() > 1000)
  {  
    goo++;
    Serial.print("goo > ");
    Serial.println(goo);

    time.reset();
  }

}


im currently using tons of methods from your generous examples. especially the Serial state machine, clearly writen and so needed.
Amended on Sun 22 Jan 2012 07:16 PM by Yair
Australia Forum Administrator #4
What you have is fine. However your two variables time and time2 are not inside the loop(). If they were, you would need "static" or they get reset every time through loop().

Quote:

im currently using tons of methods from your generous examples ... clearly writen and so needed


Thanks! It's nice to get feedback. :)
#5
im having difficulties getting my digital pins to run in sequence, like in the chase example (example >control>arrays)
basically im looking for array with no delay. currently im not using array, just trying to get the sequence going. but im missing something.



void HwaveLeft(){  

  if(timerChase.intervalMs() > waveIntrvl && waveState==0){     
    H_pulse(0);
    waveState=1;
  }
  if(timerChase.intervalMs() > waveIntrvl*2 && waveState==1){     
    H_pulse(1);
    waveState=2;
  }
  if(timerChase.intervalMs() > waveIntrvl*4 && waveState==2){     
    H_pulse(2);
    waveState=3;
  }
  if(timerChase.intervalMs() > waveIntrvl*5 && waveState==3){     
    H_pulse(3);
    waveState=0;
    timerChase.reset();  
  }

void H_pulse(int pin){
  if(time[pin].intervalMs() > intrvl_kick && Hstate[pin]==0)
  {
    H_bwd(pin);
    Hstate[pin]=1;
  }
  if(time[pin].intervalMs() > intrvl_kick+intrvlOFF && Hstate[pin]==1) //50
  {
    H_fwd(pin);
    Hstate[pin]=2;
  }

  if(time[pin].intervalMs() > intrvl_kick+intrvlON && Hstate[pin]==2) //15
  {
    H_off(pin);
    Hstate[pin]=0;
    time[pin].reset();
  }
}



btw. feel free to direct me to the arduino forums if you see fit..
Australia Forum Administrator #6
Yes, probably a good idea. People are always asking about doing things in sequence there. If you make a post (put the whole sketch there, not just parts of it) and send me a PM on the forum giving the post link, I'll take a look at it.