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
- 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++;
}
—————————————–
To start with we include the 2 Header files & then declare a variable 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
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
a very good presentation and useful to implement