AVR TIMER0 tratando con prescaler y sin parpadear un led

0

Estoy jugando con el TIMER0 de ATMEGA168A. La CPU está funcionando a 20MHz y hay dos tratamientos.

a) Parpadea un LED a una frecuencia de 20 ms utilizando un precalculador 1024. En ese caso, cuento las veces que se produce un desbordamiento para la frecuencia que el prescaler de 1024 'me da'. Y de acuerdo con la fórmula, para lograr un retraso de 20 ms con 1024 preescalador, el temporizador debe desbordarse 1 vez y en el segundo bucle para contar 145 "tics" más. Con ese método, el LED parpadea pero, por supuesto, no podemos verlo. Aquí está el código:

#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) Parpadea un LED a una frecuencia de 20 ms pero sin usar ningún prescaler. CPU y esta vez corre a 20MHz. Aquí ocurre que para lograr un retardo de tiempo de 20 ms, TIMER0 debe desbordarse 1568 veces y en la 1569a vez para contar 160 'tics' más. En ese caso el LED no se enciende. Aquí está el código:

#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;
            }
        }
    }
}

¿Alguna idea de por qué sucede esto? ¿Estoy haciendo algo mal o hay una limitación de cuántas veces se puede desbordar un temporizador (< - eso parece una idea tonta).

Gracias.

    
pregunta F.N

1 respuesta

3

total_overflow nunca será mayor que 1568 porque está usando un entero sin signo de 8 bits para el trabajo, que solo puede contar hasta 256 (0-255). Cambio

volatile uint8_t total_overflow;

a

volatile uint16_t total_overflow;

para que su variable pueda contener valores suficientemente altos.

EDITAR: Además, debe mover la declaración de su total_overflow a main en lugar de tenerla global y establecerla en 0 de inmediato.

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

EDIT2: Disculpe, ignora la primera edición ya que no te vi aumentando la variable en el contexto de interrupción.

    
respondido por el chwi

Lea otras preguntas en las etiquetas