Arduino Timer Interrupts
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.
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,
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.
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 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
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:
/ /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
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.