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
Class and example code below:
// Elapsed class
// Author: Nick Gammon
// Date: 11th May 2011
class Elapsed
{
unsigned long startus, startms;
public:
// constructor resets time
Elapsed () {
reset ();
};
// reset time to now
void reset () {
startus = micros ();
startms = millis ();
};
// return Elapsed time in milliseconds
unsigned long intervalMs () {
return millis () - startms;
};
// return Elapsed time in microseconds
unsigned long intervalUs () {
return micros () - startus;
};
}; // end of class Elapsed
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;
However if you do, you will probably get these compiler errors:
Elapsed_class_test.cpp.o: In function `loop':
Elapsed_class_test.cpp:62: undefined reference to `__cxa_guard_acquire'
Elapsed_class_test.cpp:62: undefined reference to `__cxa_guard_release'
Elapsed_class_test.cpp:62: undefined reference to `__cxa_guard_acquire'
Elapsed_class_test.cpp:62: undefined reference to `__cxa_guard_release'
To fix that you need to provide these missing functions, as follows (put this code near the start of your sketch):
// this blathering on is in case you want to make the class a static variable in a function
extern "C" {
__extension__ typedef int __guard __attribute__((mode (__DI__)));
int __cxa_guard_acquire(__guard *g) {
return !*(char *)(g);
};
void __cxa_guard_release (__guard *g) {
*(char *)g = 1;
};
void __cxa_guard_abort (__guard *) {
};
}