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!






Hey Mayank,
Another great tutorial. I am trying to set up a program in which I can toggle a pin for different time periods within the same program (ie High for 5 seconds, Low for 5 seconds, High for 1 second, Low for 1 second ….) I tried using Timer 1 and creating delay functions. But when I run the programmed MCU the pin just stays High (I have an LED attached to it). Here is my code:
#include
//USE PC5 TO TURN THE PUMP ON AND OFF
//INITIALIZE TIMER 1/ 1Mhz SYSTEM CLOCK with 256 prescale
void timer1_init()
{
TCCR1B |= (1 << CS12);
TCNT1 = 0;
}
void delay_one(){
TCNT1 = 0;
while (TCNT1 <= 3906);
{
}
}
void delay_five(){
TCNT1 = 0;
while (TCNT1 <= 19,531);
{
}
}
int main(void)
{
DDRC |= (1 << 5);
timer1_init();
while(1)
{
PORTC |= (1 << 5);
delay_five();
PORTC &= ~(1 << 5);
delay_five();
PORTC |= (1 << 5);
delay_one();
PORTC &= ~(1 << 5);
delay_one();
}
return 0;
}
I am wondering if your trained eye can see where my problem is. I have tried changing several different things, all with the same result. Or perhaps you can prescribe a more efficient way to accomplish what I want to do.
Hi Devin,
A few things in the above the code:
while (TCNT1 <= 3906); // either use the semicolon or the brackets, but not both
{
}
while (TCNT1 <= 19,531); // again, the same thing. And make it 19531
{
}
Then check whether it works or not. If it doesn’t work, then please re post here, we will come up with something else.
Arrgh. I figured it was something simple
.
Thanks
Devin
Hi Mayank,
I removed the ; from the statements. It still does not function properly. When I try to run it in AVR Simulator it hangs up/won’t let me place a breakpoint after the first “PORTC |= (1 << 5); " statement in the while(1) function. I was thinking of using an ISR, then writing functions that set different overflow count criteria. Do you think this will work?
Thanks
Devin
Okay. So let’s go step by step.
STEP 1: Create a new project, copy/paste your code there, and then modify it to toggle an LED every 5 seconds (just the way its shown in the above post, but use your own code i.e. timer1). This will ensure that you have initialized your timer1 properly and it is running properly. Always keep in mind that the timer runs in parallel to the CPU’s operation, and hence whatsoever you write in main(), the timer runs in background without any interruption.
Once you do this, we will move to Step-2.
Hi Mayank,
I have rewritten your program with the changes to accomodate TIMER1 (I Think). When I ran it on my uC it does not work. So I ran it in AVR Simulator. I notice something curious. If I manually write tot_overflow to a full count it toggles PC5 as expected. But if I manually write TCNT1 to a full count tot_overflow does not tick up 1 as it should. I do not know what I missed here that is causing this problem. Here is my code:
“#include ”
“#include ”
//global variable to count the number of overflows
volatile uint8_t tot_overflow;
//initialize timer1, interrupt and variable
void timer1_init()
{
//set up timer with precaler = 1
TCCR1B |= (1 << CS10);
//INITIALIZE COUNTER
TCNT1 = 0;
//ENABLE OVERFLOW INTERRUPT
TIMSK1 |= (1 << TOIE1);
//ENABLE GLOBAL INTERRUPTS
sei();
//INITIALIZE OVERFLOW COUNTER VARIABLE
tot_overflow = 0;
}
//TIMER1 OVERFLOW INTERRUPT SERVICE ROUTINE
//CALLED WHENEVER TCNT1 OVERFLOWS
ISR(TIMER1_OVF_vect)
{
//KEEP TRACK OF THE NUMBER OF OVERFLOWS
tot_overflow++;
}
int main(void)
{
//CONNECT PC5 TO LED
DDRC |= (1 <= 76)
{
PORTC ^= (1 << 5); //TOGGLES THE LED/PUMP
TCNT1 = 0; //RESET COUNTER
tot_overflow = 0; //RESET OVERFLOW COUNTER
}
}
}
Thanks for your help,
Devin
Hi Mayank,
I have an update. I rewrote the program to use TIMER0 (8 BIT) on the ATmega48A with a 5 secind delay and it works just fine (really confused as to why it won’t work on TIMER1). So I will just use TIMER0 with a 256 prescaler since it works. So i guess I am ready for step 2.
Thanks
Devin
Devin,
In this case, step 2 is creating another timer for 1sec delay, and then writing the code. Step 3 would be to activate the timers sequentially one by one in the same program (the code that you wanted to execute), and then writing more complex codes.
But I am really confused as to why the code won’t work for timer1. Right now I am a bit busy with some exams, but after that, I will surely look into your code that you wrote for timer1 and get back to you. You can also refer to my timer1 tutorial, and/or read about it from the datasheet. Datasheet is one of the best places to learn from! All the tutorials I have written, as well as other tutorials elsewhere on the net are all taken from information shared in the datasheet.
Do post your updates here!
Regards,
Mayank
Hi thanks for this explanations about the mikrocontroller. I just copied the code from the examplecollection of electronicsplanet:
http://www.electronicsplanet.ch/mikrocontroller/avrcodesammlung/atmega16timer0fastpwm.htm
and it worked. but thanks to your explanations, i understand, what it is doing
Hey, that’s great!
macro names must be identifiers, this is the error i am getting, when compiling the 1st timer code in this page, also there is an extra ‘}’ at the end of code
Hi Amruth,
I have not used macros anywhere in the code. And yes, my code was a bit staggered in the tutorial. I have made it right now. Try it again now.
i am still getting same error, what is this error about?
i think u have also written the new code in previous error project, type new code in new project , it will give no error, this worked for me
I am enjoying all your posts. Tanks ones more
Pingback: AVR-Timer | Annotary·
hi mayank…i’m trying to write a pgm for video detection using avr atmega16 timers….i’ve jus started with avr studio…..so….
jus comparing two i/p..if its high start the timer annd if the signal goes low stop it…..basic structure of d pgm??
dis is d progrm dat i got around to…it does not give d o/p though
Code can be found here.Hi viii
Where did you get the code from? Seems like it has confused you. So basically, what are you trying to do? Compare two inputs. If both match, then start the timer, and if both do not match, then stop it?
yea…sry..dat was d code i wrote without learning about interrupts…i’ve modified it now…but the idea is as u’ve stated….i’ve written it for one i/p oly…jus to see if i can get a count on the display..but dat does not work either..
Hi viii
If you simply wish to compare two inputs, then you need to take the inputs via the digital pins and then simply compare them using the if() statement. Why do you need to include interrupts. And please be more clear. I don’t get your problem. You say that you want to compare two inputs, then you say that you use one input to see if you get a count on the display. How have you implemented your count function? And which display are you using?
ok…i’m using an atmega16 development board with an lcd for display….basically i’m giving two i/ps to the muc through two ports…one is a sensor i/p and the other one is a square wave…and it is something like this..
if(sensor=high){
if(square i/p=low)
{start counter}
else
{stop counter}
}
else
reset counter
now i want this sequential count ( where the counter starts and stops )to be displayed on the lcd ……
i was introduced to atmegs recently..never programmed a muc b4!….i’m lacking time here…so did’nt learn the basics at all…but i’m doin it now…so…hopefully i’l have a code written by d end of it…but some help will b gr8ly appreciated…
Hi Viii
Well, this is a pretty straightforward application. Just read through my tutorials and you will be all set!
Well done man, good tutorial…
Thanks,
Thanks a lot!!
is it possible to make a function in wch i pass delay(in microsec.) as argument and whnever i call that function i got the delay….?
e.g.
delay(5000); ->>>>>>this will give the 5 ms delay…if yes thn how?plz help me a bit….
Hi Ramdas,
Why don’t you use
_delay_us(5000);?? It’s already inbuilt.You simply need to include
#includein the header.hey mayank ,
r u talking about #include
if yes, thn sorry to say that that it will not give us an exect delay….i m using this delay bt if i will right _delay_ms(1000);
thn it will not give me an exact 1 sec. delay…..i wana make a header file for exact delay….if u have any suggestion thn plz help me…. thnks
You should check out my timer tutorials. Using that, you will be able to do so, and that too very accurately!
Amazing tutorials. gud work!
Thanks Sharadwi!
These are really good tutorials. I’ve been recommending them to some guys I’m teaching part-time.. the learning curve is really good for a newbie.
will u give me hex file for avr programs like timer led blinking
Hi Mizpah,
Why don’t you compile the above code and generate the hex file yourself?
Code for ATmega8:
Brother,
I need AC dimming Program,
I have need Zero-Crossing and the delay will be timer0,
how can i done it
please help me.
Hi Pulak,
Please be more clear with your queries.
Thank you.
PS. We do not write code for anyone, however, we do help them to write one themselves! But before asking, kindly read the posts on this website.