Arduino Timer Interrupts Tutorial

100% found this document useful (1 vote)
202 views7 pages
The document discusses using timers with microcontrollers like AVR and Arduino boards. It explains that timers can trigger interrupts to run code asynchronously and independently of the main…

Uploaded by

bugaboo2323
  • Introduction
  • How Timers Work
  • Configuring Timers
  • Timer Prescaling and CTC
  • Advanced Usage
  • Conclusion and Further Resources

Microcontroller tutorial series: AVR and Arduino timer interrupts

Does your program seem like its trying to do too much at once? Are you using a lot of d e l a y ( )or w h i l e ( )loops that are holding other things up? If so, your project is a good candidate to use timers. In this tutorial, well discuss AVR and Arduino timers and how to use them to write better code. In our prior article, we covered interrupt basics and how to use external interrupts that are triggered by a pin change or similar event. Check it out if youre looking to brush up on interrupts in general. This chapter moves on to timer interrupts and talks about their applications in Arduino projects or custom AVR circuits. Almost all Arduino boards are powered by AVR 8-bit processors, so to experience the full power of timers youll use the same techniques no matter which platform youre on. Heres the tutorials table of contents: What is a timer? How do timers work? Types of timers Configuring and running the timer Timer prescaling and CTC Going further

What is a timer?
Youre probably familiar with the general concept of a timer: something used to measure a given time interval. In microcontrollers, the idea is the same. You can set a timer to trigger an interrupt at a certain point in the future. When that point arrives, you can use the interrupt as an alert, run different code, or change a pin output. Think of it as an alarm clock for your processor. The beauty of timers is that just like external interrupts, they run asynchronously, or independently from your main program. Rather than running a loop or repeatedly calling m i l l i s ( ) , you can let a timer do that work for you while your code does other things. For example, say youre building a security robot. As it roams the halls, you want it to blink an LED every two seconds to let potential intruders know theyll be vaporized if they make a wrong move. Using normal code techniques, youd have to set a variable with the next time the LED should blink, then check constantly to see if that time had arrived. With a timer interrupt, you can set up the interrupt, then turn on the timer. Your LED will blink perfectly on cue, even while your main program executes its complicated t e r m i n a t e V i l l i a n ( ) routine.

How do timers work?


Timers work by incrementing a counter variable, also known as a counter register. The counter register can count to a certain value, depending on its size. The timer increments this counter one step at a time until it reaches its maximum value, at which point the counter overflows , and resets back to zero. The timer normally sets a flag bit to let you know an overflow has occurred. You can check this flag manually, or you can also have the timer trigger an interrupt as soon as the flag is set. Like any other interrupt, you can specify an Interrupt Service Routine (ISR) to run code of your choice when the timer overflows. The ISR will reset the overflow flag behind the scenes, so using interrupts is usually your best option for simplicity and speed. In order to increment the counter value at regular intervals, the timer must have access to a clock source. The clock source generates a consistent repeating signal. Every time the timer detects this signal, it increases its counter by one. Because timers are dependent on the clock source, the smallest measurable unit of time will be the period of this clock. For example, if we provide a 1 MHz clock signal to a timer, we can calculate our timer resolution (or timer period) as follows:

T=t i m e rp e r i o d ,f=c l o c kf r e q u e n c y T=1/f T=1/1M H z=1/1 0 ^ 6H z T=( 1*1 0 ^ 6 )s

Our timer resolution is one millionth of a second. You can see how even relatively slow processors can break time into very small chunks using this method. You can also supply an external clock source for use with timers, but in most cases the chips internal clock is used as the clock source. This means that your minimum timer resolution will be based on your processor speed (either 8 or 16 MHz for most 8-bit AVRs).

Types of timers
If youre using any of the standard Arduino variants or an 8-bit AVR chip, you have several timers at your disposal. In this tutorial, well assume youre using a board powered by the AVR ATmega168 or ATmega328. This includes the Arduino Uno, Duemilanove, Mini, any of Sparkfuns Pro series, and many similar designs. You can use the same techniques on other AVR processors like those in the Arduino Mega or Mega 2560, youll just have to adjust your pinout and check the datasheet for any differences in the details. The ATmega168 and ATmega328 have three timers: Timer0, Timer1, and Timer2. They also have a watchdog timer, which can be used as a safeguard or a software reset mechanism. However, we dont recommend messing with the watchdog timer until you get comfortable with the basics. Here are a few details about each timer:

T I ME R 0
Timer0 is an 8-bit timer, meaning its counter register can record a maximum value of 255 (the same as an unsigned 8-bit byte). Timer0 is used by native Arduino timing functions such as d e l a y ( )and m i l l i s ( ) , so you Arduino users shouldnt mess with it unless youre comfortable with the consequences.

T I ME R 1
Timer1 is a 16-bit timer, with a maximum counter value of 65535 (an unsigned 16-bit integer). The Arduino Servo library uses this timer, so be aware if you use it in your projects.

T I ME R 2
Timer2 is an 8-bit timer that is very similar to Timer0. It is utilized by the Arduino t o n e ( )function.

T I ME R 3 , T I M E R4 , T IM E R 5
The AVR ATmega1280 and ATmega2560 (found in the Arduino Mega variants) have an additional three timers. These are all 16-bit timers,

and function similarly to Timer1.

Configuring and running the timer


In order to use these timers, we need to set them up, then make them start running. To do this, well use built-in registers on the AVR chip that store timer settings. Each timer has a number of registers that do various things. Two of these registers hold setup values, and are called TCCRxA and TCCRxB, where x is the timer number (TCCR1A and TCCR1B, etc.). TCCR stands for Timer/Counter Control Register. Each register holds 8 bits, and each bit stores a configuration value. Here are the details, taken from the ATmega328 datasheet:

To start using our timer, the most important settings are the last three bits in TCCR1B, CS12, CS11, and CS10. These dictate the timer clock setting. By setting these bits in various combinations, we can tell the timer to run at different speeds. Heres the relevant table from the datasheet:

By default, these bits are set to zero. Lets use a simple example, and say that we want to have Timer1 run at clock speed, with one count per clock cycle. When it overflows, well run an Interrupt Service Routine (ISR) that toggles a LED tied to pin 2 on or off. Well write Arduino code for this example, though well use avr-libc routines wherever they dont make things overly complicated. AVR pros can adapt as they see fit. First, we initialize the timer:

/ /a v r l i b cl i b r a r yi n c l u d e s # i n c l u d e< a v r / i o . h > # i n c l u d e< a v r / i n t e r r u p t . h > # d e f i n eL E D P I N2 v o i ds e t u p ( ) { p i n M o d e ( L E D P I N ,O U T P U T ) ; / /i n i t i a l i z eT i m e r 1 c l i ( ) ; / /d i s a b l eg l o b a li n t e r r u p t s T C C R 1 A=0 ; / /s e te n t i r eT C C R 1 Ar e g i s t e rt o0 T C C R 1 B=0 ; / /e n a b l eT i m e r 1o v e r f l o wi n t e r r u p t : T I M S K 1=( 1< <T O I E 1 ) ; / /S e tC S 1 0b i ts ot i m e rr u n sa tc l o c ks p e e d : T C C R 1 B| =( 1< <C S 1 0 ) ; / /e n a b l eg l o b a li n t e r r u p t s : s e i ( ) ; }

Youll notice that we used a new register, T I M S K 1 . This is the Timer/Counter1 Interrupt Mask Register. It controls which interrupts the timer can trigger. Setting the TOIE1 bit tells the timer to trigger an interrupt when the timer overflows. We can also set other bits to trigger other interrupts. More on that later. Once we set the CS10 bit, the timer is running, and since weve enabled an overflow interrupt, it will call the I S R ( T I M E R 1 _ O V F _ v e c t ) whenever the timer overflows. Next, we can define the ISR:

I S R ( T I M E R 1 _ O V F _ v e c t ) { d i g i t a l W r i t e ( L E D P I N ,! d i g i t a l R e a d ( L E D P I N ) ) ; }

Now were free to define our l o o p ( )and our LED will toggle on and off regardless of whats happening in the main program. To turn the timer off, we can set T C C R 1 B = 0at any time. However, lets think about how this will work. Using the code weve written, how fast will our LED blink? Weve set Timer1 to interrupt on an overflow, and lets assume were using an ATmega328 with a 16MHz clock. Since Timer1 is 16 bits, it can hold a maximum value of (2^16 1), or 65535. At 16MHz, well go through one clock cycle every 1/(16*10^6) seconds, or 6.25e-8 s. That means 65535 timer counts will elapse in (65535 * 6.25e-8s) and our ISR will trigger in, oh about 0.0041 seconds. Then again and again, every four thousandths of a second after that. Oops. At this rate, we probably wont even be able to detect blinking. If anything, weve created an extremely fast PWM signal for the LED thats running at a 50% duty cycle, so it may appear to be constantly on but dimmer than normal. An experiment like this shows the amazing power of microprocessors even an inexpensive 8-bit chip can process information far faster than we can detect.

Timer prescaling and CTC


Luckily, the good engineers at Atmel thought of this problem, and included some options. It turns out you can also set the timer to use a prescaler, which allows you to divide your clock signal by various powers of two, thereby increasing your timer period. For example, lets say wed rather have our LED blink at one second intervals. Going back to the TCCR1B register, we can use the three CS bits to set a better timer resolution. If we set CS10 and CS12 using T C C R 1 B| =( 1< <C S 1 0 ) ;and T C C R 1 B| =( 1< <C S 1 2 ) ; , we divide our clock source by 1024. This gives us a timer resolution of 1/(16*10^6 / 1024), or 6.4e-5 seconds. Now the timer will overflow every (65535 * 6.4e5s), or 4.194s. Hm, too long. What can we do?

It turns out theres another mode of operation for AVR timers. This mode is called Clear Timer on Compare Match, or CTC. Instead of counting until an overflow occurs, the timer compares its count to a value that was previously stored in a register. When the count matches that value, the timer can either set a flag or trigger an interrupt, just like the overflow case. To use CTC, lets start by figuring out how many counts we need to get to our one second interval. Assuming we keep the 1024 prescaler as before, well calculate as follows:

( t a r g e tt i m e )=( t i m e rr e s o l u t i o n )*( #t i m e rc o u n t s+1 )

and rearrange to get

( #t i m e rc o u n t s+1 )=( t a r g e tt i m e )/( t i m e rr e s o l u t i o n ) ( #t i m e rc o u n t s+1 )=( 1s )/( 6 . 4 e 5s ) ( #t i m e rc o u n t s+1 )=1 5 6 2 5 ( #t i m e rc o u n t s )=1 5 6 2 5-1=1 5 6 2 4

Why did we add the extra +1 to our number of timer counts? In CTC mode, when the timer matches our desired count it will reset itself to zero. This takes one clock cycle to perform, so we need to factor that into our calculations. In many cases, one timer tick isnt a huge deal, but if you have a time-critical application it can make all the difference in the world. Now we can rewrite our s e t u p ( )function to configure the timer for these settings:

v o i ds e t u p ( ) { p i n M o d e ( L E D P I N ,O U T P U T ) ; / /i n i t i a l i z eT i m e r 1 c l i ( ) ; T C C R 1 A=0 ; T C C R 1 B=0 ;

/ /d i s a b l eg l o b a li n t e r r u p t s / /s e te n t i r eT C C R 1 Ar e g i s t e rt o0 / /s a m ef o rT C C R 1 B

/ /s e tc o m p a r em a t c hr e g i s t e rt od e s i r e dt i m e rc o u n t : O C R 1 A=1 5 6 2 4 ; / /t u r no nC T Cm o d e : T C C R 1 B| =( 1< <W G M 1 2 ) ; / /S e tC S 1 0a n dC S 1 2b i t sf o r1 0 2 4p r e s c a l e r : T C C R 1 B| =( 1< <C S 1 0 ) ; T C C R 1 B| =( 1< <C S 1 2 ) ; / /e n a b l et i m e rc o m p a r ei n t e r r u p t : T I M S K 1| =( 1< <O C I E 1 A ) ; s e i ( ) ; / /e n a b l eg l o b a li n t e r r u p t s }

And well need to replace our overflow ISR with a compare match version:

I S R ( T I M E R 1 _ C O M P A _ v e c t ) { d i g i t a l W r i t e ( L E D P I N ,! d i g i t a l R e a d ( L E D P I N ) ) ; }

Thats all there is to it! Our LED will now blink on and off at precisely one second intervals. And as always, were free to do anything we want in l o o p ( ) . As long as we dont change the timer settings, it wont interfere with our interrupts. With different mode and prescaler settings, theres no limit to how you use timers. Heres the complete example in case youd like to use it as a starting point for your own project. Double click to copy:

/ /A r d u i n ot i m e rC T Ci n t e r r u p te x a m p l e / /w w w . e n g b l a z e . c o m / /a v r l i b cl i b r a r yi n c l u d e s # i n c l u d e< a v r / i o . h > # i n c l u d e< a v r / i n t e r r u p t . h > # d e f i n eL E D P I N2 v o i ds e t u p ( ) { p i n M o d e ( L E D P I N ,O U T P U T ) ; / /i n i t i a l i z eT i m e r 1 c l i ( ) ; T C C R 1 A=0 ; T C C R 1 B=0 ;

/ /d i s a b l eg l o b a li n t e r r u p t s / /s e te n t i r eT C C R 1 Ar e g i s t e rt o0 / /s a m ef o rT C C R 1 B

/ /s e tc o m p a r em a t c hr e g i s t e rt od e s i r e dt i m e rc o u n t : O C R 1 A=1 5 6 2 4 ; / /t u r no nC T Cm o d e : T C C R 1 B| =( 1< <W G M 1 2 ) ; / /S e tC S 1 0a n dC S 1 2b i t sf o r1 0 2 4p r e s c a l e r : T C C R 1 B| =( 1< <C S 1 0 ) ; T C C R 1 B| =( 1< <C S 1 2 ) ; / /e n a b l et i m e rc o m p a r ei n t e r r u p t : T I M S K 1| =( 1< <O C I E 1 A ) ; / /e n a b l eg l o b a li n t e r r u p t s : s e i ( ) ; } v o i dl o o p ( ) { / /d os o m ec r a z ys t u f fw h i l em yL E Dk e e p sb l i n k i n g } I S R ( T I M E R 1 _ C O M P A _ v e c t ) { d i g i t a l W r i t e ( L E D P I N ,! d i g i t a l R e a d ( L E D P I N ) ) ; }

Going further
Keep in mind that you can use the built-in ISRs to extend timer functionality. For example, if you wanted to read a sensor every 10 seconds, theres no timer setup that can go this long without overflowing. However, you can use the ISR to increment a counter variable in your program once per second, then read the sensor when the variable hits 10. Using the same CTC setup as in our previous example, our ISR would look something like this:

I S R ( T I M E R 1 _ C O M P A _ v e c t ) { s e c o n d s + + ; i f( s e c o n d s= =1 0 ) { s e c o n d s=0 ; r e a d M y S e n s o r ( ) ; } }

Note that in order for a variable to be modified within an ISR, it must be declared as v o l a t i l e . In this case, wed need to declare v o l a t i l eb y t es e c o n d s ;or similar at the beginning of our program.

This tutorial covers the basics of timers. As you start to understand the underlying concepts, youll want to check the datasheet for more information on your particular chip. Datasheets are readily available on Atmels website. To find them, navigate to the page for your device (8-bit AVRs found here) or do a search for your chip model. Theres a lot of information to wade through, but the documentation is surprisingly readable if you have the patience. Otherwise, experiment and have fun! Check out our other tutorials if youre looking for more knowledge, or sign up for our email newsletter for future AVR and Arduino updates.

Common questions

Powered by AI

AVR timers can manage simultaneous tasks by triggering interrupts at specific intervals, allowing the execution of different routines independently of the main loop. This is particularly useful for tasks that require regular updates, such as refreshing a display, reading sensors, or controlling actuators, where each task is handled by its interrupt-driven execution, maintaining system responsiveness and ensuring all tasks receive appropriate processor time without relying on sequential execution .

AVR timers can create non-blocking delays by setting up a timer interrupt to execute periodically. Instead of using delay(), a timer can run independently, triggering an interrupt service routine (ISR) that signals when a delay period has passed. This method allows the main program to continue executing other tasks while the timer maintains the delay schedule, enhancing the program's responsiveness and efficiency .

Timer0 is an 8-bit timer utilized by Arduino's delay() and millis() functions, making it less suitable for custom interrupts without affecting these functions . Timer1 is a 16-bit timer with a larger maximum count, used by the Arduino Servo library, providing more precise control and longer counting intervals, thus more suitable for activities like generating PWM signals . Timer2 is also an 8-bit timer, similar to Timer0, often used by the Arduino tone() function, suitable for creating audio tones but with less precision than Timer1 .

Challenges in integrating timer interrupts include the risk of interrupt conflicts when multiple interrupts overlap in execution, which can lead to timing inaccuracies or missed interrupts. Additionally, incorrect timer or ISR configurations can cause unintended behaviors like frequent and unintended resets. Careful management of shared resources and minimization of operations in ISRs are necessary to prevent these issues, as well as understanding the influence of prescaler settings and potential hardware limitations .

The primary trade-off between using overflow mode and CTC mode lies in precision versus simplicity. Overflow mode is simpler but less precise for specific intervals, as it depends on the register size, while CTC allows precise interval definition by comparing with a compare register. Prescalers offer another trade-off: using a higher prescale slows down the timer, providing longer intervals but reducing resolution. Balancing these factors involves aligning them with the application's needs, such as counting time intervals accurately versus the available processing power and cycle time requirements .

Timer interrupts allow Arduino projects to manage multiple tasks more efficiently by enabling asynchronous task execution. Instead of using blocking code such as delay() or while() loops that halt other operations, timers trigger interrupts that can execute specific code at designated intervals незалежно of the main program's execution. This functionality is crucial for scenarios where timing precision and multitasking are required, such as blinking an LED while executing a complicated routine .

Volatile variables are essential when used with timers and interrupts because they tell the compiler that the variable can be changed in an ISR, preventing the compiler from optimizing code by assuming data does not change beyond normal execution. This is crucial for ensuring that any variable modified inside an interrupt service routine (ISR) is read correctly by the main program, allowing reliable and predictable behavior from the microcontroller, especially in time-critical applications .

Prescalers allow the division of the clock frequency by a predetermined factor, thus altering the timer's counting speed and resolution. By reducing the clock frequency that the timer uses, prescalers increase the timer's resolution, effectively slowing down the counting rate, which allows for longer time intervals between interrupts. This is crucial when the desired interval exceeds the timer's natural capability at full clock speed, e.g., extending the overflow interval for a visible LED blink .

An external clock source may be chosen for AVR timer configuration when precise timing is needed that cannot be provided by the internal oscillator due to drift or limited accuracy. Considerations include ensuring compatibility with the microcontroller, matching voltage levels, and stability of the external clock frequency to achieve the desired timer resolution and accuracy. External clocks are critical in applications requiring synchronization or precise timing over an extended period .

CTC mode allows the timer to trigger an interrupt without waiting for an overflow. Instead, the timer compares its current value to a predefined value and triggers an interrupt or sets a flag upon a match, providing precise control over timer intervals. This is particularly useful for setting precise time intervals in applications like periodic sensor readings, as it avoids the delays associated with overflow handling and can be configured to count less than the timer's maximum value .

Microcontroller tutorial series: AVR and Arduino timer
interrupts
Does your program seem like it’s trying to do too much at o
How do timers work?
Timers work by incrementing a counter variable, also known as a counter register. The counter register ca
and function similarly to Timer1.
Configuring and running the timer
In order to use these timers, we need to set them up, the
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 2
void setup()
{
 
pinMode(LEDPIN,
It turns out there’s another mode of operation for AVR timers. This mode is called Clear Timer on Compare Match, or CTC. Inst
// Arduino timer CTC interrupt example
// www.engblaze.com
// avr-libc library includes
#include <avr/io.h>
#include <avr/int
This tutorial covers the basics of timers. As you start to understand the underlying concepts, you’ll want to check the datas

You might also like