AVR Timers – TIMER0
Hello friends! Welcome back to the second part of the AVR Timers Series. In the previous post, we have discussed the basic concepts of AVR Timers. Let me summarize it:
- We have seen how timers are made up of registers, whose value automatically increases/decreases. Thus, the terms timer/counter are used interchangeably.
- In AVR, there are three types of timers – TIMER0, TIMER1 and TIMER2. Of these, TIMER1 is a 16-bit timer whereas others are 8-bit timers.
- We have seen how prescalers are used to trade duration with resolution.
- We have also discussed how to choose an appropriate value of a prescaler.
- And then, to finish off, we learnt about interrupts.
So, I will move towards its implementation directly. I have assumed that you have understood the concepts discussed above.
In this tutorial, we will learn to use TIMER0. Since timer is a peripheral, it can be activated by setting some bits in some registers. Instead of discussing all the registers at once, we will be discussing them as and when necessary. For those who are new to the term ‘register’, they can read about it from this page. To have an idea about AVR Peripherals, view this page (you need to scroll down a bit).
Problem Statement
Let’s define a problem statement for us. The simplest one being the LED flasher. Let’s say, we need to flash an LED every 6 ms and we are have a CPU clock frequency of 32 kHz.
Well, I know that an LED flashing at every 6 ms will be always visible as on by our eye, but I could not find any simpler example which does not include prescalers. Take this as a demonstration.
Methodology
Now, as per the following formula, with a clock frequency of 32 kHz and 8-bit counter, the maximum delay possible is of 8 ms. This is quite low (for us, but not for the MCU). Hence for a delay of 6 ms, we need a timer count of 191. This can easily be achieved with an 8-bit counter (MAX = 255).
Thus, what we need to do is quite simple. We need to keep a track of the counter value. As soon as it reaches 191, we toggle the LED value and reset the counter. For this, we need the help of the following registers.
TCNT0 Register
The Timer/Counter Register – TCNT0 is as follows:
This is where the uint 8-bit counter of the timer resides. The value of the counter is stored here and increases/decreases automatically. Data can be both read/written from this register.
Now we know where the counter value lies. But this register won’t be activated unless we activate the timer! Thus we need to set the timer up. How? Read on…
TCCR0 Register
The Timer/Counter Control Register – TCCR0 is as follows:
Right now, we will concentrate on the highlighted bits. The other bits will be discussed as and when necessary. By selecting these three Clock Select Bits, CS02:00, we set the timer up by choosing proper prescaler. The possible combinations are shown below.
For this problem statement, we choose No Prescaling. Ignore the bits highlighted in grey. We will be using it later in this tutorial. Thus, we initialize the counter as:
TCCR0 |= (1 << CS00);
Please note that if you do not initialize this register, all the bits will remain as zero and the timer/counter will remain stopped.
Thus now we are ready to write a code for this. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this.
Code
#include <avr/io.h> void timer0_init() { // set up timer with no prescaling TCCR0 |= (1 << CS00); // initialize counter TCNT0 = 0; } int main(void) { // connect led to pin PC0 DDRC |= (1 << 0); // initialize timer timer0_init(); // loop forever while(1) { // check if the timer count reaches 191 if (TCNT0 >= 191) { PORTC ^= (1 << 0); // toggles the led TCNT0 = 0; // reset counter } } }
I guess the code is pretty simple and straightforward. It doesn’t need any explanation. Or maybe one thing needs explanation. In the if statement, I have used
if (TCNT0 >= 191)
instead of
if (TCNT0 == 191)
This is because sometimes due to missed compares or unexpected increment, this condition may never be true. Thus to remain on the safer side, we use ‘>=’ instead of ‘==’.
Problem Statement Redefined
Now let’s change the above problem statement to the following. We need to flash an LED every 8 ms and we have an XTAL of 16 MHz. Well, 8 ms is still low, but it’s good enough for the following illustration.
Methodology – Using Prescalers
Now since the CPU clock frequency is 16 MHz, the maximum time delay that it can measure is 16 μs! But 8 ms (which is quite a small duration for us) is way much larger. So what do we do? Yes, you guessed right (I hope so ;))! We use a prescaler in order to trade duration with resolution. Now the following table summarizes the results of using different prescalers 8, 64, 256 and 1024. See previous tutorial for details.
From the values of the counter, we can easily rule out the top three prescalers as they are above the maximum limit of an 8-bit counter (which is 255). Thus we use a prescaler of 1024. Now refer to the descriptions of clock select bits as shown in the TCCR0 register. Have a look at the selection highlighted in grey. This implements a prescaler of 1024. The rest remains the same. Moving to the coding part, we simply change the initialize function and the compare value. The rest remains the same.
Code
#include <avr/io.h> void timer0_init() { // set up timer with prescaler = 1024 TCCR0 |= (1 << CS02)|(1 << CS00); // initialize counter TCNT0 = 0; } int main(void) { // connect led to pin PC0 DDRC |= (1 << 0); // initialize timer timer0_init(); // loop forever while(1) { // check if the timer count reaches 124 if (TCNT0 >= 124) { PORTC ^= (1 << 0); // toggles the led TCNT0 = 0; // reset counter } } }
Problem Statement Redefined Again!
Now let’s change the problem statement to something you can actually see! Let’s flash an LED every 50 ms (you can surely see the LED flashing this time ;)). We have an XTAL of 16 MHz.
Methodology – Using Interrupts
So now, we have to flash the LED every 50 ms. With CPU frequency 16 MHz, even a maximum delay of 16.384 ms can be achieved using a 1024 prescaler. So what do we do now? Well, we use interrupts.
The concept here is that the hardware generates an interrupt every time the timer overflows. Since the required delay is greater than the maximum possible delay, obviously the timer will overflow. And whenever the timer overflows, an interrupt is fired. Now the question is how many times should the interrupt be fired?
For this, let’s do some calculation. Let’s choose a prescaler, say 256. Thus, as per the calculations, it should take 4.096 ms for the timer to overflow. Now as soon as the timer overflows, an interrupt is fired and an Interrupt Service Routine (ISR) is executed. Now,
50 ms ÷ 4.096 ms = 12.207
Thus, in simple terms, by the time the timer has overflown 12 times, 49.152 ms would have passed. After that, when the timer undergoes 13th iteration, it would achieve a delay of 50 ms. Thus, in the 13th iteration, we need a delay of 50 – 49.152 = 0.848 ms. At a frequency of 62.5 kHz (prescaler = 256), each tick takes 0.016 ms. Thus to achieve a delay of 0.848 ms, it would require 53 ticks. Thus, in the 13th iteration, we only allow the timer to count up to 53, and then reset it. All this can be achieved in the ISR as follows:
// global variable to count the number of overflows volatile uint8_t tot_overflow; // TIMER0 overflow interrupt service routine // called whenever TCNT0 overflows ISR(TIMER0_OVF_vect) { // keep a track of number of overflows tot_overflow++; } int main(void) { // connect led to pin PC0 DDRC |= (1 << 0); // initialize timer timer0_init(); // loop forever while(1) { // check if no. of overflows = 12 if (tot_overflow >= 12) // NOTE: '>=' is used { // check if the timer count reaches 53 if (TCNT0 >= 53) { PORTC ^= (1 << 0); // toggles the led TCNT0 = 0; // reset counter tot_overflow = 0; // reset overflow counter } } } }
Please note that the code is not yet ready. Not until you learn how to enable the interrupt feature. For this, you should be aware of the following registers.
TIMSK Register
The Timer/Counter Interrupt Mask – TIMSK Register is as follows. It is a common register for all the three timers. For TIMER0, bits 1 and 0 are allotted. Right now, we are interested in the 0th bit TOIE0. Setting this bit to ‘1’ enables the TIMER0 overflow interrupt.
TIFR Register
The Timer/Counter Interrupt Flag Register– TIFR is as follows. Even though we are not using it in our code, you should be aware of it.
This is also a register shared by all the timers. Even here, bits 1 and 0 are allotted for TIMER0. At present we are interested in the 0th bit TOV0 bit. This bit is set (one) whenever TIMER0 overflows. This bit is reset (zero) whenever the Interrupt Service Routine (ISR) is executed. If there is no ISR to execute, we can clear it manually by writing one to it.
In this example, since we are using ISR, we need not care about this bit (thus this register as a whole).
Enabling Global Interrupts
In the AVRs, there’s only one single bit which handles all the interrupts. Thus, to enable it, we need to enable the global interrupts. This is done by calling a function named sei(). Don’t worry much about it, we simply need to call it once, that’s all.
Final Code
#include <avr/io.h> #include <avr/interrupt.h> // global variable to count the number of overflows volatile uint8_t tot_overflow; // initialize timer, interrupt and variable void timer0_init() { // set up timer with prescaler = 256 TCCR0 |= (1 << CS02); // initialize counter TCNT0 = 0; // enable overflow interrupt TIMSK |= (1 << TOIE0); // enable global interrupts sei(); // initialize overflow counter variable tot_overflow = 0; } // TIMER0 overflow interrupt service routine // called whenever TCNT0 overflows ISR(TIMER0_OVF_vect) { // keep a track of number of overflows tot_overflow++; } int main(void) { // connect led to pin PC0 DDRC |= (1 << 0); // initialize timer timer0_init(); // loop forever while(1) { // check if no. of overflows = 12 if (tot_overflow >= 12) // NOTE: '>=' is used { // check if the timer count reaches 53 if (TCNT0 >= 53) { PORTC ^= (1 << 0); // toggles the led TCNT0 = 0; // reset counter tot_overflow = 0; // reset overflow counter } } } }
So friends, we are done with the basics of TIMER0. What remains to be discussed in it are CTC Mode and PWM Mode. We will be discussing them in upcoming posts. In the next post, we will discuss how to apply the same concepts to use TIMER1, and then to TIMER2.
Till then, enjoy flashing LEDs at different intervals! ;)
And please comment below to encourage me to keep on updating interesting stuffs! :) Also you can grab the RSS Feeds or subscribe to my blog to stay updated!
Thank You!
Thanks for such a nice blog….
Thanks! ;)
Keep Reading, Keep Sharing!
Dear Mayank!!
This is awesome!! I tried many docs to get clear basic idea on Timers & Interrupts with AVR.
You are the Best. You helped me a lot.
Thank you very much and Keep posting!! :)
very good concept
too bad. You can use other prescaler value to obtain a integer division, for example prescaler 64 and set the counter register to generate an ISR of 1ms and then using a variable that it increments by one each ISR you can count when this variable reaches 50.
Hi Max,
the best tutorial ever !
Finally I found a very, very clear tutorial on the timers/pwm stuff !
Thank you so mauch !!!
Federico
Thanks!
Keep reading, keep sharing!!
Hallo sir, Im a new Biginer of AVR Microcontroller, and i have a question
what the Difference between delay created by configuring timer 0,1,2 and delay that created by Delay.h Liblary?
as i know that we could use Delay.h Liblary, using _delay_ms(1000) for 1 second Delay, so why must we need to configure all this timer all along?
Thanks sir :D
delay stops your avr, but sometimes you want to do something different between blinking led
For your general knowledge in the embedded systems field, there are two ways in dealing with interrupting events while dealing with other ones: Using polling and using interrupts. In your application you are using the polling method which is a periodic checking every time a delay occurs. On the other hand interrupts happen when a flag is raised inside the peripheral itself, ether you are using ADC, SPI, I2C or any other peripheral in the microcontroller –> meaning that do whatever you want until an interrupt flag is fired, then the program counter ( PC ) goes inside an interrupt service routine ( ISR ) in which it will execute the piece of code inside the ISR and when finishing executing, the PC will return to the last statement it was executing. Hope my answer helps you :)
It’s Awesome… Great, keep going…
Thanks!
Keep reading, keep sharing!!
Is here an error?
TCNT0 >= 191
You use 8-bit timer, so it should’n be 255 – 191 = 64 ??
Because it starts from 64, ends on 255 then overflow and again from 64 ? What gives us 191 Timer Count ….
great tutorial! thanks!
Thanks!
Keep Reading, Keep Sharing. :D
Max, these tutorials are very helpful!
One question: is “TIMER0_OVF_vect” generated based on our enabling of the TOIE0 bit?
Thanks, and keep these tutorials coming!
Sir, I want to make an LED on for 15 minutes & then it will turn off forever until user wants to turn it on again. how & which code i have write for Atmega8. please help me.
Correct me if I’m wrong, but in the last example, shouldn’t the 13th iteration only count to 52? Wouldn’t that be consistent with your formula in the beginning of the article (to subtract 1 to account for the zero count)
thank you sir!
keep posting :)
Using atmega328P and Codevision software but it says error as undefined symbol ‘TCNT1’ what could be the probable error ?
hi max, can you explain more about prescaling in TCCR0? I’m a litlle bit confused about which prescaler should I use? thank u.
The great explanation ever .)
very nicely explain
sir this code is not working. I want to make a code in which led on for 3 seconds and off for 5 second. Kindly help me. (not using interrupts)
You gotta try first before I can even think of helping you.
So this toggles the led, but it does it so it’s on for 50ms, then off for 50ms, and so on and so forth. It’s not exactly “flashing” the LED for a shorter, more instantaneous period of time and then turning off for 50ms before flashing again, and so on and so forth. Correct?
50 ms is too small for you to see it blink. You should see it dimmed. But in reality, it is “flashing” – on for 50ms, off for 50ms.
I have a confusion in the formula: Timer Count=((required delay)/(time period)) – 1.
I think that subtracting 1 is not needed.
As the timer starts from 0 goes till 255, there are only 255 ticks and not 256.
Consider we calculate the time taken for overflow in timer0 (with prescalar 1024)
Since there are 255 ticks , time for overflow= 255*1024/16,000,000=16.32ms.
but according to given formula , time overflow = 256*1024/16,000,000 = 16.384.
From 0 to 1, there is 1 tick . From 0 – 1- 2 , there are 2 ticks. SImilarly , from 0-1-2-…..-254-255, there are 255 tick. Implies time overflow = 255 *1024/16MHz , instead of 256 in numerator
Hence 1 must not be subtracted from RHS. Plz respond to my proposal…..
There are 256 ticks (NOT 255). 0, 1, 2, 3, …, 254, 255, 0 (back to zero – that’s 256th tick).
I can’t understand it too. Let me ask you this way, if our required daley is equal to the clock time period, The timer count will be 0 ?! And what does it have to dk with the total number of ticks?!
from 255 —>0 is 1 tick. i.e 256
great explanation….
all your tutorials are very simple to understand
dear sir,
i made a clock using atmega 8
i have 2 same circuit arrangements
when i use the same code for both of them their is a slight variation in the output
can anybody please provide an explaination
thank you in advance
How much is your “slight” variation? It is expected to miss by a few timer counts since the software isn’t as accurate as the hardware. Even though your hardware may tick exactly at 1 second interval, when you write software on top of it, by the time it processes everything for you, it is already a few more milliseconds over.
sir the delay between the 2 circuits is 4 sec per hour.
i understand that the actual clock and the atmega clock will have difference.
what i dont understand is how 2 same circuits(made together with same pcb) is performing differently on same code.
how can i overcome this
thanks for the reply sir
This is because no two chips or PCBs are the same. It isn’t guaranteed that the two ATMegas you’re using are made of the same silicon (i.e. they don’t come from the same die/wafer). Plus there are many other parasitic effects like capacitances, clock skew, etc that could kick in at the hardware level. If you’d like to guarantee accurate time measurement across all devices, consider using a real time clock.
As already said by others.
I really appreciate the effort you put into building up this massive compendium.
I am here for the first time and this saves me so much time to get my informations here when considering to read all the AVR Manuals instead.
Thank you so much.
Greetings from Germany,
Tom