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:

TCNT0 Register

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:

TCCR0 Register

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.

Clock Select Bit Description

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.

Prescaler Selection

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.

TIMSK Register

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.

TIFR Register

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!

About these ads

130 responses to “AVR Timers – TIMER0”

1. I had a doubt regarding timing of the timers
Suppose TCNT0=0 and the timer is activated…..then during the first clock cycle what will the value of the TCNT0?…..0 or 1….I’m assuming no clock cycles have passed and the clock is internal clock.
From the datasheet the timing diagram indicates that TCNT0 increments on the rising edge of the clock pulse.

• Hi Alex,
TCNTx will always remain 0 in the first cycle. Check out the timing diagrams in pages 77 through 79 of ATmega32 datasheet. In case of no prescaling, TCNTx increments at the rising edge of clock. In case of a prescaler, TCNTx increments at the falling edge of the divided clock AND at the rising edge of the original clock. Whatever the case it may be, whenever the timer is activated, TCNTx=0, and it will increment only in the next corresponding clock edge. Did I answer what you asked for?

2. Thanks guys enough nice work. list ur coming up posts this will help and encourage ur regular readers….

• Hello,
Thanks for the advice! We’ll figure out a way to do that. And FYI, here is a list of some of our up coming posts as of today-
1. MSP at a glance
2. Unboxing the MSP430 Launchpad
3. The SPI of the AVR
4. The I2C of the AVR
5. Beaglebone Black Quick Start Guide

Cheers!

3. Hey, Your posts have been really helpfull :). Thanks
But I would like to know how to use the external clock sources of timer 1 and timer0.

• Thanks Bilal.
To use the external clock sources as timers, you simply need to hook up a crystal oscillator between the XTAL pins of your microcontroller in parallel with two parallel 22uF capacitors. And then you also need to set proper fuses. That’s it. Once it is done, your microcontroller will start following the external crystal as F_CPU.

4. In the first code segment, don’t you think TCNT should be incremented in every while loop (inside the if statement) ?

5. Sorry I made a mistake. Never mind.

• Hi Abhishek,
I don’t understand what you mean by “1 second delay 4 LED blink”. Do you want to blink four LEDs every second or do you want to blink an LED every second? If it’s the first case, please improve your english grammar, if it’s the latter, then please don’t use abbreviations. We do not encourage use of SMS language.

From what I see, there might be issues in setting your clock frequency. Try using in this way–

```#ifndef F_CPU #define F_CPU 1000000UL #endif```

Secondly, check whether your clock frequency is actually 1 MHz or not. These are the two most accountable reasons for the error. Let me know how it goes.

Thanks,
Max

• Indeed it was the first case. Sorry for the inconvenience. The first solution doesn’t seem to make any difference. As for the second, I’m just beginning with the ATMega8, so I’m not really sure of how to go about checking the clock frequency.

• Dear Abhishek,
A microcontroller can be clocked using either an internal clock or an external clock. An external clock is usually a crystal oscillator attached to the XTAL pins of the microcontroller. They look somewhat like this. See if you can find it attached to your microcontroller board. Make sure to check beneath the microcontroller as well, because some manufacturers put in the crystal beneath the microcontroller to save space on board. If you find it, then look closely, it should have the exact frequency written on it. Note that this external crystal is followed by the microcontroller only if you ask it to do so (by setting proper fuses).

If you don’t find it, then the microcontroller is usually running at it’s internal clock frequency. Now, a microcontroller can have multiple internal clock frequencies, but usually, if you haven’t played around with the fuses, then it should be 1 MHz for ATmega8.

• I’m pretty sure that I haven’t played around with the fuses. I do have an external crystal at 12Mhz. If it helps, it’s a Robosapiens iBot Mini V 2.0 board. I’m guessing that, since the delay is smaller than expected, the clock frequency is being set higher. But I really can’t figure out why.

• Try changing the FCPU value in your code to 12000000UL. It might help.

• Changed it to 12000000UL and modified the program accordingly. Works like a charm. Thanks a lot. But I really need to know why it wouldn’t work at 1000000UL if I wanna sleep at night. Sorry for bugging you this much.

• Dear Abhishek, The problem with using F_CPU = 1000000UL is that it is equivalent to 1MHZ. Basically you are telling your Microcontroller that you are using a 1MHZ oscillator wheras you are actually using a 12MHZ osicllator.

So what happens is that your Microcontroller would think that 1 second is over as soon as 1000000 = 1 Mega pulses are generated, and it blinks. But in reality only around 83.33 ms has passed.

So you need to tell your Microcontroller the real value of the Oscillator you are using.

Regards
Kabir

• Thanks for the explanation Kabir! You’re fantastic!

• Oh yes Sarathi, it is on my list. You should see some of them soon.

• Rahul, please read this and my other timer posts, and you’ll find the answer yourself.

• Rahul, please read this and my other timer posts, and you’ll find the answer yourself.

6. i am using Atmega16a which is 8bit and 16MHz).. if we use _delay_ms(2000)…it is not generating 2seconds exactly..can you please explain..why?

• Hey Arnav,
Did you define the correct F_CPU?

• Arnav, try to register this at the back of your head. You always always always always need to define the value of F_CPU. It is for the compiler to optimize your code properly and generate correct hex code. Even if you haven’t used timers, the function `_delay_ms()` calls timer in the back end.

7. Hi Mayanak, Ur codes work very well. However, pl. give hint of how to add an INPUT pin (say portB0) so that when it is HIGH, only then the four LEDs go on / off in sequence, but if this INPUT pin B0 is LOW, Then the program should STOP & the LED that was last ON should also go OFF. I tried to add input pin but did not succeed, so how & where to add this additional condition in the ISR loop or in a while loop?? Pl. help. Thanx., Below is my working code:-
http://pastebin.com/2804tV0b

• Hey Navin,
I can’t find you reading data anywhere in the code. You can refer to this post to know about AVR I/O operations, and this post to refer to how you can interface a switch for input.

• Hi Mayank, Yes U r right, there’s no “reading data” in my code, bcoz when I tried to add an INPUT to it like – (portB pin0) & tried to use a <while(PINB==0b00000001)> loop with-in the ISR loop, it did not work…(see that part of code below):-
http://pastebin.com/aEL5frLC
(I hv read Ur tutorial regarding I/O input / output use & examples, ..they r great.., but why the loop did not work within the ISR loop, where else in this Timer0 code, it is possible for such INPUT conditions to work..??..Thanx… pl, give a hint..)

• Navin,
Ideally we do not prefer to do heavy tasks in the ISR. Try to modify your logic in some way so that you read the data from PINB in to some variable in `main()` and then access it in the ISR. Make sure you don’t forget to initialize that variable as `volatile`. Let me know if that works.

8. Hi Mayank,
Ur valuable advice & hint gave me NEW insights to understand how ‘volatile’ variables r flexible & much better to use than just simple variables & how they can be accessed. However, in my (the INPUT could not be read inside the ISR loop), even after dozens of attempts, so I tried to put the in the <while(true)> loop, -& then it WORKED..!!
But only, a minor problem remains, -that the two LEDs now don’t go ON for 3 sec. like before, (just as I wanted),but they just flicker ON for a fraction of a second. The <_delay_ms(100)> could not stop their flickering, but it is NOT a problem for my hardware, as my two relays won’t go ON with such a short ON pulse. But pl. give some hints as to how to stop this short flickering completely. Below is the only code that worked (given as suedo code below):-
http://pastebin.com/th8LemEW

So this last ‘if’ statements inside of the above <while(true) loop> WORKED well, & it stopped the two LEDs from going ON, (which is what I wanted), but this ‘if’ condition of INPUT, did not work inside the , even though I defined a “volatile” variable & tried to access in the but it did not work there*/..Thanx, Ur TIPS in this regard will be of great help.

9. Hi Mayank, (contd…),..all ‘if’ conditions related to OUTPUT (PORTC) worked inside the ISR loop of both timer0 & timer1 (AtMega8a chip), but no ‘if’ statement related to INPUT, ever worked inside this ISR loop…why..??? But still, I got my INPUT ‘if’ condition code working inside the <while(true)> loop…, yet, what could be the reason..? (by the way the 1st. two OUTPUT LEDs r operating my two relays, which put ON my ‘washing machine motor’ ON-(Clock-wise for 3 sec., then stop for 1 sec., & then again anti-clock-wise for another 3 sec.)… & so on…, So if INPUT (pinB0 is HIGH) that means ‘water level’ in the washing machine is low or NIL, so the motor must STOP, -which I achieved in the <while(true)> loop but could not do it in the ISR loop? Thanx, Ur hints awaited anxiously…regards.

• Navin,
I hope you are familiar that when the `ISR` is executing, your `main()` is not! This means that every time an interrupt happens, the AVR CPU has to perform a context switch by saving all its register in the stack, executing the `ISR`, and then loading the registers back from the stack. This takes a lot of time. So one consideration is to have as less number of interrupts as possible. Another consideration is to reduce the execution time of `ISR` as much as possible. We want our `main()` to execute continuously. If the `main()` is interrupted for a long time, your other functions being implemented might be thrown out of sync, or be delayed, and result in something you don’t expect at all. This is why we usually do not perform read and write operation in `ISR` because they take a while to get executed. You read/write your data in `main()`. And all you usually do in the `ISR` is to set/clear some (`volatile`) variables, or do some other light tasks which are not processor intensive. Reading/writing in `ISR` is not a good coding practice, whether it works or not is a different issue.

Now coming to your question on why it doesn’t work, well I can’t say. I don’t know what’s going on, and I’ll have to give it a try myself before I say anything to you.
And regarding the flickering, why do you even have the delay loop if you want it to be off?

• Hi Mayank,
Thanx for ur reply, U r right in saying that the main() can be thrown out of sync or delayed -and this I think, is EXACTLY what has started happen, after some successful trial runs of my code, & now the (Led OFF code) which worked previously, with some “flickering” of the leds, has now stopped to work COMPLETELY..! So I’m back to square one!
But BOTH my ISR loops (of timer0 & timer1) are working TOGETHER beautifully. [8bit Timer0 prescaler set at /1024 & 16 bit Timer1 prescaler is set at /8] so that timer0 is putting (led1 ON for 3 sec., then OFF or 1 sec. then led2 ON for 3 sec.& so on..) & at the SAME TIME (timer1 is putting led3 ON for 64 sec, OFF for 1 sec. then led4 ON for 64 sec & so on..). Also each of the four ‘if’ conditions put WITHIN BOTH the (timer0 ISR and timer1 ISR) loops r working perfectly to control output of the four pins of PORTC, ONLY problem is that, ISR loop is not accepting any code to read INPUT. I just wanted ONLY the timer0 ISR loop to read just one pin0 of portB, which is not working there, & now, it is not even working in the while(true) loop. The complete TESTED & working code I am send U in next post, so that U can easily see what is going on there, as this whole program works very well, except that I can’t get just one INPUT pin to be read at any place in this code: Pl. go thru’ the whole code, & if possible suggest some hint as to how to get one input pin to be read somewhere out there in this code. There is no one else here, who can guide me, So Thanx. a lot for ur help…
The code is given next:
http://pastebin.com/jSGRfBgb

• Navin, I have a question. If you want to read PINB0 in Timer0-ISR, why are you reading it in the main and assigning PORTC values? Note that Timer0-ISR executes only when Timer0 overflows, whereas while(true) executes always. If you want to read data only when timer overflows, why the heck do you want to read it in while(1)?

Try something like this. I don’t know if it’ll work or not, but give it a try. http://pastebin.com/V8HpP7vd

PS. Please don’t paste such long codes here. If you want to share your code, go to pastebin.com, paste your code with proper syntax highlighting, and share the link here. It becomes messy with long codes posted here. Thanks.

10. HI Mayank, Thanks for Ur valuable guidance of giving me “codes as examples” for my problem. I realized, I must be doing something basically wrong. Now with ur advice, it is becoming more clear of what error I must be making, so I’ll try to write my code in line with ur given examples, & test them accordingly.
& v. sorry for sending long codes in the comments box, (but now I know there is another place to put in such long matters),…Thanx a lot again,..& Ur code examples r just the kind of help and hints that I really needed…

• Happy to help! All the best!

11. I give a thumbs-up to the information on this page! Need some info on how to use two timers at a time. Counting on your help.

• Hello Cyril,
You can use two different timers simultaneously. Go ahead, try it out. Read my other timer posts, and implement them together. They should work.

• Hi Mayank, U r right in telling Cyril that using two different timers should work, in fact taking cue from ur tutorials, I was able to get all the THREE (timer0, timer1, & timer2) to work together very well, & independently (on AtMega8a chip), with three sets of LEDs going ON & OFF at three different timings.
…Only that, I still could not get an INPUT to be read successfully at the same time. Will I hv to use a 2nd. chip to do the reading? Ur suggestions did work, but after some hours of run, the INPUT reading goes erratic or stops completely, even though the three timers go on working properly…Thanx, Regards.

12. Thanks so much for this post!
I have been searching for weeks about the avr timer, and with your help i can finally understand!

• Amazing! Keep it up! Good luck, hope you learn more!