Arduino Timmer Interrupt
Arduino Timmer Interrupt
Each hardware timer has a digital counter register at its core that counts up based on an input clock signal. If the clock signal is coming from a
fixed-frequency internal source, then it’s said to be working in timer mode. But if the clock input is externally fed from an IO or any async source,
it’s said to be working as a counter that counts incoming pulses.
2. Arduino Timer Prescaler
A prescaler in a hardware timer module is a digital circuit that is used to divide the clock signal’s frequency by a configurable number to bring
down the timer clock rate so it takes longer to reach the overflow (maximum count number).
This is really useful to control the maximum time interval that can be generated using the timer module, the PWM output frequency, or the range
of time that can be measured using the timer module.
The timer prescaler divider values differ from one timer module to another and it’s clearly stated in the datasheet for each timer module (Timer0,
1, and 2).
3. Arduino Timer Interrupts
Arduino timers provide different interrupt signals for various events. Such as timer overflow, when a timer reaches its maximum count value (255
for 8-Bit, and 65535 for 16-Bit timers). It fires an overflow interrupt, rolls back to zero, and starts counting up again.
There is also two output compare registers in each timer (COMPA and COMPB). When the timer register’s counter value reaches COMPA value,
it
drives the OCnA pin HIGH or LOW depending on your configurations, and it also fires a COMPA interrupt (if enabled). And the same goes for
COMPB.
Each timer interrupt signal can be enabled or disabled individually and has its own interrupt vector address.
4. Arduino Timers Comparison
This is a summarized table for Arduino UNO (Atmega328p) timers, differences between them, capabilities, operating modes, interrupts, and use
cases.
Timer Mode ✓ ✓ ✓
Counter Mode ✓ ✓ ✓
TIMER1_OVF_vect
TIMER0_OVF_vect TIMER2_OVF_vect
TIMER2_COMPA_vect
Interrupts Vectors TIMER0_COMPA_vect TIMER2_COMPA_vect
TIMER1_COMPB_vect
TIMER0_COMPB_vect TIMER2_COMPB_vect
TIMER1_CAPT_vect
We can initialize, configure, and control Arduino Timers & Timer Interrupts using the associated registers as stated in the datasheet. The Timer-
associated registers are as follows:
The timer module in timer mode is configured to have the internal system clock as the clock source with multiple prescaler options. It’s generally
used to generate fixed time interval interrupts to insert time delays between events or to execute periodic events at fixed time intervals.
n time mode, the timer module will keep counting (0 to 255 or 65535 depending on resolution). At overflow, a timer overflow interrupt is fired
and the timer rolls over back to zero and starts counting again.
The desired output time interval (TOUT) is equal to the number of timer ticks multiplied by the single tick time. The timer’s tick time is determined
by the input clock frequency and the prescaler ratio that you’ve selected. Therefore, the general timer equation can be expressed like this:
𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃𝑃 × 𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇
𝑇𝑇𝑂𝑂𝑂𝑂𝑂𝑂 =
𝐶𝐶𝐶𝐶𝐶𝐶𝐹𝐹𝐹𝐹𝐹𝐹𝐹𝐹
And that’s the equation we’ll be using to design timer-based applications (e.g. time interval delays, periodic tasks execution, and much more). You
should note that the maximum TOUT is defined by the prescaler ratio configuration. Changing the prescaler will allow us to raise the maximum
allowable TOUT time interval generation with the timer module before it overflows.
For example, Timer1 in Arduino UNO is clocked at 16MHz. With a prescaler of 1:1, the Maximum TOUT can be achieved by setting the TicksCount
to its maximum value of 65536. This will give us TOUT(Max) = (1×65536)/16M = 4.1ms.
If you need to generate a larger TOUT time interval with that timer module @ 16MHz clock, you need to choose another option for the prescaler.
Let’s say you’d like to generate a 500ms timer interrupt as a time-base for your system. This means the TOUT(MAX) needs to be >500ms.
Therefore, setting the prescaler ratio to 1:256 will be the best option. Because it’ll allow a maximum TOUT(MAX) of = (256×65536)/16M = 1.049s.
Which is more than the 500ms requirement so it becomes achievable by selecting this larger prescaler ratio. Let’s now discuss how to use the
general timer equation and do the required calculations to be able to configure the timer module properly.
Arduino Timer Calculations
The best way to demonstrate timer module calculations is to consider a practical example use case and walk through the calculation process step
by step. And that’s what we’re going to do in this section.
et’s say you’d like to generate a periodic timer interrupt every 100ms and use it as a time base for your system. We’ll be using the Timer1 module
which is clocked at 16MHz (in Arduino UNO boards).
Step 1- Select a suitable prescaler divider. The required TOUT is 100ms. The TOUT(MAX) should be > 100ms. Therefore, selecting a prescaler of
1:64 will be sufficient. Because at 1:64 prescaler, the TOUT(MAX) = (64×65536)/16M = 262ms. Which is definitely above the required 100ms
time interval.
Step 2- Using the general timer equation, plug in the (TOUT value, Prescaler divider, and CLK frequency). Then solve the equation for
the TicksCount value.
64 × 𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇𝑇
100𝑚𝑚𝑚𝑚 =
16𝑀𝑀
Step 3- TicksCount = 25,000 ticks. And that’s the output of the calculation that we’ll use thereafter to program the timer module to generate the
desired 100ms timer interrupt event.
Arduino Timer Interrupt Code
After calculating the required timer TicksCount to achieve the desired TOUT time interval for timer interrupt events, we can go about programming
the Arduino timer module in two different ways.
1- Timer Preloading
The first method is to preload the timer register (TCNTx) with a value in such a way it reached overflow (65535) after only TicksCount ticks. For
the previous 100ms example, the TicksCount turned out to be 25000 ticks. Therefore, the timer preload value = 65535-25000 = 40535.
By writing 40535 to the TCNTx register, we guarantee that it’s going to tick 25000 ticks to reach the overflow state. In the timer overflow interrupt
ISR handler, we’ll also need to preload the TCNTx register with the same value and keep repeating over and over again.
1 /*
2 * LAB Name: Arduino Timer Preloading
3 * Author: Khaled Magdy
4 * For More Info Visit: www.DeepBlueMbedded.com
5 */
6
7 ISR(TIMER1_OVF_vect)
8 {
9 TCNT1 = 40535; // Timer Preloading
10 // Handle The 100ms Timer Interrupt
11 //...
12 }
13
14 void setup()
15 {
16 TCCR1A = 0; // Init Timer1
17 TCCR1B = 0; // Init Timer1
18 TCCR1B |= B00000011; // Prescalar = 64
19 TCNT1 = 40535; // Timer Preloading
20 TIMSK1 |= B00000001; // Enable Timer Overflow Interrupt
21 }
22 void loop()
23 {
24 // Do Nothing
25 }
26
An easier way to achieve the same goal without disrupting the timer’s TCNTx register’s value would be to use the compare match interrupt events.
This is probably the best way to implement timer-based interrupt events. Because it gives you two (COMPA and COMPB) registers to generate
two independent timer interrupt events using the same timer module.
Considering the previous 100ms time interval interrupt example, we need the timer to tick 25000 ticks to get the 100ms periodic interrupt. So,
we’ll use COMPA compare register, enable its interrupt, and set its value to 25000. When a compare match occurs (when TCNT1 = OCR1A), an
interrupt is fired. And that’s the 100ms periodic interrupt we want.
To keep it running at the same 100ms rate, we need to update the COMPA value because the timer’s count has now reached 25000. Therefore, we
need to add 25000 ticks to the COMPA value. Don’t worry about overflow, at 65535, the register will roll over back to zero exactly like the timer’s
TCNTx register does. So it’s going to work flawlessly all the time.
/*
* LAB Name: Arduino Timer Compare Match Interrupt
* Author: Khaled Magdy
* For More Info Visit: www.DeepBlueMbedded.com
*/
ISR(TIMER1_COMPA_vect)
{
OCR1A += 25000; // Advance The COMPA Register
// Handle The 100ms Timer Interrupt
//...
}
void setup()
{
TCCR1A = 0; // Init Timer1
TCCR1B = 0; // Init Timer1
TCCR1B |= B00000011; // Prescalar = 64
OCR1A = 25000; // Timer CompareA Register
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
}
void loop()
{
// Do Nothing
}
Timer Prescaler & TOUT Relationship
Prescaler Min TOUT Max TOUT Min TOUT Max TOUT Min TOUT Max TOUT
32 – – – – 2μs 512μs