AVR TIMER0 Behandlung mit Vorteiler und ohne eine LED zu blinken

Ich spiele mit TIMER0 von ATMEGA168A. Die CPU läuft mit 20 MHz und es gibt zwei Behandlungen.

a) Blinken einer LED mit einer Frequenz von 20 ms unter Verwendung eines 1024-Prescalers. In diesem Fall zähle ich die Zeiten, in denen ein Überlauf für die Frequenz auftritt, die mir der Prescaler von 1024 "gibt". Und gemäß der Formel, um 20 ms Verzögerung mit 1024 Prescaler zu erreichen, sollte der Timer 1 Mal überlaufen und in der zweiten Schleife 145 'Ticks' mehr zählen. Bei dieser Methode blinkt die LED, aber wir können sie natürlich nicht sehen. Hier ist der 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) Blinken einer LED mit einer Frequenz von 20 ms, jedoch ohne Verwendung eines Prescalers. CPU und läuft diesmal mit 20MHz. Hier kommt es vor, dass TIMER0, um eine Zeitverzögerung von 20 ms zu erreichen, 1568 Mal überlaufen und beim 1569. Mal 160 weitere 'Ticks' zählen muss. In diesem Fall leuchtet die LED nicht. Hier ist der 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;
            }
        }
    }
}

Irgendeine Idee, warum das passiert? Mache ich etwas falsch oder gibt es eine Begrenzung, wie oft ein Timer überlaufen kann (<-- das scheint eine dumme Idee zu sein).

Danke schön.

Antworten (1)

total_overflowwird nie größer als 1568 sein, da Sie für den Job eine 8-Bit-Ganzzahl ohne Vorzeichen verwenden, die nur bis 256 (0-255) zählen kann. Ändern

volatile uint8_t total_overflow;

Zu

volatile uint16_t total_overflow;

damit Ihre Variable ausreichend hohe Werte aufnehmen kann.

BEARBEITEN: Außerdem sollten Sie die Deklaration Ihrer total_overflownach main verschieben, anstatt sie global zu haben, und sie sofort auf 0 setzen.

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

EDIT2: Entschuldigung, ignorieren Sie die erste Bearbeitung, da ich nicht gesehen habe, dass Sie die Variable im Interrupt-Kontext erhöht haben.