ISR-defining vs checking for TIFR corresponding bit in AVR timer programming

217 Views Asked by At

With timers, I want to toggle an LED every one second. I'm using ATMega32 and the clock frequency is 1MHz. I can get to 0.1 second using the 8-bit counter, and for each 10 timer interrupts, I blink the led.

#define F_CPU 1000000UL

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

typedef unsigned char   u8_t;
typedef unsigned short u16_t;

void func();

int main(void)
{
    DDRC = 0x80;
    TCCR0 |= (1 << WGM01); // CTC bit.
    TCCR0 |= (1 << CS02) | (1 << CS00); // Prescalar = 1024.
    
    OCR0 = 98; // 98 ticks correspond to roughly 0.1 second with 1024 prescaler
    TIMSK |= (1 << OCIE0); 
    TCNT0 = 0; 
    sei();
    
    while(1)
    {
        if (!(TIFR & (1 << OCF0))) {
            func();
        }
    }
}

void func()
{
    static u8_t extra_time = 0;
    
    if (extra_time == 10)
    {
        extra_time = 0;
        PORTC ^= 0x80;
    }
    else extra_time++;
    
    TIFR |= (1 << OCF0);
}

In the preceding code, I do not define an ISR for the TIMER0_COMP_vect interrupt.

From the datasheet:

The OCF0 bit is set (one) when a compare match occurs between the Timer/Counter0 and the data in OCR0 – Output Compare Register0. OCF0 is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, OCF0 is cleared by writing a logic one to the flag. When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.

emphasis mine.

Therefore, by the emphasized sentence, I can check for the OCF0 bit for being a zero, and if so, I can "handle" the on-compare-match event.

However, the LED blinks much more frequently (not even a tenth second between each blink but I cannot measure of course).

This works fine if I just set an ISR on TIMER0_COMP_vect and check for nothing, but I want to know why is the OCF0 always(?) logic 0, hence "on", even though I set it to high on each func() call. And what's the problem with this method.

1

There are 1 best solutions below

0
On

Keep reading the next line in the data sheet

When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.

then take a look at your code

  • you have Enabled Compare Match Interrupt
TIMSK |= (1 << OCIE0); 
  • you have Enabled the Global interrupt (I-bit in SREG)
sei();
  • so whenever output compare flag OCF0 is set then all the 3 conditions for interrupt have occurred and interrupt is automatically fired

when an interrupt has been fired the program flow of execution will jump to a specific memory location corresponding to this interrupt to execute the code and handle it,

but you did not provide any code for this interrupt (no ISR), so the microcontroller does not know what he can do because you did not tell him, so simply he will RESET

and so on, interrupt with no Handler keep fired makes the microcontroller keep reset

finally, when you add an empty ISR you Provide a code which tell the microcontroller to do nothing if this interrupt is fired and the micro will not reset because he knows how to handle it

if you want to keep track OCF0 flag by yourself delete this line

TIMSK |= (1 << OCIE0);