Überlaufunterbrechung wird nur einmal ausgelöst

Ich bin auf ein Problem gestoßen, bei dem mein Interrupt anscheinend nur einmal ausgelöst wird und sich dann einfach weigert, erneut auf meinem ATMega32U2 zu feuern. Ich habe den folgenden (abgespeckten) Code:

void init(void) {
    DDRB = 0xff;
    PORTB = 0x00;

    TCCR0A = (1 << WGM01);
    // 1024 prescaler
    TCCR0B = ((1 << CS02) | (1 << CS00));
    // Interrupt every 4096 clocks
    OCR0A = 3;
    // Enable timer compare match interrupt
    TIMSK0 != (1 << OCIE0A);
}

ISR(TIMER0_COMPA_vect) {
    PORTB++;
}

int main(void) {
    init();

    sei();

    while(1);

    return 0;
}

Wenn ich eine LED in jeden Pin von stecke PORTB, ist der erste Pin hoch, während der Rest niedrig ist. Das Beste, was ich daraus ableiten kann, ist, dass der Interrupt einmal PORTBinkrementiert und dann in Ruhe gelassen wird, da der Interrupt nie wieder mit dem Vektor ausgelöst wird.0x01TIMER0_COMPA_vect

Wenn ich jedoch den Vergleichs-Interrupt durch einen Überlauf-Interrupt ( TIMER0_OVF_vect) ersetze und die Register anders konfiguriere, funktioniert es einwandfrei; PORTBZyklen durch 0 - 255 sehr schnell, wie ich es erwarten würde. Dies ist mein Arbeitscode mit der Art von Interrupt, die ich nicht möchte:

// Different timer config
void init(void) {
    DDRB = 0xff;
    PORTB = 0x00;

    TCCR0B |= (1 << CS01);

    // Enable timer 0 interrupt
    TIMSK0 |= (1 << TOIE0); 
}

// This time, it's an OVERFLOW vector, not a compare vector
ISR(TIMER0_OVF_vect) {
    PORTB++;
}

int main(void) {
    init();

    sei();

    while(1);

    return 0;
}

Ich habe gelesen, was es bei Google zu lesen gibt, aber die einzigen geposteten Korrekturen sind logische Fehler, von denen ich nicht glaube, dass ich sie habe. Ich habe diesen Forumsbeitrag gelesen und mir die Timer-Konfigurationsregister angesehen, und sie sind genau die gleichen wie in meinem ersten Beispiel. Ich habe diese Frage auch gelesen , aber das hat nicht geholfen.

Ich habe das Tutorial auf dieser Seite (PDF) für den LED-Treiberchip TLC5940 verfolgt und bin in Kapitel 4 (Umgestaltung des Codes zur Verwendung von Interrupts). Bitte beachten Sie, dass ich die fertig erstellte Bibliothek nicht verwenden möchte; Ich nutze dies als Lernerfahrung.

Antworten (1)

Dies kann nur ein Tippfehler in Ihrem Beitrag sein, aber die Zeile, in der Sie den Timer Compare-Interrupt aktivieren, sagt:

TIMSK0 != (1 << OCIE0A);

... wenn es heißen sollte ...

TIMSK0 |= (1 << OCIE0A);

Es ist subtil, aber wenn das Ihr Code tatsächlich war, dann haben Sie TIMSK0 mit einer Konstante verglichen, anstatt ihr zuzuweisen (und daher den Interrupt nie wirklich aktiviert).

In einer Randbemerkung können Sie prägnanter schreiben:

TIMSK0 |= _BV(OCIE0A);

... anstatt ..

TIMSK0 |= (1 << OCIE0A);

in der avr-libc, falls du auf sowas stehst :-).

was ist das _BV?? das habe ich nicht gesehen..
Aber (1 << OCIE0A) ist standardmäßiges idiomatisches C, und _BV(OCIE0A) verwendet ein hässliches, unaussprechliches Makro, das ich noch nie zuvor gesehen habe. Nein danke.
Das sollte auch eine Warnung auslösen, obwohl ich mit dem verwendeten Compiler nicht vertraut bin. Bei meinem Setup mit GCC (4.5.1) wird die Warnung "berechneter Wert wird nicht verwendet" ausgegeben.
@0xakhil - Es ist ein Makro in avr-libc, das den 'Bitwert' der Zahl erhält. Zum Beispiel _BV(3)verwandelt sich in 0b0000 0100, genauso wie ( 1 << 3 ). Es wird "Unterstrich Bee Vee" ausgesprochen.
@vicatcu Danke für den Tipp. Ich schäme mich, dass ich das nicht selbst gesehen habe, aber jetzt funktionieren meine Interrupts, also ist alles in Ordnung.
@JamWaffles kein Problem, froh, dass ich helfen konnte – unterschätze nicht die Kraft frischer Augen!
@markrages _BV wird in der gesamten avr-libc-Dokumentation verwendet. Die Verwendung des Makros erspart Ihnen viele Wiederholungen - es gibt keine "Informationen" im "1 <<"-Teil des (1 << 3)-Idioms, wenn Sie einfach nur ein einzelnes Bit an einer bestimmten Position setzen möchten. Weniger Tippen kann zu weniger Laufzeitfehlern führen. Beispielsweise kann es verhindern, dass Sie versehentlich (1 < 3) eingeben, obwohl Sie (1 << 3) gemeint haben.