Interrupt Service Routine pausieren sei(); cli();

Hallo zusammen.

Kann mir vielleicht jemand bei folgendem Problem weiterhelfen? Ich habe eine Interrupt-Service-Routine (ISR) programmiert welche ich unter bestimmten Bedingungen mit den Befehlen sei(); und cli(); starten /anhalten möchte. Anschließend soll sie wie zuvor weiterarbeiten (jede Sekunde Werte ändern). Anhalten mit cli(); funktioniert. Der Befehl sei(); startet die ISR aber nicht wieder!?

Ausschnitte aus meinem Programm mit Teilen aus dem Internet:

int Counter = 0; //Variable für Interrupt-Counter-Overflow
//------------------------------------------------------------
// Interrupt-Service-Routine
// Aruino runs at 16 Mhz, so we have 1000 Overflows per second...
// 1/ ((16000000 / 64) / 256) = 1 / 1000
ISR(TIMER2_OVF_vect) {
TCNT2 = 6; //Timer Reset
Counter += 1;
if (Counter == 1000) {
Counter = 0;
Sekunde +=1;
}
};

void setup() {
//Timer2 Settings: Timer Prescaler /64,
TCCR2B |= (1<<CS22);
TCCR2B &= ~((1<<CS21) | (1<<CS20));
// Use normal mode
TCCR2A &= ~((1<<WGM21) | (1<<WGM20)); // turn off WGM21 and WGM20 bits
TCCR2B &= ~(1<<WGM22); // turn off WGM22
// Use internal clock - external clock not used in Arduino
ASSR |= (0<<AS2);
//Timer2 Overflow Interrupt Enable
TIMSK2 |= (1<<TOIE2) | (0<<OCIE2A);
TCNT2 = 6; //Timer Reset
sei();
}

Damit läuft die ISR erst einmal. Das klappt auch alles ganz gut. Aber wenn ich mit folgender Abfrage in eine Unterroutine springe und die ISR anhalte bekomme ich sie nicht wieder zum Laufen. Das Programm friert einfach ein:

if (Taster_X == HIGH) { ISR_anhalten (); }

void ISR_anhaltenn () {
cli();
Serial.println("ISR angehalten");
Register_setzen ();
delay(1000);
sei();
}

mit cli() hälst Du alle Interrupts an.
Somit läuft auch die delay() Funktion nicht mehr, da diese einen Hardwaretimer benutzt...
Ausserdem wird auch die serielle Kommunikation nicht mehr klappen, da der UART nicht mehr senden wird, oder klappt das bei Dir noch?

grundsätzlich macht man das ISR_anhalten so:

void ISR_anhaltenn () {
 uint8_t sreg = SREG;
 cli();
//irgendwas machen

 SREG = sreg;
}

Interrupts sind ein sehr komplexes Thema, ich empfehle dazu, das Datenblatt vom ATMega168 ausführlich zu studieren.

Am sinnvollsten wäre es, nur den Timer zu stoppen und dann wieder neu zu starten, also stoppen mit

TCCR2B &= ~(1 << CS22);

in Deinem Fall. Und starten so wie Du es in setup() machst.
Also nicht cli() und sei() benutzen, sondern nur den Timer stoppen und neu starten...

Vielen Dank für die schnelle Antwort! Ich werde dies gleich morgen mal ausprobieren und die Befehle gleichzeitig im Datenblatt ansehen :wink:

Lieben Gruß
Poldi

Hey "bohne"! Da bin ich wieder :wink:

Hat alles super geklappt. Bin total happy! Vielen Dank nochmal!

Lieben Gruß
Poldi

Klasse!

Und was wird Dein Programm machen wenn es fertig ist? Oder war das ein Experiment, um die Timer besser zu verstehen?

Das Programm ist eine Digitaluhr realisiert mit LEDs an Schieberegistern!

Sie lief auch schon klasse und zieht viele neugierige Blicke auf sich. Es hatte mich nur genervt das die ISR das Einsstellen der Uhrzeit immer unterbrochen hat :wink:

Nun habe ich einen Taster "Zeit" hinzugefügt. Solange er gedrückt ist ruht die ISR und ich kann die Register füllen wie ich mag :smiley:

Lieben Gruß
Poldi