Go Down

Topic: Interrupt Service Routine pausieren sei(); cli(); (Read 3976 times) previous topic - next topic

Poldi

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();
}

bohne

#1
Mar 12, 2009, 04:03 pm Last Edit: Mar 12, 2009, 04:06 pm by bohne Reason: 1
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:

Code: [Select]

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
Code: [Select]

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...
http://www.dorkbot.de
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236434254
http://www.luminet.cc

Poldi

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

Lieben Gruß
Poldi

Poldi

Hey "bohne"! Da bin ich wieder ;-)

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

Lieben Gruß
Poldi

bohne

Klasse!

Und was wird Dein Programm machen wenn es fertig ist? Oder war das ein Experiment, um die Timer besser zu verstehen?
http://www.dorkbot.de
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236434254
http://www.luminet.cc

Poldi

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 ;-)

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 :D

Lieben Gruß
Poldi

Go Up