You are on page 1of 17

CONTENTS LINKS

Home Timers/Counters Mouser

Some Programming Just about every microcontroller comes with one or more (sometimes many more) Digikey
Basics built-in timer/counters, and these are extremely useful to the embedded
Avnet
programmer - perhaps second in usefulness only to GPIO. The term
Embedded Hello World
timer/counter itself reflects the fact that the underlying counter hardware can Arrow
GPIO Outputs usually be configured to count either regular clock pulses (making it a timer) or
irregular event pulses (making it a counter). This tutorial will use the term Jameco
Output Examples timer rather than timer/counter for the actual hardware block, in the name of
simplicity, but will try and make it clear when the device is acting as an event Sparkfun
GPIO Inputs counter rather than a normal timer. Also note that sometimes timers are called
hardware timers to distinguish them from software timers which are bits of AVR Freaks
Input Examples
software that perform some timing function.
Interrupts

Interrupt Examples
Timer basics
Timers/Counters
A typical timer will consist of a prescaler, an N-bit timer/counter register
Timer/Counter (typically N is 8, 16 or 32 bits), one or more N-bit capture registers, and one or
Examples more N-bit compare registers. There will also be control and status registers to
configure and monitor the timer.
LCD Character Displays
Note that this section is called Timers/Counters. The fundamental hardware
Display Multiplexing involved is an up-counter, which counts incoming pulses. A counter, any counter,

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
becomes a timer when the incoming pulses are at a fixed, known frequency. I
Key/Switch
will often use the terms counter and timer interchangeably, but just keep in
Multiplexing
mind that the hardware is always a counter, and that the counter becomes a
PWM timer if we are feeding it a fixed, known frequency to count.

UARTs It is also worth noting that the size in bits of a timer is not directly related to
the size in bits of the CPU architecture. Nothing prevents an 8-bit microcontroller
SPI from having 16-bit timers (most do, in fact), nor does anything prevent a 32-bit
uC from having 16-bit timers (and some do).
I2C
Something else that you may see are uCs that have multiple timers of different
ADCs size. For example, most AVRs have both 8-bit and 16-bit timers, and some
LPC2xxx devices have both 32-bit and 16-bit timers.
WDTs

Real Time Operating


Systems
Prescaler
Coming Soon
The prescaler takes the basic timer clock frequency (which may be the CPU clock
frequency or may be some higher or lower frequency) and divides it by some
value before feeding it to the timer, according to how the prescaler register(s)
are configured. The prescaler values that may be configured might be limited to
a few fixed values (powers of 2), or they may be any integer value from 1 to 2^P,
where P is the number of prescaler bits.

The purpose of the prescaler is to allow the timer to be clocked at the rate you
desire. For shorter (8 and 16-bit) timers, there will often be a tradeoff between
resolution (high resolution requires a high clock rate) and range (high clock rates
cause the timer to overflow more quickly). For example, you cannot (without
some tricks) get 1us resolution and a 1sec maximum period using a 16-bit timer.
If you want 1us resolution you are limited to about 65ms maximum period. If you
want 1sec maximum period, you are limited to about 16us resolution. The
prescaler allows you to juggle resolution and maximum period to fit your needs.

As an example of a fixed selection prescaler, many AVR devices allow for fixed
prescale values of 1, 8, 64, 256 and 1024. If the system clock frequency is e.g.
8MHz, this results in a timer clock period of 0.125, 1, 8, 32 or 128 microseconds
per clock tick. Likewise, the 9S12 prescaler allows fixed prescale values in powers
of 2: 1, 2, 4, 8, 16, 32, 64 and 128.

As an example of a fully configurable prescaler, the NXP LPC2000 family has 32-
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
bit timers that have 32-bit prescalers, which allow for any prescale value between
1 and 2^32. Such fully configurable prescalers are of course more flexible than
fixed selection prescalers, but in practice the fixed selection prescalers are
usually adequate, though they may require that more thought be given to
choosing a system clock frequency and other timing values.

In the prescaler section I also include any configuration logic to clock the timer
with an external signal, present on an input pin of the C. If this external signal
is a fixed frequency then the counter hardware continues to act as a timer, but if
the external signal consists of pulses that are not fixed and regular then the
counter is simply acting as a counter, as was discussed above. When a
timer/counter is configured as a counter, it is most commonly used in conjunction
with some timebase (another onboard timer or an external timebase signal) to
count pulses per some time interval.

Timer Register

The timer register itself is most typically a N-bit up-counter, with the ability to
read and write the current count value, and to stop or reset the counter. As
discussed, the timer is driven by the prescaler output. Any regular pulses which
drive the timer, whatever their source, are often called ticks and that is the
term which will be used here. Understand that timers do not necessarily time in
seconds or milliseconds or microseconds, they time in ticks. Depending on the
hardware design and software configuration, the rate of these ticks may be
configured to some human-friendly value such as e.g. 1 microsecond or 1
millisecond, or they may be some oddball value which makes more sense for a
particular system design.

The ways in which the timer can be manipulated will be discussed in the
following sections on capture and compare registers.

Capture Registers

A capture register is a register which can be automatically loaded with the current
counter value upon the occurance of some event, typically a transition on an
input pin. The capture register is thus used to take a snapshot of the timer at
the moment when the event occurs. A capture event can also be configured to
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
the moment when the event occurs. A capture event can also be configured to
generate an interrupt, and the ISR can save or otherwise use the just-captured
timer snapshot. Since the capture happens in hardware, there is no latency error
introduced into the snapshot value as there would be if the capture was done in
software.

Capture registers can be used, among other things, to time intervals between
pulses, to determine the high and low times of input signals, and to time the
intervals between two different input signals.

Compare/Match Registers

Compare registers (sometimes also called match registers) hold a value against
which the current timer value is automatically and continuously compared. A
compare register is used to trigger an event when the value in the timer register
matches the value in the compare register. If the timer/counter is configured as
a timer, using compare registers will let you generate events (output pin changes
and/or interrupts and/or timer resets) at known and precise times. If the T/C is
configured as a counter, the compare registers can generate events based on
preset counts being achieved.

One example of the use of a compare register is to generate a timer tick, a


fixed timer interrupt used for system software timing. For example, if a 5ms tick
is desired, and the timer is configured with a 1us clock, setting a compare
register to 5000 will cause a compare event after 5ms. If that compare event is
configured to both generate an interrupt and to reset the timer back to 0, the
result will be an endless stream of 5ms interrupts.

Another use of a compare register would be to generate a variable width pulse.


Set an output high (or low) when the timer is at 0 (many timers have this
capability in hardware), set the compare register to the value of the pulse width,
and on the compare event set the output low (or high). Use a second compare
register with a larger value to set the pulse interval by resetting the timer on
compare, or just let the timer roll over from -1 to 0 and let that be the pulse
interval.

Using a similar technique, but toggling an output pin on every compare, a


variable frequency square wave can easily be generated with a single compare
register.

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
Some Different Ways to Use Timers

What follows are some examples of how different ways to use timers. The
examples are just a beginning, something to convey a basic understanding of
how timers work and can be used.

Timer Polling

While timers are most commonly used in conjunction with timer-generated


interrupts, it is also useful to understand how timers can be used in a polling
situation. Polling means sitting in a software loop, reading some register or
memory location, and waiting for some value in that location.

// poll for a value in a memory location

while ( Location_Im_Polling != VALUE_IM_WAITING_FOR )


; // wait for this location to contain specified value

// or poll for specific bit(s) to go high

while ( !(Location_Im_Polling & MY_BITMASK) )


; // wait for bit(s) of MY_BITMASK to go high

Polling a timer results in an approach between simple cycle-counting on the one


hand, and timer-generated interrupts on the other. The advantage of polling a
timer is that the accuracy of the timer is for the most part retained. The
disadvantage is that the time the C spends polling the timer is still wasted
time, instruction cycles that could otherwise be doing useful work.

Polling for a Timer Value

This is a technique you probably never want to use in a serious project, but its
useful to help you start thinking about how timers work. This technique is very
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
similar to your earlier software delay loops, with the difference being that now,
instead of timing by monitoring a variable that is incremented (or decremented)
in software, you will monitor the hardware timer register. Notice the similarity:

Software delay loop (COUNT is the number of software loops to wait)

1. Set variable to 0
2. Increment variable
3. Check if variable is at COUNT
4. If not, loop to #2
5. If yes, finished

Timer register polling loop (COUNT is the number of timer ticks to wait)

1. Set timer register to 0


2. Increment timer register (this happens in the hardware, not the software!)
3. Check if timer register is equal to or greater than COUNT
4. If not, loop to #3
5. If yes, finished

The difference is simply in which timer variable is monitored, and in how it is


incremented. The advantage of using the hardware timer is that you can do
other work e.g. service interrupts and you will not lose accuracy, unless you
happen to be doing the other work at the exact time the timer register reaches
your desired COUNT value.

Polling for a Timer Flag

This is another technique you probably never want to use in a serious project, but
it will introduce you to one of the useful flags (hardware status bits) that are
associated with timers:

Timer overflow flag polling loop (COUNT is the number of timer ticks to wait)

1. Set timer register to 0-COUNT


2. Increment timer register (this happens in the hardware, not the software!)
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
3. Check if timer overflow flag is set
4. If not, loop to #3
5. If yes, finished

This method utilizes the timer overflow flag (which most if not all timers will
have), which will be set when the timer register counts over from -1 to 0. -1
would be 0xFF for an 8-bit timer, 0xFFFF for a 16-bit timer, and 0xFFFFFFFF for a
32-bit timer. Since the flag signals when the timer goes to zero, we start the
timer at 0-COUNT to get COUNT ticks.

The main advantage of this method over timer register polling is that we have an
unambiguous indication of when the end of the interval has occurred. There are
some pathological possibilities in the timer register polling, if the COUNT value is
near N-1, where one could miss the COUNT value and have the timer roll over to
0 and then wed end up waiting another 2^N ticks. By checking instead for the
overflow flag, even if we missed the exact time it was set, the flag will never
unset by itself, so we will always detect it as soon as our software polling loop
comes around to the next check. Another advantage is that the code to compare
for a given COUNT value may be larger and slower than the code to check for a
single bit flag. Slower code means less precision as to when the time interval has
ended.

Keep in mind that most, if not all, timer hardware will require the software to
explicitly clear the overflow flag after it has been set and detected.

Timer overflow interrupt

Now we begin to get into the natural pairing that exists between timers and
interrupts. This method is similar to the timer overflow polling loop except that
now the timer overflow triggers an interrupt, and the ISR can handle the end of
the timing interval directly, or it can signal the main code to handle the end of
the interval.

Whereas with the polling method the software had to clear the overflow flag, the
hardware on many microcontrollers will automatically clear the flag when the
timer is configured to generate an interrupt.

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
Timer compare interrupt with automatic timer clear

This method is similar to the timer overflow interrupt method, but the interrupt is
generated by match between the timer register and a compare register. The
compare event which triggers the interrupt also automatically clears the timer
register, so for the first time we have a configuration that can generate repetitive
timing intervals with no slippage or loss of accuracy between intervals. This is a
major advance in our timer operation. While it is often useful to be able to
achieve single timing intervals, it is much more useful to be able to achieve
repetitive, constant timing intervals. This method allows us to achieve such
intervals.

Note that for most devices it is also possible to configure a timer to reset on
compare without generating an interrupt. This has benefits when the timer is
being used to generate waveforms, but it offers no particular advantage as a
means of generating repetitive intervals using software polling.

Note also that it is also possible, as was discussed above, to configure a timer to
interrupt on overflow, while letting the timer continue to run. This will generate
an interval every 2^N timer ticks. This is fundamentally the same as the
compare interrupt with automatic clear, but it is much more limited since the
timer count cannot be altered from its maximum count of 2^N. Thus the only
control the programmer has over the timing interval is through adjusting the
prescaler, while with the automatic clear method both the prescaler and the
compare value can be adjusted, giving much more control over the timer interval.

Timer compare interrupt with leapfrogging

This method also uses a compare match to generate an interrupt, but does not
configure the timer to clear when the match occurs. Thus the interrupt is
triggered but the timer continues to run. It will eventually overflow, going from
2^N-1 to 0, but that overflow will not stop the timer either. So the timer register
counts indefinitely, going from 0 to 2^N-1 and repeating that cycle endlessly. To
generate equal intervals using this method, the compare register must be
modified on each interrupt. This is actually quite simple, as the modification just
involves adding a constant (the timer period, in ticks) to the compare register (as

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
always, ignoring any overflow, as discussed in the section on leapfrogging). In
case you were wondering, the term "leapfrogging" is an informal one, referring to
the way in which one or more compare register values leap ahead as the compare
events occur.

Using timer overflows to extend timer resolution

The simplest way to use a timer is to use it for counts that are less than the
natural timer count 2^N. However, it is possible to use a timer to count numbers
greater than the natural timer period by keeping track of overflows and including
the overflow count in the total count calculation.

Potential problem using overflows

There is an atomicity problem when using overflows in the manner described


above. This problem occurs when an overflow occurs between accessing the
timer register and accessing the overflow status, and it occurs no matter in what
order the register and the status are accessed. The problem is that when a timer
overflow occurs between the two accesses, the data read in those two accesses
becomes inconsistent. One example of this is the following sequence:

Read timer register


Timer overflows
Read overflow status

An example of the opposite order is this:

Read overflow status


Timer overflows
Read timer register

In both cases, the combined data of the overflow state and the timer register
yield a corrupted value, much the same as the corrupted values seen in the
discussion on interrupts. The timer overflow is not an interrupt (although it may
generate one), but like an interrupt it results in an asynchronous modification of

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
the data being accessed, unknown to the program.

Luckily, we can detect such an event easily and then correct for it. We can
detect the event because the timer register value after an overflow is less than
the value before the overflow, which is not the case in the normal act of reading
the timer register two times in succession. Similarly, the overflow status after an
overflow is different than the status before an overflow. We can use these facts
to check if the potentially corrupting situation has occurred, and if we detect this,
we can immediately access the data again. This second access of the data,
assuming it is done in a timely fashion, will always be valid because the timer
cannot overflow again so soon after a previous overflow. Note that what we are
detecting is not a corruption of data we cannot detect that with certainty. All
we can detect is that an overflow happened at some point in the sequence of
accesses. The timing of the overflow may have resulted in corruption, or there
may have been no corruption, but since we cannot know that the data accesses
were uncorrupted, we perform the accesses again to obtain a guarantee of
uncorrupted data. This is a technique worth remembering in any case where you
are accessing multiple pieces of data that can be changing as they are being
accessed.

Read timer register


Read overflow status (timer may have overflowed after reading timer
register)
Compare current timer register with value from #1
If current value is less than first value, an overflow occurred sometime
between 1st and 2nd timer register reads
Read overflow status again and use in conjunction with 2nd timer register
value

The same technique works if the order of data accesses is reversed

Read overflow status


Read timer register (timer may have overflowed after reading overflow
status)
Compare current overflow status with first overflow status value
If current overflow status is not the same as first overflow status, an
overflow occurred sometime between 1st and 2nd overflow status reads
Read timer register again and use in conjunction with 2nd overflow status
value

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
This same problem can occur with other hardware. For example, imagine a 16-bit
timer that must be read as two separate 8-bit values. Between reading the first
byte and reading the second byte of the 16-bit value, an overflow from the LSB to
the MSB may have occurred. This will result in a corrupted 16-bit value. The
solution is to read the slower-changing byte (MSB) first, then read the faster-
changing byte (LSB), then read the slower-changing byte (MSB) again. If the two
MSB values are different, an LSB overflow occurred at some point in the access.
If that happened, read both the MSB and the LSB again for guaranteed valid
data.

Want even more bad news? The same problem can occur in writing a 16-bit value
via two 8-bit writes. Example

Write low byte


Timer advances, overflowing low byte
Write high byte - the 16-bit timer value is now corrupted

The good news is that if your 8-bit CPU has a 16-bit timer, the designers have
probably taken that hassle out of reading the timer register (and other changing
16-bit registers) by having a way to perform the entire 16-bit read in one
operation (remember, the problem only occurs if you read the two halves of the
register at different times). In the AVR, for example, reading the low byte of the
16-bit register also copies the high byte into a temporary register, and when you
then read the high byte you are reading the value stored in this temporary
register, so you are reading an entire 16-bit value that was fetched in one
operation. Likewise, to write to a 16-bit register you first write the high byte
which goes into a temporary register, then write the low byte. On writing the low
byte, the high byte stored in the temporary register is written out in the same
operation.

System tick

It is very common to configure a hardware timer to generate a system tick


which controls all the system timing and delays. This tick is often in the range of
1-20ms (50-1000 ticks per second). From such a tick it is easy to generate in
software almost unlimited timing intervals, at the resolution of the tick period.
For example, if you need to display a message for 3 seconds and your system has
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
a 10ms tick, your program would display the message for 300 ticks. During that
time your system will be available for other work, since youre only checking the
tick count at every interrupt. This strategy of extending hardware timers with
software is a very common one and can greatly increase the utility of the C
hardware timers.

The system tick function is so common that some C devices have a dedicated
system tick timer, thus freeing up other onboard timers for other uses. If a C
does not have a dedicated system tick timer, and a system tick is desired, then
one of the regular hardware timers must be dedicated to this task.

If a C has multiple timers, and if some of the timers have higher resolution than
others (e.g. an 8-bit timer and a 16-bit timer, or a 16-bit and a 32-bit timer), it is
usually a good idea to use a lower-resolution timer for the system tick if
possible, thus leaving the higher resolution timer(s) available for other uses
where the higher resolution may be necessary or desirable. Proper choice of
prescaler and timer count, along with suitable choice of system clock frequency,
should always allow a useable system tick interval to be achieved using the
lower-resolution timer. See also the discussion below about how precise a
system tick interval has to be.

More on Leapfrogging

As already mentioned, this unofficial term refers to a useful technique in deriving


one or multiple timing signals or interrupts, which are not simply related, from a
single timer. An example might be where one needs a 10ms interrupt, and also a
42.5ms interrupt. One solution would be to find the GCD of those two periods,
which in this case is 2.5ms, configure a 2.5ms interrupt, and perform the 10ms
task every 4 interrupts, and the 42.5ms task every 17 interrupts. Another
solution would be to use two separate timers, one for each interval. A third
solution would be to use a single timer along with multiple timer compare
registers and the leapfrog technique.

Leapfrogging simply means adjusting the compare register, on each timer


compare event, for the next interval. This is as opposed to the more common
method of leaving the compare register value set, and having a compare event
automatically reset the timer. In the leapfrog technique, the timer is never
reset, but runs as a simple binary timer, rolling over from its maximum count

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
(2^N-1 for an N-bit timer) to 0. On each compare interrupt, instead of causing
the timer to reset, the compare register is advanced to the next interval. This
advancing is a simple addition, e.g.:

OCR1A += 42500; // leapfrogs 42.5ms, assuming a 1us timer tick

Note that this calculation will at some point overflow or wrap around. For a 16-
bit compare register this example will overflow the very first time the calculation
is performed. This is, perhaps surprisingly, not a problem, since the timer count
register overflows or wraps around in exactly the same way. Thus, taking our
example through two intervals:

OCR1A = 42500; // initial compare from 0, 0xA604



OCR1A += 42500; // 0x14C08 doesnt fit into 16 bits, so we get 0x4C08 with an overflow

After the timer reaches 0xA604, the first compare value, it will count 0x59FC
(23036d) more counts before overflowing, and then 0x4C08 (19464d) counts at
which point the compare to OCR1A happens. This gives a total of
23036+19464=42500 counts, just as we desired. The overflow in the calculation
had no ill effect on the time interval.

Note that it doesnt matter when, after the compare event, that the compare
register is updated, just as long as it is updated before the next compare is
scheduled. That is becuase you are not trying to do math based on an advancing
timer value, but on a fixed previous compare value. This means that interrupt
latency does not affect the accuracy of the compare events.

As stated, one situation where the leapfrog technique is useful is in achieving


multiple non-simply-related timing intervals, either for interrupts or for driving
output pins. It is also useful in obtaining non-equal intervals. Suppose e.g. a
certain process required sequential intervals of 1ms, 7ms, 18ms and 3.5ms.
Again, this could be done by counting 0.5ms ticks, or it could be done by
leapfrogging 1, 7, 18, 3.5 and then back to 1ms. Either method requires keeping
track of the current interval and determining the next interval value, so there is
no clear advantage of one or the other method in that regard.

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
Software Timers

As we have said, hardware timers are an extremely useful resource, but they are
also a limited resource, both in terms of the number of hardware timers a C may
have, and of the resolution of those timers. If your application needs more
timers than your hardware offers, and if the timing requirements for those extra
timers are fairly slow (relative to the processor speed), then the extra timers
can easily be created in software. Likewise, the range of hardware timers can be
extended through software.

Do you really need a 10.00000 ms tick?

Maybe you do, but quite often you dont. For example, suppose you have an AVR
running at 10 MHz, and you want to use one of its 8-bit timers to generate a
10ms tick. This means you want to divide the system clock frequency of
10,000,000 down to 100, for a total division of 100,000 With an 8-bit timer this
requires the use of a 1024 prescale, which means our timer is being driven by a
frequency of 10 MHz / 1024 or 19531.25 Hz. (If you prefer to think in terms of
periods rather than frequencies, you are multiplying your system clock period of
50ns by 1024 for a timer clock period of 51.2us. to get a frequency of 100 Hz
from a frequency of 19,531.25 Hz (or, equivalently, to get a period of 10ms from
a period of 51.2us), you need to divide by 195.3125. Obviously this is not a
value you can enter into your 8-bit timer. So what if you enter 195 instead? You
get a frequency of 100.1603 Hz (period of 9.984ms).

No, its not the 10ms you wanted, but the chances that you cant use this tick
value are very, very small. In fact, just about the only time such a small timing
error would be a problem is when the timer ticks are used to generate time
values for external systems, especially " round number" time values meant for
human evaluation. For most system tick uses, the precise value of the system
tick doesn't matter as much as using that actual value, whatever it may turn out
to be, in calculating any other time values that are based on the tick.

If, due to hardware considerations, your system tick ends up not being a nice
"round number" but you still want to remove long-term drift (say e.g. you want to
maintain an elapsed time for logging events), you can "slip" your system tick
software accumulator to remove any long-term drift.

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
Timer Errors

This section would more accurately be called Integer Arithmetic Errors


Affecting Timer Use, but thats a bit much. The problem we want to address is
that, as you calculate your timer prescale and count values, you can get errors in
your values due to the truncation that occurs with integer arithmetic. Even
though all your math is correct, you can end up with timers that dont time
exactly what you want.

Here is a concrete example. Many microcontroller designs, including our LPC2294


device, use an oddball crystal of 14.7456 MHz. Actually there is nothing oddball
about that value, it is one of the many values that allows for achieving exact
standard UART baud rates e.g. 1200,9600,19200,115200, etc. But at the same
time it can result in timer prescale and count values that are not nice exact
integers. In our example our LPC2294 is configured to quadruple the crystal
frequency to a CPU clock of 58.9824 MHz, and then divide that by 2 to get a
peripheral clock of 29.4912 MHz. This is the clock that is fed into the prescaler.
Further, let us say that we want to get timer ticks of 1us (1MHz). Well, there is
no integer prescale value that will convert 29.4912 MHz into 1 MHz. When we do
our integer math we will get a prescale value of 29 (we would actually load 29-1
into the prescale register, due to the design of the timer). But this value does
not give us 1us ticks, it gives us 0.98334418s ticks. If we wanted to count
ticks to get e.g. a 200ms time interval, and if we counted 200,000 ticks, we
would actually get a 196.66ms interval. Thats an error of more than 1.5%, all
due to the unavoidable truncation error in our prescaler calculation.

There are at least two ways to fix (or at least greatly mimimize) this problem.
One is to use an exact (usually larger) prescale value that avoids integer math
errors. For example, if we had a prescale of 147,456, then we would get ticks of
exactly 147,456/29,491,200 or every 5 ms. If that tick rate is acceptable then
our problem is solved, since 40 ticks give s exactly our 200 ms time interval.
But if we really wanted to keep our (approximately) 1 s tick, then we need to
recalculate how many such ticks make up 200 ms. With our not-quite-right
prescale of 29, we have 29,491,200/29 or about 1,016,938 ticks per second,
rather than our desired 1,000,000 ticks per second. Therefore, to time 200 ms
we need to count not 200,000 ticks but 1,016,938/5 or 203,387 ticks (notice
another integer truncation, the precise but unrepresentable tick count is
203,387.6). This timer value, 203,387, while still not exactly correct, now has an
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
error of less than 1 part in 200,000, rather than our original error of about 1 part
in 60. By taking into account our original prescale truncation error and calculating
our timer value using the truncated prescale value, we have reduced our error by
a factor of more than 3000. Such a reduction could of course easily make the
difference between acceptable timer accuracy and unacceptable timer accuracy.
The key to this improvement is to do the timer math based on the actual
(truncated) prescale value, rather than on the theoretical prescale value before
the truncation.

If this sounds complicated, it's not really. It's just a matter of forcing the same
truncation in the calculation as happens in the hardware. For example:

// calculations for a 200ms (200000us) interval


// timer counts per prescale = F_TIMER / 1000000 (truncates)
// F_PRE is actual clock going INTO prescaler
// F_WANT_TMR is desired clock coming OUT OF prescaler, INTO timer (desired tick rate)
// F_REAL_TMR is actual clock coming out of prescaler, into timer (actual tick rate)

#define F_PRE 29491200UL // from our 14.7456 MHz crystal


#define F_WANT_TMR 1000000UL // we want 1us ticks
#define PRESCALE (F_PRE/F_WANT_TMR) // for ~1us ticks (may truncate)
#define F_REAL_TMR (F_PRE/PRESCALE) // our actual tick rate with truncated prescale
#define TWO_HUN_MSa 200000UL // our intuitive but incorrect value
#define TWO_HUN_MSb ((200000UL*F_REAL_TMR)/F_WANT_TMR) // gives correct value of 203387

Here, dividing by the truncated prescaler value (F_PRE / F_WANT_TMR) causes a


division by the same value that is loaded in the prescaler, which is what we need
in order to get the correct answer, the answer that takes into account the
truncation of the prescaler value.

Event Counters

When timer/counter hardware is used to count external event pulses it is


behaving as an event counter. Some typical examples would be counting the
number of widgets that come down the assembly line in the Acme Widget plant,
or the number of pulses coming off a flywheel engine speed sensor. In the latter
case the goal would be to count the number of pulses in a given time period, in
order to calculate an engine speed. As in that example, it is very common that
open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com
an event counter is used to count not just the number of events, but the number
of events in a given time interval. Thus you will usually see event counters and
timers (hardware or software) used in combination.

One illustrative use of a timer in counter mode is to count the bounces of a


switch. The fact that a mechanical switch or button does bounce was discussed
in an earlier chapter. Connecting a counter to such a switch allows one to see
that bouncing in very concrete terms.

Later when we have gotten a display up and running we will revisit some of these
event counter examples.

open in browser PRO version Are you a developer? Try out the HTML to PDF API pdfcrowd.com

You might also like