Forum: Mikrocontroller und Digitale Elektronik Arduino: TMR2, Interrupt-Problem


von Arlenne (Gast)


Lesenswert?

Hallo liebe Community,

bin mir jetzt nicht sicher, ob das hier das richtige Forum ist. Ich 
versuche es einfach mal und bitte um Nachsicht.
Ich würde das Problem gerne verstehen und beheben. Antworten, dass 
Arduino nicht ernst zu nehmen sei oder man das doch lieber komplett in C 
macht, sind ein anderes Thema und nicht zielführend.

Zum Verständnis habe ich mein Programm auf das wesentliche abgespeckt. 
Das Programm schläft meistens, wird von einem Tastendruck (externer 
Interrupt INT0) oder einem TMR2-Interrupt aufgeweckt. Die jeweilige 
Aufweckoption wird im Programm gewählt. Grundsätzlich funktioniert das 
auch, aber...

Wenn der externe Interrupt zum ersten Mal ausgeführt wird, funktionert 
der Timer Interrupt das erste Mal danach nicht mehr. Dann muss das 
Aufwachen durch einen Tastendruck geschehen. Das nächste Mal 
funktioniert der Timer Interrupt dann.
Als quick and dirty Lösung habe ich deshalb in Setup() den 
Timer-Interrupt aktiviert. Der wird auch ausgeführt.
Nach dem nächsten externen Interrupt (Taster) geht der Timer Interrupt 
aber nicht mehr und der Controller muss durch einen Tastendruck geweckt 
werden.

Hier der komplette Code:
1
#include <avr/sleep.h>
2
3
// **************** Definitions ****************
4
5
// Push Button (wired to interrupt pin and regular digital pin)
6
#define BUTTON_INT          2
7
#define BUTTON              7
8
9
// Timer
10
#define TIMER_INTERVAL      3
11
12
// **************** Global Variables ****************
13
volatile bool buttonPress = false;
14
volatile bool buttonInt = false;
15
volatile bool timerInt = false;
16
volatile unsigned long timerCnt = 0;
17
18
unsigned int timeoutSeconds = 0;
19
volatile bool timeoutFlag = false;
20
21
enum wakeupSources
22
{
23
    EXTERNAL_INTERRUPT,
24
    TIMEOUT_INTERRUPT
25
};
26
27
28
// **************** Sleep and Wakeup, Interrupts and Timer2 ****************
29
30
// Interrupt INT0 for push button
31
void ISR_BUTTON(void)
32
{
33
    detachInterrupt(digitalPinToInterrupt(BUTTON_INT));
34
    buttonPress = true;
35
    buttonInt = true;                                                           // DEBUG
36
}
37
38
// Interrupt Timer2
39
ISR(TIMER2_COMPA_vect)
40
{
41
    static unsigned long counter = 0;
42
43
    counter++;
44
    if (counter >= ((unsigned long)(timeoutSeconds) * 40UL))
45
    {
46
        timeoutFlag = true;
47
        counter = 0;
48
        TIMSK2 = 0;                                                             // disable interrupt
49
    }
50
51
    timerInt = true;                                                            // DEBUG
52
    timerCnt = counter;                                                         // DEBUG
53
54
    return;
55
}
56
57
// Sleep
58
void enterSleep(wakeupSources source, unsigned int timeout_sec)
59
{
60
    Serial.print("\r\nenter sleep, wait for ");
61
    if (source == EXTERNAL_INTERRUPT)
62
    {
63
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
64
        Serial.print("EXT INT... ");
65
66
        buttonPress = false;
67
    }
68
    else if (source == TIMEOUT_INTERRUPT)
69
    {
70
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
71
        Serial.print("TMR INT... ");
72
73
        // Setup TMR2: interrupt every 25ms
74
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
75
        TCCR2B = 0;                                                             // set TCCRXB register to 0
76
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
77
        OCR2A = 194;                                                            // set compare match register of timer 2
78
        TCNT2 = 0;
79
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
80
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt
81
82
        timeoutSeconds = timeout_sec;
83
        timeoutFlag = false;
84
    }
85
    Serial.flush();
86
87
    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts
88
89
    sleep_bod_disable();
90
    do                                                                          // loops when timer interrupts
91
    {
92
        buttonInt = false;                                                      // DEBUG
93
        timerInt = false;                                                       // DEBUG
94
        cli();
95
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
96
        sleep_enable();
97
        sei();
98
        sleep_cpu();
99
        sleep_disable();
100
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
101
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(".");  // DEBUG
102
        Serial.flush();
103
    }
104
    while ( (buttonPress == false) && (timeoutFlag == false));
105
106
    Serial.println("-Wakeup");
107
    Serial.flush();
108
109
    return;
110
}
111
112
113
// **************** Setup ****************
114
void setup(void)
115
{
116
    Serial.begin(115200);
117
    Serial.println();
118
    Serial.println("\r\nHello!");
119
120
    // Button
121
    pinMode(BUTTON_INT, INPUT);                                                 // external pull-Up
122
    pinMode(BUTTON, INPUT);
123
124
    enterSleep(TIMEOUT_INTERRUPT, 0);                                           // This works!
125
    timeoutFlag = 0;                                                            // But 2nd call in main() doesn't !?
126
127
    Serial.println("End of setup()");
128
}
129
130
// **************** Main ****************
131
void loop(void)
132
{
133
    enum wakeupSources wakeupSource;
134
    unsigned int wakeupTimeout;
135
136
    wakeupSource = EXTERNAL_INTERRUPT;                                          // initial wakeup source
137
138
    // -------- Push Button
139
    if (buttonPress == true)
140
    {
141
        buttonPress = false;
142
        Serial.println("button");
143
144
        while(digitalRead(BUTTON) == LOW)
145
            delay(100);
146
147
        wakeupSource = TIMEOUT_INTERRUPT;
148
        wakeupTimeout = TIMER_INTERVAL;
149
    }
150
151
    // -------- Timeout
152
    if (timeoutFlag == true)
153
    {
154
        timeoutFlag = false;
155
        wakeupSource = EXTERNAL_INTERRUPT;
156
        Serial.println("timeout");
157
    }
158
159
    // -------- Sleep
160
    enterSleep(wakeupSource, wakeupTimeout);
161
};

Und hier die Ausgabe des seriellen Monitors:
1
Hello!
2
3
enter sleep, wait for TMR INT... -Wakeup
4
End of setup()
5
6
enter sleep, wait for EXT INT... iB-Wakeup
7
button
8
9
enter sleep, wait for TMR INT... iB-Wakeup
10
button
11
12
enter sleep, wait for TMR INT... ............................................................-Wakeup
13
timeout
14
15
enter sleep, wait for EXT INT...

Hier sieht man, dass der Timer-Interrupt in Setup() funktioniert, nach 
dem ersten externen Interrupt nicht mehr. Das zeigt der dritte Absatz, 
in dem auf einen Timer-Interrupt gewartet wird, der aber nicht kommt und 
deshalb der Taster gedrückt werden muss.

*enter sleep, wait for TMR INT... iB-Wakeup*

button

Die folgenden Timer-Interrupts funktionieren dann alle, das ist hier 
aber nicht gezeigt. Der Beitrag ist auch so schon lang genug...

Ich hoffe, das ist trotz der Länge einigermaßen verständlich und hier 
kann mir jemand helfen, ganz vielen Dank schon mal!

LG
Arlenne

von Arlenne (Gast)


Lesenswert?

Irgendwie scheint es so, als ob der erste Aufruf des externen Interrupts 
den Timer Interrupt so beeinflusst, dass letzterer dann nicht mehr 
funktioniert. Aber eben nur das erste Mal!?

von Axel R. (axlr)


Lesenswert?

bei "enterSleep" musst du sicher den vorherigen Spleemode deaktivieren, 
um den jeweils anderen aktivieren zu können. Ausm Deep-Sleep geht ja nur 
der Low-Level INT am Button.
Denke, dass es dort "hakt", bei der Umschaltung der beiden Sleep-Modi.
Viel Erfolg!

von Arlenne (Gast)


Lesenswert?

Danke für den guten Hinweis, ich schaue mir das später am Nachmittag an 
und gebe dann Rückmeldung. Das hört sich nämlich wirklich nach einer 
vielversprechenden Spur an.

von Forist (Gast)


Lesenswert?

Arlenne schrieb:
> Die folgenden Timer-Interrupts funktionieren dann alle, das ist hier
> aber nicht gezeigt. Der Beitrag ist auch so schon lang genug...

Richtig - deshalb gibt es hier die Möglichkeit, Quellcode als 
Dateianhang hochzuladen.

von Arlenne (Gast)


Lesenswert?

Die Funktion enterSleep() habe ich jetzt um einige Debug-Ausgaben 
ergänzt, insbesondere die Timer-Register:
1
void enterSleep(wakeupSources source, unsigned int timeout_sec)
2
{
3
    Serial.print("\r\nenter sleep, wait for ");
4
    if (source == EXTERNAL_INTERRUPT)
5
    {
6
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
7
        Serial.print("EXT INT... ");
8
9
        buttonPress = false;
10
    }
11
    else if (source == TIMEOUT_INTERRUPT)
12
    {
13
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
14
        Serial.print("TMR INT... ");
15
16
        // Setup TMR2: interrupt every 25ms
17
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
18
        TCCR2B = 0;                                                             // set TCCRXB register to 0
19
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
20
        OCR2A = 194;                                                            // set compare match register of timer 2
21
        TCNT2 = 0;
22
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
23
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt
24
25
        timeoutSeconds = timeout_sec;
26
        timeoutFlag = false;
27
    }
28
    Serial.print("SMCR= 0b"); Serial.print(SMCR, BIN);                          // DEBUG
29
    if ((SMCR&(1<<SM1)) && !(SMCR&(1<<SM0))) Serial.println(" (power down)");     // DEBUG
30
    if ((SMCR&(1<<SM1)) && (SMCR&(1<<SM0)))  Serial.println(" (power save)");     // DEBUG
31
    Serial.print("TCCR2A= 0b"); Serial.println(TCCR2A, BIN);                          // DEBUG
32
    Serial.print("TCCR2B= 0b"); Serial.println(TCCR2B, BIN);                          // DEBUG
33
    Serial.print("TIMSK2= 0b"); Serial.println(TIMSK2, BIN);                          // DEBUG
34
    Serial.print("OCR2A= "); Serial.println(OCR2A);                          // DEBUG
35
    Serial.print("TCNT2= "); Serial.println(TCNT2);                          // DEBUG
36
    Serial.flush();
37
38
    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts
39
40
    sleep_bod_disable();
41
    do                                                                          // loops when timer interrupts
42
    {
43
        buttonInt = false;                                                      // DEBUG
44
        timerInt = false;                                                       // DEBUG
45
        cli();
46
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
47
        sleep_enable();
48
        sei();
49
        sleep_cpu();
50
        sleep_disable();
51
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
52
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(".");  // DEBUG
53
        Serial.flush();
54
    }
55
    while ( (buttonPress == false) && (timeoutFlag == false));
56
57
    Serial.println("-Wakeup");
58
    Serial.flush();
59
60
    return;
61
}

Damit sieht die Ausgabe wie folgt aus:
1
14:28:06.860 -> Hello!
2
14:28:06.860 -> 
3
14:28:06.860 -> enter sleep, wait for TMR INT... SMCR= 0b110 (power save)
4
14:28:06.860 -> TCCR2A= 0b11
5
14:28:06.860 -> TCCR2B= 0b111
6
14:28:06.860 -> TIMSK2= 0b10
7
14:28:06.860 -> OCR2A= 194
8
14:28:06.860 -> TCNT2= 43
9
14:28:06.907 -> -Wakeup
10
14:28:06.907 -> End of setup()
11
14:28:06.907 -> 
12
14:28:06.907 -> enter sleep, wait for EXT INT... SMCR= 0b100 (power down)
13
14:28:06.907 -> TCCR2A= 0b11
14
14:28:06.907 -> TCCR2B= 0b111
15
14:28:06.907 -> TIMSK2= 0b0
16
14:28:06.907 -> OCR2A= 194
17
14:28:06.907 -> TCNT2= 13
18
14:28:17.519 -> iB-Wakeup
19
14:28:17.519 -> button
20
14:28:17.720 -> 
21
14:28:17.720 -> enter sleep, wait for TMR INT... SMCR= 0b110 (power save)
22
14:28:17.720 -> TCCR2A= 0b11
23
14:28:17.720 -> TCCR2B= 0b111
24
14:28:17.720 -> TIMSK2= 0b0
25
14:28:17.720 -> OCR2A= 194
26
14:28:17.720 -> TCNT2= 36
27
14:28:23.490 -> iB-Wakeup
28
14:28:23.490 -> button
29
14:28:23.591 -> 
30
14:28:23.591 -> enter sleep, wait for TMR INT... SMCR= 0b110 (power save)
31
14:28:23.591 -> TCCR2A= 0b11
32
14:28:23.591 -> TCCR2B= 0b111
33
14:28:23.591 -> TIMSK2= 0b10
34
14:28:23.591 -> OCR2A= 194
35
14:28:23.591 -> TCNT2= 36
36
14:28:23.637 -> ............................................................-Wakeup
37
14:28:27.502 -> timeout

Im vorletzten Abschnitt haben wir den Fehler-Fall, dass der 
Timer-Interrupt zwar gesetzt, aber nicht ausgelöst wird. Im letzten 
Abschnitt klappt das dann wieder wie erwartet.
Der Unterschied ist, dass im Fehler-Fall das Timer-Interrupt Mask 
Register TIMSK2 = 0 ist, wenn es dann funktioniert ist in diesem 
Register das Bit OCIE2A gesetzt, wie es auch sein soll.

Nun die Frage, wie das sein kann! In beiden Fällen wird in der genannten 
Funktion das Timer 2 compare interrupt flag gesetzt:

*TIMSK2 |= (1 << OCIE2A);*

Einmal klappt das nicht, dann schon.

Ich hoffe, es hat jemand eine Idee, woran das liegt.

von Arlenne (Gast)


Lesenswert?

Und nochmal mit anderer Debug-Ausgabe, die sich jetzt auf das Register 
TIMSK2 bezieht:
1
void enterSleep(wakeupSources source, unsigned int timeout_sec)
2
{
3
    Serial.print("\r\nenter sleep, wait for ");
4
    if (source == EXTERNAL_INTERRUPT)
5
    {
6
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
7
        Serial.print("EXT INT... ");
8
        Serial.println();                                                       // DEBUG
9
        Serial.print("TIMSK2-A= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
10
        buttonPress = false;
11
    }
12
    else if (source == TIMEOUT_INTERRUPT)
13
    {
14
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
15
        Serial.print("TMR INT... ");
16
        Serial.println();                                                       // DEBUG
17
        Serial.print("TIMSK2-B= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
18
        // Setup TMR2: interrupt every 25ms
19
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
20
        TCCR2B = 0;                                                             // set TCCRXB register to 0
21
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
22
        OCR2A = 194;                                                            // set compare match register of timer 2
23
        TCNT2 = 0;
24
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
25
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt
26
        Serial.print("TIMSK2-C= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
27
        TIMSK2 |= (1 << OCIE2A);                                                // DEBUG
28
        Serial.print("TIMSK2-D= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
29
30
        timeoutSeconds = timeout_sec;
31
        timeoutFlag = false;
32
    }
33
    Serial.print("TIMSK2-E= 0b"); Serial.println(TIMSK2, BIN);                  // DEBUG
34
    Serial.flush();
35
36
    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts
37
38
    sleep_bod_disable();
39
    do                                                                          // loops when timer interrupts
40
    {
41
        buttonInt = false;                                                      // DEBUG
42
        timerInt = false;                                                       // DEBUG
43
        cli();
44
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
45
        sleep_enable();
46
        sei();
47
        sleep_cpu();
48
        sleep_disable();
49
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
50
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(":");  // DEBUG
51
        Serial.flush();
52
    }
53
    while ( (buttonPress == false) && (timeoutFlag == false));
54
55
    Serial.println("-Wakeup");
56
    Serial.flush();
57
58
    return;
59
}

Hier die Ausgabe dazu:
1
Hello!
2
3
enter sleep, wait for TMR INT... 
4
TIMSK2-B= 0b0
5
TIMSK2-C= 0b10
6
TIMSK2-D= 0b10
7
TIMSK2-E= 0b10
8
-Wakeup
9
End of setup()
10
11
enter sleep, wait for EXT INT... 
12
TIMSK2-A= 0b0
13
TIMSK2-E= 0b0
14
iB-Wakeup
15
button
16
17
enter sleep, wait for TMR INT... 
18
TIMSK2-B= 0b0
19
TIMSK2-C= 0b0
20
TIMSK2-D= 0b10
21
TIMSK2-E= 0b10
22
............................................................-Wakeup
23
timeout
24
25
enter sleep, wait for EXT INT... 
26
TIMSK2-A= 0b0
27
TIMSK2-E= 0b0

Da ist jetzt wieder der vorletzte Abschnitt interessant (vor der Zeile 
mit den .....):
Da wird also TIMSK2 beschrieben, das Ergebnis ist, dass es trotzdem noch 
0x00 ist (Ausgabe TIMSK2-C). Dann wird es gleich darauf nochmal 
beschrieben, jetzt erfolgreich (Ausgabe TIMSK2-D).

Dann muss die Frage jetzt also lauten, warum der Schreibzugriff auf 
dieses Register nicht in jedem Fall funktioniert.

Ich bin ratlos...

von S. Landolt (Gast)


Lesenswert?

> ... TIMSK2 ... dass es trotzdem noch 0x00 ist ...
Wohl eher 'wieder' - dazwischen erfolgt ja eine (längere) serielle 
Ausgabe. Vielleicht mal in cli /sei/ kapseln.

von Arlenne (Gast)


Lesenswert?

Danke für den Tipp, habe das gleich probiert und die erste Zuweisung, 
die ja schief geht, in cli() und sei() eingebettet.
Am Ergebnis ändert sich leider nichts, die Zuweisung ist nicht 
erfolgreich, die Ausgabe die gleiche wie zuvor.

von S. Landolt (Gast)


Lesenswert?

> die erste Zuweisung, die ja schief geht, in cli() und sei() eingebettet
?
Die Zuweisung geht doch nicht schief - die serielle Ausgabe sollte 
eingebettet werden.

von Arlenne (Gast)


Lesenswert?

Das verstehe ich jetzt aber nicht:
TIMSK2 wird beschrieben und dann im Zug der seriellen Ausgabe zurück 
gelesen.
Warum sollte das Serial.print() einen falschen Wert ausgeben?

Aber natürlich probiere ich das gleich noch aus.

von Axel R. (axlr)


Lesenswert?

lass dir doch mal das assembler-Listing ausgeben...

von Arlenne (Gast)


Lesenswert?

Das mit dem Assembler-Listung muss ich erst noch sehen, wo ich das 
finde...

Aber das cli() und sei() habe ich ausgedehnt auf das Serial.print() UND 
den zweiten Schreibzugriff auskommentiert:
1
    else if (source == TIMEOUT_INTERRUPT)
2
    {
3
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
4
        Serial.print("TMR INT... ");
5
        Serial.println();                                                       // DEBUG
6
        Serial.print("TIMSK2-B= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
7
        // Setup TMR2: interrupt every 25ms
8
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
9
        TCCR2B = 0;                                                             // set TCCRXB register to 0
10
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
11
        OCR2A = 194;                                                            // set compare match register of timer 2
12
        TCNT2 = 0;
13
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
14
        cli();
15
        TIMSK2 |= (1 << OCIE2A);
16
        Serial.print("TIMSK2-C= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
17
        sei();
18
//        TIMSK2 |= (1 << OCIE2A);                                                // DEBUG
19
//        Serial.print("TIMSK2-D= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
20
21
        timeoutSeconds = timeout_sec;
22
        timeoutFlag = false;
23
    }
24
    Serial.print("TIMSK2-E= 0b"); Serial.println(TIMSK2, BIN);                  // DEBUG
25
    Serial.flush();

Die Ausgabe ist sehr interessant:
1
enter sleep, wait for TMR INT... 
2
TIMSK2-B= 0b0
3
TIMSK2-C= 0b10
4
TIMSK2-E= 0b0

Demnach ist das Schreiben des Registers tatsächlich erfolgreich (Ausgabe 
TIMSK2-C), das zweite Schreiben entfällt, und am Ende ist das Register 
doch wieder 0x00 und kein Interrupt wird ausgelöst.

Wer oder was setzt dieses Register zurück?

von S. Landolt (Gast)


Lesenswert?

> Wer oder was setzt dieses Register zurück?
Na - eine Interrupt-Routine natürlich.
  Aber mich in diese Interrupt-Struktur mal so eben nebenher 
einzuarbeiten, das schaffe ich nicht; da fehlt mir die Zeit.

von S. Landolt (Gast)


Lesenswert?

Es gibt ja nur eine Programmstelle mit 'TIMSK2 = 0;', nämlich in 
ISR(TIMER2_COMPA_vect), wenn ich das richtig sehe - also ...

von Arlenne (Gast)


Lesenswert?

Das ist wirklich ein guter Hinweis, ganz vielen Dank dafür!
Werde da weiter suchen und wenn ich die Lösung gefunden habe, teile ich 
das hier mit.

von Arlenne (Gast)


Lesenswert?

Das Problem scheint tatsächlich zu sein, dass ein Timer-Interrupt 
auftritt und das Enable-Flag gelöscht wird, bevor der Controller in den 
Sleep-Mode geht.

Die Lösung:
Der Timer muss initialisiert werden, wenn alle Interrupts abgeschaltet 
sind. Außerdem muss das Timer-Interrupt-Flag gelöscht werden:
1
        cli();
2
        TCCR2B = 0;                                                             // stop the timer and reset WGM22
3
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode with top in OCR2A
4
        OCR2A = 194;                                                            // set compare match register of timer 2
5
        TCNT2 = 0;                                                              // initialize counter value to 0
6
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
7
        TIFR2 |= (1 << OCF2A);
8
        TIMSK2 |= (1 << OCIE2A);
9
        sei();

Damit läuft das dann endlich und der Timer-Interrupt wird zuverlässig 
ausgeführt!

Vielen Dank für alle Tipps, die mich in die richtige Richtung geführt 
haben!

LG Arlenne

von c-hater (Gast)


Lesenswert?

Arlenne schrieb:

> Dann muss die Frage jetzt also lauten, warum der Schreibzugriff auf
> dieses Register nicht in jedem Fall funktioniert.
>
> Ich bin ratlos...

Wärest du nicht, wenn du anfangen würdest, Datenblätter zu lesen, statt 
mit Arduino zu spielen...

Der Timer2 wird doch sehr wahrscheinlich im asynchronen Modus betrieben 
(um als RTC zu dienen und/oder um das Teil aus dem Tiefschlaf wecken zu 
können).
Im asnchronen Modus ist es mit dem Schreiben eines SFIO-Registers nicht 
getan. Man muss warten, bis dieser Schreibvorgang bei der asynchronen 
Zielperipherie auch angekommen ist.

Das kann durchaus recht lange dauern. Das hängt nämlich vom Takt in 
deren Taktdomain ab, bei Timer2 typisch halt nur 32kHz.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.