This mode is similar to the normal port operation. The difference is that the compare value is store in the OCRx register instead of TCNTx. In order to use the OCRx register, the timer should operate in CTC mode, that
TCCR0|=(1<<WGM01); //CTC mode
The main program is
#include<avr/io.h>
int main(void)
{
DDRC=0xff;
TCCR0|=(1<<WGM01); //CTC mode
TCCR0|=(1<<CS02)|(1<<CS00); //F_CPU/1024
TCNT0=0; //clear Timer
while(1)
{
OCR0=97; //100ms Timer
PORTC^=0xff;
}
return 0;
}
As soon as OCRx register is equal is equal to TCNTx register an interrupt available and we can use the interrupt. In order to use the interrupt we need to set the interrupt enable bit i.e. Timer/Counter-x, Output Compare Match Interrupt Enable bit. Let enable the Timer/Counter0 Output Compare Match Interrupt and use it. The corresponding service routine is ISR(TIMER0_COMP_vect). Internal interrupt enable as the same as external interrupt. Three must be set
#include<avr/interrupt.h>
sei(); //Global Interrupt Enable
TIMSK|=(1<<OCIE0); //Timer/Counter0 Output Compare Match Interrupt Enable
ISR(TIMER0_COMP_vect)
{
/******** do something at that interrupt *****************/
}
Let’s make a time clock that display time in LCD display. The parameter is 8MHz external crystal and prescaler=256. Let make a delay of 8ms with the parameter. So the OCR0 value should be
OCR0=(8ms)*(8MHz/256)-1 =249
Since our OCR0 value is 249, so after 8ms an interrupt can available. We use this interrupt for our second, minute and hour calculation. In interrupt the second calculation is 1s=(1000/8)=125. So we declare four variables millisecond, second, minute and hour. The logic is when millisecond=125 is one second, when 60 second 1 minute and 60 minute 1hour. The logic is
/***********************************************************************************************
************************************************************************************************
********************************* Digital Clock ************************************************
************************************************************************************************
***********************************************************************************************/
#include<avr/io.h>
#include<stdio.h>
#include<util/delay.h>
#include<avr/interrupt.h>
#include"lcd.h"
uint8_t millisecond=0,second=0,minute=0,hour=0;
char str[20];
int main(void)
{
LCD_INIT();
LCD_write_string(1,1,"**Digital Clock*");
TCCR2|=(1<<WGM21)|(1<<CS22)|(1<<CS21); //normal CTC mode with 256
TCNT2=0; //clear Timer
TIMSK|=(1<<OCIE2); //Timer/Counter0 Output Compare Match Interrupt Enable
sei(); //Globel Interrupt Enable
OCR2=249; //F_CPU=8MHz,P=256,Delay=8ms
while(1)
{
if(hour<=12){
sprintf(str,"TIME %d:%d :%d am",hour,minute,second);
LCD_write_string(1,2,str);
}
else{
sprintf(str,"TIME %d:%d :%d pm",hour,minute,second);
LCD_write_string(1,2,str);
}
}
return 0;
}
ISR(TIMER2_COMP_vect)
{
millisecond++;
if(millisecond==125){
second++;
millisecond=0;
if(second==60){
minute++;
second=0;
}
if(minute==60){
hour++;
minute=0;
if(hour==24) hour=0;
}
}
}
In CTC mode we can also use the OC0 pin to generate a square wave. In that case we have to set the OC0 pin to output pin. See the COM01 and COM00 logic operation to make your desire program. The CTC mode of Timer1 and Timer2 is similar to Timer0. Let build a toggle CTC program with Timer1. For register description see the data sheet of ATmega32 Timer1. We use Timer/Counter1, Output Compare A Match Interrupt. The full program as follow-
#include<avr/io.h>
#include<avr/interrupt.h>
uint8_t sample;
int main(void)
{
DDRB=0xFF;
DDRD|=(1<<DDD5); //OC1A output PIN
TCCR1B=(1<<WGM12)|(1<<CS12); //CTC with prescaler=256
TCCR1A=(1<<COM1A0); //Toggle OC1A/OC1B on compare match
TCNT1=0; //Clear Timer
OCR1A=31249; //F_CPU=8MHz,Prescaler=256,Delay= 1s
sei(); //Globel Interrupt Enable
TIMSK=(1<<OCIE1A); // Timer/Counter1, Output Compare A Match Interrupt Enable
while(1);
return 0;
}
ISR(TIMER1_COMPA_vect)
{
sample^=1;
sample ? (PORTB=0xFF):(PORTB=0x00);
}
We already know that as soon as OCRx register is equal to TCNTx register an interrupt available. We can use this interrupt without enabling the interrupt i.e. glag register. The all flags register are available at #include<avr/io.h>, so no need of #include<avr/interrupt.h> and ISR service routine.
The flag register of individual interrupt is active when an interrupt active that OCRx is equal to TCNTx. Let’s modify the above program without interrupt handling
#include<avr/io.h>
uint8_t sample;
int main(void)
{
DDRB=0xFF;
DDRD|=(1<<DDD5); //OC1A output PIN
TCCR1A=(1<<COM1A0); //Toggle OC1A/OC1B on compare match
TCCR1B=(1<<WGM12)|(1<<CS12); //CTC with prescaler=256
TCNT1=0; //Clear Timer
OCR1A=31249; //F_CPU=8MHz,Prescaler=256,Delay= 1s
while(1)
{
if(TIFR&(1<<OCF1A)){
PORTB^=0xFF;
TIFR|=(1<<OCF1A);
}
}
return 0;
}
Since we already know about our basic C to check a bit the condition is
C:/> (register name &(1<< bit position))
Since the flag is set when OCRx value is equal to TCNTx value so in if() format we check the value and the flag is clear by writing 1 to it i.e. TIFR|=(1<<OCF1A);.