1

With timers, I want to toggle an LED every one second. I'm using ATmega32 and the clock frequency is 1 MHz. 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); // Prescaler = 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 (emphasis mine):

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.

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 Answer 1

2

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 the output compare flag OCF0 is set, then all the three conditions for the interrupt have occurred and an 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 it can do, because you did not tell it, so simply it will RESET.

And so on. An interrupt without any handler keeps firing, making the microcontroller keep resetting.

Finally, when you add an empty ISR, you provide code which tells the microcontroller to do nothing if this interrupt is fired and the microcontroller will not reset, because it knows how to handle it.

If you want to keep track of the OCF0 flag by yourself, delete this line:

TIMSK |= (1 << OCIE0);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.