So, nachdem ich noch weiter recherchiert und im Datenblatt gelesen habe,
konnte ich zumindest den Compare-Interrupt korrekt implementieren.
Ich zeige ich mal meinen Code und vlt. seht ihr ja, wo mein Fehler ist:
1. Variante mit Overflow-Interrupt
1 | void init() {
|
2 | __disable_interrupt();
|
3 |
|
4 | TIMSK2 &= ~(1<<TOIE2);
|
5 | ASSR = (1<<AS2); // select asynchronous operation of Timer2
|
6 |
|
7 | TCNT2 = 0; // clear TCNT2A
|
8 |
|
9 | TCCR2A = (0<<CS22) | (1<<CS21) |(1<<CS20); // Vorteiler auf 32
|
10 |
|
11 |
|
12 | while((ASSR & 0x01) | (ASSR & 0x04)); // wait for TCN2UB and TCR2UB to be cleared
|
13 |
|
14 | TIFR2 = 0xFF; // clear interrupt-flags
|
15 |
|
16 | TIMSK2 |= (1<<TOIE2); // enable Timer2 overflow interrupt
|
17 |
|
18 | __enable_interrupt();
|
19 | }
|
Interrupt-Routine:
1 | #pragma vector = TIMER2_OVF_vect
|
2 | __interrupt void TIMER2_OVF_interrupt(void)
|
3 | {
|
4 | static int overflows = 0;
|
5 | ++overflows;
|
6 |
|
7 | if(overflows == 4) {
|
8 | ++sekunden; // Globale volatile int
|
9 | overflows = 0;
|
10 | }
|
11 | }
|
Diese Variante arbeitet korrekt. Auch nach mehreren Minuten stimmen die
gezählten Sekunden mit den Sekunden meiner Vergleichsuhr überein!
Funktioniert also.
2. Variante: CTC und Compareinterrupt
1 | void init() {
|
2 | __disable_interrupt();
|
3 |
|
4 | TIMSK2 = (1<<OCIE2A) | (0<<TOIE2);
|
5 | ASSR = (1<<AS2); // select asynchronous operation of Timer2
|
6 |
|
7 | TCNT2 = 0; // clear TCNT2A
|
8 |
|
9 | // Output Compare Register A auf 0 setzen:
|
10 | OCR2A = 0; /* Datenblatt S. 139: "Whenever TCNT2 equals OCR2A, the comparator signals a match. A match will set
|
11 | the Output Compare Flag (OCF2A) at the next timer clock cycle." */
|
12 |
|
13 |
|
14 | TCCR2A = (0<<CS22) | (1<<CS21) |(1<<CS20) | (1<<COM2A1) | (0<<COM2A0) | (1<<WGM21) | (0<<WGM20); // Vorteiler auf 32, CTC an.
|
15 |
|
16 | while((ASSR & 0x01) | (ASSR & 0x04)); // wait for TCN2UB and TCR2UB to be cleared
|
17 |
|
18 | TIFR2 = 0xFF; // clear interrupt-flags
|
19 |
|
20 | TIMSK2 |= (1<<TOIE2); // enable Timer2 overflow interrupt
|
21 |
|
22 | __enable_interrupt();
|
23 | }
|
Interrupt-Routine:
1 | #pragma vector = TIMER2_COMP_vect
|
2 | __interrupt void TIMER2_COMP_interrupt(void)
|
3 | {
|
4 | static int overflows = 0;
|
5 | ++overflows ;
|
6 |
|
7 | if(overflows == 1024) {
|
8 | overflows = 0;
|
9 | ++sekunden;
|
10 | }
|
11 | }
|
Die Idee bei dieser Variante ist, jeden der 32768/32=1024 "Ticks" im
Compare-Interrupt abzugreifen. Diese Variante zählt FAST richtig. Jede
Minute geht allerdings 1 Sekunde verloren. Nach 180 Sekunden realer Zeit
zeigt mir mein Microkontroller 177 Sekunden an.
Meine Vermutung (aus diesem Thread:
Beitrag "(Atmel) CTC counter zählen unterschiedlich schnell"):
Kann es an den 1024 Interrupt-Aufrufen pro Sekunde liegen?
Zitat: "Aber wenn Du Interrupts aktiv hast,
ist es ja wohl klar, dass ab einer gewissen "Geschwindigkeit" was
verloren geht,[...]"