Timer in AVR ATmega16/ATmega32


Generally, we use a timer/counter to generate time delays, waveforms, or to count events. Also, the timer is used for PWM generation, capturing events, etc.

In AVR ATmega16 / ATmega32, there are three timers:

  • Timer0: 8-bit timer
  • Timer1: 16-bit timer
  • Timer2: 8-bit timer

Basic registers and flags of the Timers

TCNTn: Timer / Counter Register

           Every timer has a timer/counter register. It is zero upon reset. We can access value or write a value to this register. It counts up with each clock pulse.

TOVn: Timer Overflow Flag

           Each timer has a Timer Overflow flag. When the timer overflows, this flag will get set.

TCCRn: Timer Counter Control Register

           This register is used for setting the modes of timer/counter.

OCRn: Output Compare Register

          The value in this register is compared with the content of the TCNTn register. When they are equal, the OCFn flag will get set.


Let us see Timer0 to understand the timers in ATmega16 / ATmega32


First, we need to understand the basic registers of the Timer0

  1. TCNT0: Timer / Counter Register 0

            It is an 8-bit register. It counts up with each pulse.

       2. TCCR0: Timer / Counter Control register 0

            This is an 8-bit register used for the operation mode and the clock source selection.



Bit 7- FOC0: Force compare match

        Write only a bit, which can be used while generating a wave. Writing 1 to this bit causes the wave generator to act as if a compare match has occurred.

Bit 6, 3 - WGM00, WGM01: Waveform Generation Mode

WGM00WGM01Timer0 mode selection bit
01CTC (Clear timer on Compare Match)
10PWM, Phase correct
11Fast PWM


Bit 5:4 - COM01:00: Compare Output Mode

           These bits control the waveform generator. We will see this in the compare mode of the timer.

Bit 2:0 - CS02:CS00: Clock Source Select

           These bits are used to select a clock source. When CS02: CS00 = 000, then timer is stopped. As it gets a value between 001 to 101, it gets a clock source and starts as the timer.

000No clock source (Timer / Counter stopped)
001clk (no pre-scaling)
010clk / 8
011clk / 64
100clk / 256
101clk / 1024
110External clock source on T0 pin. Clock on falling edge
111External clock source on T0 pin. Clock on rising edge.


        3. TIFR: Timer Counter Interrupt Flag register



Bit 0 - TOV0: Timer0 Overflow flag

            0 = Timer0 did not overflow

            1 = Timer0 has overflown (going from 0xFF to 0x00)

Bit 1 - OCF0: Timer0 Output Compare flag

            0 = Compare match did not occur

            1 = Compare match occurred

Bit 2 - TOV1: Timer1 Overflow flag

Bit 3 - OCF1B: Timer1 Output Compare B match flag

Bit 4 - OCF1A: Timer1 Output Compare A match flag

Bit 5 - ICF1: Input Capture flag

Bit 6 - TOV2: Timer2 Overflow flag

Bit 7 - OCF2: Timer2 Output Compare match flag


Timer0 Overflow

Normal mode: When the counter overflows i.e. goes from 0xFF to 0x00, the TOV0 flag is set.


Creating Delay Using Timer0

Steps to Program Delay using Timer0

1. Load the TCNT0 register with the initial value (let’s take 0x25).

2. For normal mode and the pre-scaler option of the clock, set the value in the TCCR0 register. As soon as the clock Prescaler value gets selected, the timer/counter starts to count, and each clock tick causes the value of the timer/counter to increment by 1.

3.Timer keeps counting up, so keep monitoring for timer overflow i.e. TOV0 (Timer0 Overflow) flag to see if it is raised.

4. Stop the timer by putting 0 in the TCCR0 i.e. the clock source will get disconnected and the timer/counter will get stopped.

5. Clear the TOV0 flag. Note that we have to write 1 to the TOV0 bit to clear the flag.

6. Return to the main function.


Program for Timer Delay 

  Generating delay using ATmega16 Timer0

#include <avr/io.h>

void T0delay();

int main(void)
	DDRB = 0xFF;		/* PORTB as output*/
    	while(1)  		/* Repeat forever*/
		T0delay();  	/* Give some delay */

void T0delay()
	TCNT0 = 0x25;  		/* Load TCNT0*/
	TCCR0 = 0x01;  		/* Timer0, normal mode, no pre-scalar */
	while((TIFR&0x01)==0);  /* Wait for TOV0 to roll over */
	TCCR0 = 0;
	TIFR = 0x1;  		/* Clear TOV0 flag*/


The time delay generated by above code

As Fosc = 8 MHz

T = 1 / Fosc = 0.125 μs

Therefore, the count increments by every 0.125 μs.

In above code, the number of cycles required to roll over are:

0xFF - 0x25= 0xDA i.e. decimal 218

Add one more cycle as it takes to roll over and raise TOV0 flag: 219

Total Delay = 219 x 0.125 μs = 27.375 μs



Let us generate a square waveform having 10 ms high and 10 ms low time:

First, we have to create a delay of 10 ms using timer0.

*Fosc = 8 MHz

Use the pre-scalar 1024, so the timer clock source frequency will be,

8 MHz / 1024 = 7812.5 Hz

Time of 1 cycle = 1 / 7812.5 = 128 μs

Therefore, for a delay of 10 ms, number of cycles required will be,

10 ms / 128 μs = 78 (approx)

We need 78 timer cycles to generate a delay of 10 ms. Put the value in TCNT0 accordingly.

Value to load in TCNT0 = 256 – 78 (78 clock ticks to overflow the timer)

= 178 i.e. 0xB2 in hex

Thus, if we load 0xB2 in the TCNT0 register, the timer will overflow after 78 cycles i.e. precisely after a delay of 10 ms.

*Note - All calculations are done by considering 8 MHz CPU frequency. If you are using another value of CPU frequency, modify the calculations accordingly; otherwise, the delay will mismatch.


Program for 10ms Delay Using Timer0

  Generating a delay of 10 ms using ATmega16 Timer0 

#include <avr/io.h>

void T0delay();

int main(void)
	DDRB = 0xFF;		/* PORTB as output */
    	while(1)  		/* Repeat forever */

void T0delay()
	TCCR0 = (1<<CS02) | (1<<CS00); /* Timer0, normal mode, /1024 prescalar */
	TCNT0 = 0xB2;  		/* Load TCNT0, count for 10ms */
	while((TIFR&0x01)==0);  /* Wait for TOV0 to roll over */
	TCCR0 = 0;
	TIFR = 0x1;  		/* Clear TOV0 flag */


Timer Interrupt 

TIMSK: Timer / Counter Interrupt Mask Register

We have to set the TOIE0 (Timer0 Overflow Interrupt Enable) bit in the TIMSK register to set the timer0 interrupt so that as soon as the Timer0 overflows, the controller jumps to the Timer0 interrupt routine.


Timer0 Interrupt Program

  	Generating 10 ms delay pulse on PORTB using ATmega16 Timer interrupt

#include <avr/io.h>
#include <avr/interrupt.h>

/* timer0 overflow interrupt */
	PORTB=~PORTB;		/* Toggle PORTB */
	TCNT0 = 0xB2;

int main( void )
	DDRB=0xFF;  		/* Make port B as output */

	TIMSK=(1<<TOIE0);  	/* Enable Timer0 overflow interrupts */
	TCNT0 = 0xB2;  		/* Load TCNT0, count for 10ms*/
	TCCR0 = (1<<CS02) | (1<<CS00); /* Start timer0 with /1024 prescaler*/



Components Used

ATmega 16
ATmega 16


ATmega_Timer_Interrupt_Project_File Download
ATmega_Timer_Delay_Project_File Download