VIDEO TUTORIALS ON TIMER0 :

Timers/counters are an independent unit inside AVR. They  run independently of what task CPU is performing. In this post we’ll explore the TIMER 0 Interrupts of AVR ATMEGA 16 .The previous post was on External Interrupts , this TIMER 0 is Internal Interrupt.

AVR ATMEGA 16 has 3 timers TIMER0 ,TIMER 1 & TIMER 2.Of these TIMER 1 is 16 bit Timer while others are 8 bit timers.

8-bit timer is capable of counting 2^8=256 steps from 0 to 255

Similarly a 16 bit timer is capable of counting 2^16=65536 steps from 0 to 65535. Due to this feature, timers are also known as counters. When the timer returns to its initial value of zero , We say that the timer/counter overflows.

Timer Events

1. OVERFLOW

In normal operation overflow occurs when the count value passes 0XFF & becomes 00

Timer 0 is a 8 bit timer. It basically means it can count from 0 to 2^8 255. The operation of timer 0 is straight forward. The TCNT0 register hold the timer Count and it is incremented on every timer “tick”. If the timer is turned on it ticks from 0 to 255 and overflows. If it does so, a Timer OverFlow Flag (TOV) is set.

The Flags are present inside the Register TIFR which is common for all 3 timers.

2. COMPARE MATCH

Another interesting feature is that a value can be set in the Output Compare Register (OCR0), and whenever TCNT0 reaches that value, the Output Compare Flag (OCF0) flag is Set.

We say Compare Match has occurred  when the count value equals the contents of the output compare register

In this post we handle these above 2 events using the Interrupt concept.

OVERFLOW INTERRUPT

TCNT0 is the register that holds the current value of Timer

You can read from or write to this register to set your own time.

Timer0 works by incrementing this TCNT0a counter variable, also known as a counter register. The counter register can count to a value 0XFF , as Timer 0 is 8 bit .

The timer increments this counter one step at a time until it reaches its maximum value (255), at which point the counter overflows, and resets back to zero. The timer sets a flag (OVF0) bit .

You can check this flag inside TIFR register manually, or you can also have the timer trigger an interrupt (TOIE0) as soon as the flag is set. An  Interrupt Service Routine (ISR) is called automatically to run code of your choice when the timer overflows.

The ISR will reset the overflow flag behind the scenes automatically

TIMER0 uses 2 8 bit DATA REGISTERS  TCNT0 , OCR0

If you enable TCNT0 the register will increment from 0 counts upto 255 then overflos & start counting again ,

OCR0 never increments.You need to set a value bet 0 & 255

2 conditions occur OVERFLOW , COMPARE MATCH (TCNT0=OCR0)

The corresponding ISR vector name to be used in the ISR Function

ISR (TIMER0_OVF_vect) {}    for Overflow interrupt

ISR (TIMER0_COMP_vect) {}    for Compare Interrupt

Now let us Calculate the period of clock source .We use an external crystal oscillator of 8MHz

Period = 1/ clock freq = 1/8000000 = 0.125 usec

Timer counter overflows 256 * 0.000125ms = 0.032 msec

For 1 sec delay 10000/0.032 = 31250

Timer0 counter has to overflow 31250 times to generate one sec delay.

To increase the time delay we can reduce the clock applied to counter applying a prescaler

Prescalers of 1 ,8, 256  or  1024 can be applied by setting the CS0:2 bits of TCCR0 register

TCCR0 is the TIMER COUNTER CONTROL REGISTER for TIMER0

PRESCALER decides the speed of increment of TCNT0

Prescaler = 0 timer off

Prescaler = 1 speed of clock on which uc runs

= 2 clk/8      = 3 clk/64      =4 clk/256 ,       =5 clk/1024

=6 ext clock falling edge count ,   =7 ext clock at p0 pin rising edge count

Let us select prescaler of 1024

Programming steps:

1. Initialize TNCNT0 to value 0.

2. Program Prescaler by setting CS bits of TCCR0.

3. Set Timer OverFlow Interrupt TOIE0 bit of TIMSK register.

4. Enable global interrupt by sei () command.

5. Write code for ISR function with vector name TIMER0_OVF_vect

1. Code using OVERFLOW Interrupt that blinks LED at PD6 at 1 second interval

————————————————-

#include <avr/io.h>

#include <avr/interrupt.h>

volatile uint8_t count;

int main (void)

{

DDRD |= (1<<6); //PD6 as output

TCNT0 = 0;

count = 0;

TCCR0 |= (1<<CS02) | (1<<CS00); // PRESCALER 1024

TIMSK = (1<<TOIE0);

sei();

while(1)  {}

}

ISR (TIMER0_OVF_vect)

{

if (count == 31)

{

PORTD ^= (1<<6);

count=0;

}

else

count++;

}

—————————————–

volatile uint8_t count;

Here we use the keyword Volatile , as the variable is a Global one & will be used inside  the ISR Function.If you do not use the volatile keyword & use the variable within ISR , the AVR-GCC compiler may report error while optimizing the code.

As we connect an LED at PD6 we make it as OUTPUT using left shift operator.

We then initialize the TCNT0 & the count variable to 0.

To set the prescaler as 1024 we need to set the bits CS00 & CS02 to 1inside the TCCR0 Register.

TCCR0 |= (1<<CS02) | (1<<CS00);

Next step is to enable the TIMER OVERFLOW INTERRUPT TOIE0 inside the

TIMSK Register

TIMSK = (1<<TOIE0);

Enable the Global interrupt using

sei();

which sets the I bit of SREG.

Next we’ve to write the code for ISR Function.

Correct Vector name must be used in this function.As we use the overflow interrupt select the correct vector name from the vector table  TIMER0_OVF_vect

gfgf

ISR (TIMER0_OVF_vect)

{

if (count == 31)

{

PORTD ^= (1<<6);

count=0;

}

else

count++;

}

Let us see the calculation how we arrived at value 31 in the if condition.

The clock is external crystal 8MHz.We apply a prescaler of 1024.

Now the clock freq to counter becomes 8000000/1024 = 7812.5 Hz

Time period = 1/freq = 1/7812.5 = 0.000128usec or 0.128 milli sec

Overflow occurs every 256*0.000128 = 0.032768sec = 32.768 msec

To generate a time delay of 1 sec 1000/32.768 =  30.5 or 31

So the counter TCNT0 has to overflow 31 times to generate A TIME DELAY OF 1 SEC.

As done in previous example , save this file as main.c

Save  the MFILE  inside the same folder.You can use the same MFILE  as of the previous post example.(Remember to save the C file as main.c)

Make ALL from WINAVR’s Programmers Notepad to create HEX file & then click Program to upload the file.Now the LED at PD6 blinks exactly at 1 second interval.

#### CTC mode operation:

Clear Timer on Compare Match It is better to use instead of Normal mode because in CTC mode, frequency can be easily adjusted.

When the Timer is triggered, register TCNT0 starts counting.

Timer0 has a OCR0 (Output Compare Register), which is continuously compared with TCNT0 register.

In CTC mode whenever match occurs, OCF0 (Output Compare Flag) will set to 1. If continuous wave form generation is required, OCF0 must be reset again.

Alternatively, if OCIE0 (Output Compare interrupt) and Global interrupt flags in SREG are set, OCF0 will reset automatically after interrupt execution.
The bits WGM0 [1:0] are programmed to select waveform generation mode. For enabling CTC set the bit WGM01

Programming steps:

1. Select CTC mode by programming WGM0 [1:0] bit.

2. Program Prescaler by setting CS bits of TCCR0.

3. Load Compare register OCR0 with a value between 0 & 255

4. Set compare Interrupt OCIE0 bit of TIMSK register.

5. Enable global interrupt by sei () command.

6. Write code for ISR function with vector name TIMER0_COMP_vect

OCF0 – Output Compare Flag 0 — Bit 1 of TIFR

is set whenever a compare match occurs. It is cleared automatically whenever the corresponding ISR is executed. Alternatively it is cleared by writing ‘1’ to it.

———————–

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

void  timer_init(void)
{
// set up timer with prescaler = 1024 and CTC mode
TCCR0 = (1 << WGM01) ;
TCCR0=  (1 << CS00) | ( 1<<CS02);
// initialize counter
TCNT0 = 0;
// initialize compare value
OCR0 = 220;
// enable compare interrupt
TIMSK |= (1 << OCIE0);
// enable global interrupts
sei();

}

ISR (TIMER0_COMP_vect)
{
PORTD ^= (1 << 6);
}

int main(void)
{

DDRD |= (1 << 6);
timer_init();

while(1)
{
// do nothing
}
}

————————————–

TCCR0 = (1 << WGM01) ;

We enable the CTC mode in the TCCR0 Register by setting the bit WGM01

We then set the prescaler to 1024 by setting the bits CS00 & CS02

TCCR0=  (1 << CS00) | ( 1<<CS02);

Initialize the TCNT0 Register with 0 value & then load the Output Compare Register with a value 220

OCR0 = 220;

As the TIMER0 is 8 bit timer we can only load the counter with a value between 0 & 255 .This will not create a longer delay & the LED will blink fast , almost stable.In the next post we’ll see the TIMER1 capable of generating longer delay as TIMER1 is 16 bit .

Next enable the Compare Interrupt  OCIE0 within the TIMSK Register

TIMSK |= (1 << OCIE0);

Enable the Global interrupt using sei();

Inside the ISR function we just toggle the LED at PD6

ISR (TIMER0_COMP_vect)
{
PORTD ^= (1 << 6);
}

Note the usage of correct Vector name TIMER0_COMP_vect

Compile the code as done in previous examples & see the LED blinking very fast , as we could generate delay in millisec only using Compare mode.

HARDWARE INTERRUPT USING OC Pins

Instead of enabling the Interrupt we can make use of the OUTPUT COMPARE pins of AVR

The Output Compare Pins are seen as OC pins OC0 at PB3 for Timer0

Programming steps:

1. Select CTC mode by programming WGM0 [1:0] bit.
2. Program COM0 [1:0] bits and select “toggle OC0 if compare match”.

3. Set OC0 (PB3) pin as output pin.
4. Set OCIE0 bit of TIMSK register.

5. Enable global interrupt by “sei ()” command.

Mode    WGM0[1:0]    Mode
0    00    Normal
1    01    PWM,Phase Correct
2    10    CTC
3    11    Fast PWM

The Register TCCR0 also consists COM0 [1:0] bits. These bits are used to select functionality of OC0 pin. Following table shows function of COM 0[1:0]:

COM0[1:0]    Description
00                Normal,OC0 disconnected
01                Toggle OC0 on compare match
10                Clear OC0 on compare match
11               Set OC0 on compare match

#include <avr/io.h>

#include <avr/interrupt.h>

void timer_init(void)

{

// set up timer with prescaler = 1024 and CTC mode

TCCR0 |= (1 << WGM01)|(1 << CS00)|(1 << CS02);

// set up timer OC0 pin (PB3) in toggle mode

TCCR0 |= (1 << COM00);

// initialize counter

TCNT0 = 0;

// initialize compare value

OCR0 = 220;

}

int main(void)

{

// connect led to pin PB3

DDRB |= (1 << 3);

// initialize timer

timer_init();

// loop forever

while(1)  {}

}

OC0  is toggled automatically  no need to keep track of any flag bits or ISR