Timer1 auf ATtiny85 funktioniert nicht wie erwartet

Ich versuche, Timer1 auf dem ATtiny85 (Adafruit Trinket) zu verwenden, um jede Sekunde eine LED zu blinken. Der Prescaler-Wert ist 1024 und der Vergleichsregisterwert ist 28. Ich schleife dies 279 Mal durch, um eine Verzögerung von 1 Sekunde zu erhalten.

1024   . 28   . 279 8   .10 6 1

Mit dem folgenden Code bekomme ich ungefähr 8,5 Sekunden. Ich habe beim Kompilieren -mmcu=attiny85 und -DF_CPU=8000000UL gesetzt. Was könnte mir fehlen.

#include <stdint.h>
#include <avr/interrupt.h>

#define TIMER_OVERFLOW_COUNT 279

volatile uint16_t timerCount = TIMER_OVERFLOW_COUNT;
ISR(TIMER1_OVF_vect)
{
    timerCount++;
}

int main(void)
{
    DDRB = 1 << DDB1;
    OCR1C = 28;
    TIMSK = 1 << TOIE1;
    sei();
    TCCR1 = (1 << CS13) | (1 << CS11) | (1 << CS10);
    while( 1)
    {
        if( timerCount >= TIMER_OVERFLOW_COUNT)
        {
            timerCount = 0;
            PORTB ^= 1 << PORTB1;
        }
    }
    return 0;
}
Das Aktualisieren timerCountsowohl des Interrupt-Handlers als auch der Schleife ist eine schlechte Idee. Sie haben hier eine Race-Condition. Warum nicht die gesamte Logik in den Handler stecken? Es ist nicht so schwer.
@EugenSch. Obwohl es stimmt, finde ich es schwer zu glauben, dass es die ganze Zeit auf einem System passiert, das eine viel höhere Frequenz als die Interrupt-Frequenz hat. Das Deaktivieren der Interrupts vor und das Aktivieren nach der Änderung der Hauptfunktion ist immer noch eine gute Idee ... Ich mag die obskure Magie nicht, die Frequenz mit einer Compiler-Option einzustellen - läuft sie wirklich mit 8 MHz? Gibt es Prescaler für Peripherie im ATTiny85?
Sind Sie sicher, dass die MCU auf 8 MHz läuft?
@EugeneSh., danke. Aber das löst nicht das Problem, das ich habe.
Warum wird das F_CPUüberhaupt benötigt? Ich denke, es wird nur für einige Bibliotheksverzögerungsfunktionen verwendet, die nicht im Code verwendet werden.
Mit dem Standardtakt von 1 MHz sollte diese Verzögerung etwa 8 Sekunden betragen.
Warten. Sie möchten nicht bei Überlauf unterbrechen, Sie möchten bei Vergleichsübereinstimmungen unterbrechen
@BenceKaulics. Ich hatte das mit Timer 0 zum Laufen gebracht. Ich bin mir sicher, dass es 8 MHz sind.
@EugeneSh hat es richtig verstanden, Sie erhalten einen Interrupt bei Überlauf, nicht wenn der Zähler 28 erreicht. Sie müssen das OCIE1CBit setzen, nicht das TOIE1in TIMSK. So weit ich mich erinnere.
@EugenSch. Du könntest Recht haben, denke ich. Mein Problem ist jetzt, dass ich nicht sehe, wie es geht.
@BenceKaulics Es gibt kein OCIE1C-Bit in TIMSK. Es ist also nicht möglich, beim Vergleichen eine Unterbrechung zu haben, es sei denn, ich verwende OCR1A oder OCR1B?
@ SubaThomas Ich habe sicher Recht. Aber die Vorgehensweise sollte im Datenblatt beschrieben und in einigen Tutorials demonstriert werden.
Es war nur eine Vermutung, wie Sie einstellen, OCR1C = 28aber dann verwenden OCR1A = 28;und einstellen OCIE1A.
@EugenSch. Im Datenblatt gibt es keinen TIMER1_COMPC. Ich stimme Ihnen zwar zu, dass Sie Recht haben, aber ich glaube nicht, dass es möglich ist, diesen Vergleichs-Match-Interrupt auszulösen. (Es sei denn, ich schaue nicht genau genug hin.)
Es gibt TIMER1_COMPA.. man kann es auch sehr gut gebrauchen. Oder Sie können immer noch den Überlauf-Interrupt verwenden, wenn Sie den anfänglichen Timer-Wert jedes Mal korrekt berechnen (MAX-28).
@EugeneSh und Bence Kaulics, danke für deine Hilfe. Ich habe das Datenblatt etwas sorgfältiger gelesen und Folgendes festgestellt: "Im normalen Modus wird ein Überlauf-Interrupt (TOV1) generiert, wenn Timer/Counter1 von $FF bis $00 zählt ..." Im Wesentlichen ist die Vergleichsoption in nicht verfügbar normaler Modus. Ich habe TIMER_OVERFLOW_COUNT auf 31 geändert und OCR1C auf 255 gesetzt (was wirklich überflüssig ist) und die Dinge funktionieren wie erwartet.
Im Wesentlichen ist die Vergleichsoption im normalen Modus nicht verfügbar. Klingt für mich wirklich verdächtig. Wie sind Sie zu diesem Schluss gekommen?
1) Wenn ich mich im normalen Modus befinde, zählt TCNTI 255 Mal. Die Verzögerung in meinem ursprünglichen Code war 9.1
1024   . 255   . 279 8   .10 6
2) Ich konnte keinen dokumentierten Vergleichs-Match-Interrupt finden. In diesem Modus wird nur der Overflow-Interrupt dokumentiert.
Ich habe in dieser Frage mit Output Compare A Match Interrupt einen Code für einen 1-Sekunden-Interrupt für einen anderen AVR geschrieben . Der Timer sollte sich im CTC-Modus (Clear Timer on Compare match) befinden.
@BenceKaulics, dieser Timer hat keinen CTC-Modus. Es gibt ein CTC1-Bit, das den Timer-Zähler zurücksetzt, wenn es eine Übereinstimmung mit OCR1C gibt, aber es gibt keinen zu erfassenden Interrupt, wenn es passiert.
@SubaThomas - dieser Timer hat keinen CTC-Modus. Ich bin sehr spät zu diesem Thread, aber Sie haben absolut Recht. Vielen Dank, dass Sie diesen feinen Unterschied entdeckt haben – der Wortlaut des Datenblatts ist so verwirrend. Ich habe dies umgangen, indem ich den PWM1A-Modus verwendet und sowohl OCR1A als auch OCR1C auf das gewünschte TOP eingestellt habe - in meinem Fall 103 auf 1 MHz, um 9600 bps zu erhalten. Danke noch einmal. Lebensretter-Kommentar hier!

Antworten (1)

Die Sicherung CKDIV8 ist bei Geräten ab Werk programmiert. Wenn Sie vergessen, diese Sicherung zu deprogrammieren, läuft das Gerät mit 1/8 der erwarteten Taktfrequenz.