AVR TIMER0 treating with prescaler and without to blink a led

avrctimer

I am playing with ATMEGA168A's TIMER0. CPU is running at 20MHz and there are two treatments.

a) Blink a LED at 20ms frequency by using a 1024 prescaler. In that case i count the the times that an overflow occurs for the frequency that prescaler of 1024 'gives' me. And according to the formula, to achieve 20ms delay with 1024 prescaler, timer should overflow 1 time and in the second loop to count 145 'ticks' more. With that method LED is blinking but offcourse we cannot see it. Here is the code:

#define F_CPU 20000000UL

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

volatile uint8_t total_overflow;

void timer0_init(void)
{
    // Setting the 1024 prescaler
    TCCR0B |= (1 << CS00) | (1 << CS02); 

    // Initialize Timer0
    TCNT0 = 0;

    // Initialize the overflow interrupt for TIMER0
    TIMSK0 |= (1 << TOIE0);

    // Enable global interrupts
    sei();

    // Initialize total_overflow variable
    total_overflow =0;
}

// Interrupt service routine
ISR(TIMER0_OVF_vect) 
{
    total_overflow++;
}

int main(void){

    DDRB  = 0b00000001; // SET PB0 pin as output

    timer0_init();

    while(1)
    { 
        if(total_overflow >= 1)
        {

            if(TCNT0 >= 145){

                PORTB ^= (1 << 0);
                TCNT0 = 0;
                total_overflow = 0;
            }
        }
    }
}

b) Blink a LED at 20ms frequency but without using any prescaler. CPU and this time runs at 20MHz. Here occurs that to achieve a time delay of 20ms, TIMER0 needs to overflow 1568 times and in the 1569th time to count 160 more 'ticks'. In that case the LED doesn't light. Here is the code:

#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile uint8_t total_overflow;

void timer0_init(void)
{
    // Setting the no prescaler
    TCCR0B |= (1 << CS00); 

    // Initialize Timer0
    TCNT0 = 0;

    // Initialize the overflow interrupt for TIMER0
    TIMSK0 |= (1 << TOIE0);

    // Enable global interrupts
    sei();

    // Initialize total_overflow variable
    total_overflow =0;
}

// Interrupt service routine
ISR(TIMER0_OVF_vect) 
{
    total_overflow++;
}

int main(void){

    DDRB  = 0b00000001; // SET PB0 pin as output

    timer0_init();

    while(1)
    { 
        if(total_overflow >= 1568)
        {

            if(TCNT0 >= 160){

                PORTB ^= (1 << 0);
                TCNT0 = 0;
                total_overflow = 0;
            }
        }
    }
}

Any idea why this happening ? Am i doing something wrong or there is a limitation on how many times a timer can be overflowed (<– that seems silly idea).

Thank you.

Best Answer

total_overflow will never be larger than 1568 because you are using an 8bit unsigned integer for the job, which can only count to 256 (0-255). Change

volatile uint8_t total_overflow;

to

volatile uint16_t total_overflow;

so that your variable can hold high enough values.

EDIT: Also, you should move the declaration of your total_overflow to main instead of having it global and set it to 0 straight away.

int main(void){
    uint16_t total_overflow = 0;
    (...)
    while(1){
        (...)

EDIT2: Sorry, disregard first edit as I didn't see you increasing the variable in interrupt context.