In the world of robotics and embedded
programming, there are many
occasions when we need to
wait to do (or while doing)
something – for example,
when flashing an LED,
energizing a solenoid
for a certain length
of time, or delaying
briefly while a servo
repositions. At times,
we need accurate
delays, but often
we are dealing with
situations where
approximate times
are good enough.
This article will look at a
few techniques — some
accurate and some
approximate — using single
or multiple “virtual” timers,
which may be adapted to fulfill a
variety of timing needs.
It’s About
Time(ing)
By Chuck Baird
Have three sets of servos that must move back and forth once every three seconds, but each one is out of phase with the others by a second? Want to flash
an LED six times, starting in one second, with a 0.8 second
cycle time? Want to look around for the line to follow by
alternating left or right turns in larger radii each time?
No problem!
The following discussion will give an overview of each
timing technique and how to use it. Accompanying files on
the SERVO website (
www.servomagazine.com) provide
more detail, examples, and extensively commented C code
that will more fully explain and demonstrate each method.
Built-in Delays
At the easy end of the timing spectrum, some
compilers include macros or library functions that perform
delays. You include an initial declaration which states your
processor clock speed and hard codes the delay:
#define F_CPU 8000000UL
...
_delay_ms(300); // wait 300 milliseconds
Based on the two numbers, the compiler constructs
code sequences of the proper number of instructions to
create the delay. Because the compiler controls the number
of generated instructions, delays built in this way can be
quite accurate. However, before using such tools be sure to
read the fine print – the argument may need to be an
actual number, not a variable. For variable delays, you can
put a “wrapper” function around a hard coded delay,
using an argument to execute the delay a certain number
of times:
void tenths_second(unsigned int sec10) {
while (sec10—) _delay_ms(100);
// 0.1 second delay}
You lose a tiny bit of accuracy because of the function
overhead, but perhaps that is an acceptable compromise
given the added flexibility and convenience it provides.
Easy Delays the Hard Way
In the absence of a built-in macro or function, we can
write simple code to do the same thing although the
accuracy may suffer. Often we don’t care about the exact
timing of a delay, so this may be acceptable. If we aren’t
simultaneously needing to do anything else, we can allow
the delay to eat all the processor cycles without losing any
performance. This is how the built-in delays work.
One easy method of doing this is to write a function
which just loops:
void wait(void) { // may not work - see text
unsigned int t;SERVO 12.2009 41