Let’s talk about timer and timer interrupts.
A timer, or better to say, a counter is a piece of hardware builtin in our Arduino Uno.
Our Arduino Uno has three builtin timer, called timer0, timer1 and timer2.
Timer0 and timer2 has an 8 bit resolution, timer1 has an 16 bit resolution. The differenc between 8bit and 16bit is the timer resolution. With 8bit we have 256 values, with 16bit we have 65536 values.
Timer interrupts allow you to perform a task at very specifically timed intervals regardless of what else is going on.
The Arduino world used this timer for delay() function. Don’t forget, if you change this timer intervall, you change the delay() function!
With this timer it’s possible to create a clock intervall with 1 second or higher. Later more…
It’ also an 8bit timer like timer0. This timer is free.
Now it get a little more details. To config the timer, we need timer register. Here are the important register:
Output Compare Register.
Timer/Counter Interrupt Mask Register.
Timer/Counter Control Register.
All timers use this register. You distinguish the register with an additional digit. Timer0 has a TCNT0 register, timer1 used TCNT1, and timer2 used TCNT2.
Let’s start with the first register.
In the TCNT register is the actual counter value stored. You can read this value or you can store your own initial value there.
The OCR register. With this value we decide, if a timer loop finished. We must calculate this value. Remember, our timer is 8bit or 16bit. With 8bit, we have only 256 possibilities. Therefore we have the possibility to use a prescaler to be more flexible.
Prescaler: This prescale value can be set to 1, 8, 64, 256 or 1024.
Ok, now we calculate an example with timer0 .
We need a timer interrupt with 200Hz. The Arduino Uno frequency is fix, 16MHz.
OCR0 = 16.000.000 / (prescale value * frequency we need)
We start with a prescale value of 64:
OCR0 = 16.000.000 / (64 * 200)
OCR0 = 1250
Attention! The value is too big, we have only 8bit, the value must be less then 256! We need another prescale value.
We calculate with a prescale value of 256:
OCR0 = 16.000.000 / (256 * 200)
OCR0 = 312,5
Still to big!
We calculate with a prescale value of 1024:
OCR0 = 16.000.000 / (1024 * 200)
OCR0 = 78,125
OCR0 = 78
TCCR. Our control register. It’s 16bit, therefore we have two registers, TCCRxA and TCCRxB with 8bit.
We need 3 bits in the TCCRxB register, called CSx0, CSx1 and CSx2. CS is the short cut of Clock Select. With this three bits we define the prescale value. In this order: CSx2 – CSx1 – CSx0:
0 0 1 prescale value: 1
0 1 0 prescale value: 8
0 1 1 prescale value: 64
1 0 0 prescale value: 256
1 0 1 prescale value: 1024
1 1 0 not for prescaling
1 1 1 not for prescaling
How can I set CS12, CS11 and CS10 in my code?:
TCCR0B = 0; // second TCCR bit initial to 0
TCCR0B |= (1 <<CS02) // set only bit CS02 -> prescale value: 256
TCCR0B |= (1 <<CS01) // set only bit CS01 -> prescale value: 8
TCCR0B |= (1 <<CS02) | (1 << CS00) // set bit CS02 and CS0 -> prescale value: 1024
The next necessary details:
We can operate our Arduino in different modi. There are:
a) normal mode
The simplest mode. In this mode, the counter will always count up. If the maximum value reached, it start with 0 again.
b) Clear Timer on Compare Match (CTC) Mode
In this mode we are able to manipulate the counter resolution. We can use an prescale value. Therefore we need this modi!
c) Fast PWM Mode
In fast PWM mode, the counter is incremented until the counter value matches the TOP value. The counter is then cleared at the following timer clock cycle.
To decide in which mode we operate our Arduino, we need an additional register, WGMx1. WGM is the shortcut for Waveform Generation mode.
For CTC mode we need the following code statement (in example: timer0)
TCCR0A |= (1 << WGM01)
How to enable the timer interrupt?
TIMSK. This register is necessary to enable / disable the interrupt timer. After finish the configuration we enable the timer by using this register.
We need one bit from the TIMSKx register, called OCIExA.
Set this bit to one, the interrupt is enabled (in example: timer0).
TIMSK0 |= (1 << OCIE0A)