_delay_ms() innerhalb einer ISR

Gast #4622295
Lesenswert?

Hallo,

ich hätte eine Frage zum Thema Interrupts. Wenn ich folgendes Programm 
auf meinem Atmega168 ausführe, leuchtet die Lampe an PB0 für 5 Sekunden 
anstatt 2.5. Mit der CPU Frequenz hat es wohl nichts zu tun, denn wenn 
ich _delay_ms() in der main() Methode verwende funktioniert das Timing 
einwandfrei.

Kann mir das Phänomen nicht wirklich erklären und hoffe daher auf Eure 
Erklärungen.

Grüße!
Leo

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>


void setupInterrupt(void) {
  PORTD |= (1 << PD2);
  EIMSK |= (1 << INT0);
  EICRA |= (1 << ISC00);
     sei();
}

ISR (INT0_vect) {
  PORTB |= (1 << PB0);
  _delay_ms(2500);
  PORTB &= ~(1 << PB0);
}


int main(void) {

  DDRB |= (1 << PB0);
  setupInterrupt();
  while(1) {
  }

return 0;
}
Gast #4622312
Lesenswert?

Der Interrupt wird durch einen Taster generiert. Es stimmt schon dass 
solche Taster öfter zweimal schalten wenn sie nur einmal sollten. Das 
müsste aber hier egal sein oder? Wenn ich den Taster bewusst 3 mal 
drücke läuft die Routine ja auch nur 5 Sekunden.

Naja, das Problem liegt ja nicht darin dass der Interrupt verschluckt 
wird, sondern zu lange dauert. Auslösen tut er ja immer.
#4622318
Lesenswert?

Leo schrieb:
> Der Interrupt wird durch einen Taster generiert. Es stimmt schon
> dass
> solche Taster öfter zweimal schalten wenn sie nur einmal sollten. Das
> müsste aber hier egal sein oder?

Ist es aber nicht.


> Wenn ich den Taster bewusst 3 mal
> drücke läuft die Routine ja auch nur 5 Sekunden.

Weil halt neben der schon laufenden ISR das Flag nur einmal gesetzt 
wird. De dritte Tastendruck ändert daran nichts mehr.

Oliver
Gast #4622328
Lesenswert?

Leo schrieb:
> Der Interrupt wird durch einen Taster generiert.

Seufz. War ja klar.

Man kann hier im Forum millionenmal erklären, dass man Taster nicht mit 
Interrupts auswertet. Das hat nur zur Folge, das der 
Eine-Million-und-Einte kommt und es versucht.

Ebenso oft kann man hier erklären, dass man delays nicht in Interrupts 
verwendet. Das hilft nix. Es wird wieder einer geboren, der das 
versucht.
Gast #4622340
Lesenswert?

Leo schrieb:
> @ wolfgang: dann müsste der Interrupt immer sofort nach der ISR ein
> zweites mal ausgelöst werden. Und das auch jedes mal nur einmal, nie
> zweimal oder öfter. Ist eher unwahrscheinlich oder?

Warum soll das unwahrscheinlich sein. Dein Taster wird doch nur beim 
Drücken kurz (einige Millisekunden) rumprellen und nicht die ganzen 
2.5s.

Hast du dir dein Ausgangssignal jetzt mal genau angesehen, ob es (je 
nach CPU Frequenz) mal kurz für irgendetwas im Mikrosekundenbereich 
unterbrochen ist?
Gast #4622402
Lesenswert?

Hab die ISR mal folgendermaßen umgeschrieben und es blinkt viermal. => 
Die flag wird gleich während die ISR läuft wieder gesetzt.

Hätte jetzt mit Hilfe von Google und Datenblat folgende Zeile eingefügt:
PCIFR |= (1 << PCIF1);
Es blinkt aber trotzdem viermal.


ISR (INT0_vect) {
  PORTB |= (1 << PB0);
  _delay_ms(1000);
  PORTB &= ~(1 << PB0);
  _delay_ms(1000);
  PORTB |= (1 << PB0);
  _delay_ms(1000);
  PORTB &= ~(1 << PB0);
  _delay_ms(1000);
  PCIFR |= (1 << PCIF1);
}
Gast #4622728
Lesenswert?

Hallo Leo,

du hast aber nach wie vor das Problem das du die Ausführung deines 
Progammes mit einer Warteschleife in der ISR blockierst.

Versuche mal das Ganze mit einem Timer zu realisieren.

ISR...

IF Timer abgelaufen
  Lade Timer mit Teiler
  starte Timer
END

IRET

Es ist dann egal wie oft der Knopf während der Laufzeit betätigt wird.

Gruß

Roman
Gast #4623130
Lesenswert?

Und dabei ist die Lösung so einfach:
Wir "pollen" die Taste z.B. im 20ms - Raster.

Timer mit ISR aufsetzen, da drin nachschauen ob sich der Eingang 
geändert hat, fallweise ein Flag setzen. Dauert wenige Taktzyklen.

Die Flags schaut man sich z.B. in der main an, und ruft die zugehörige 
Funktion auf, wenn eins davon schreit.

Zusatznutzen : Reagiert werden kann asynchron im Resteittask. Eine 
Reaktion nach 200ms empfindet man als Mensch immer noch als wirklich 
rasant, ist für den µC aber eine halbe Ewigkeit, in der man 
zeitkritischeres tun kann.

Alternative:
Hardware. Siehe vielzitierter Artikel.

Delay() + ISR = epic fail ;-)
#4623437
Lesenswert?

Dieter schrieb:
> Hey,
>
> Arbeite doch mit Cli() und Sei(), damit der Interrupt sich nicht selber
> unterbricht. Damit solltest du dafür sorgen, dass der Interupt einmal
> ausgeführt wird und die Lampe 2,5s leuchtet
>
> Gruß
> Dieter

Die ISR läuft schon mit gesperrten Interrupts, das ist bei AVR 
grundsätzlich so und wenn anders gewünscht müssen Int's explizit 
freigegeben werden.

Was passiert wirklich:
- Tastendruck löst Int aus
- ISR läuft 2,5 Sekunden mit gesperrten Int's
- Taste prellt ca 2ms, d.h. es steht ein neuer Interruptrequest an der
- sobald die ISR fertig ist, diese gleich nochmal ruft
- wieder 2,5 Sekunden warten, also in Summe 5 Sekunden
- das Prellen der Taste ist innerhalb der ersten 2,5 Sekunden natürlich 
vorbei, d.h.
- es laufen immer exakt 2 ISR in Folge

Was insgesamt zu diesen Programm-Design zu sagen ist, wurde schon 
gesagt.
Gast #4623455
Lesenswert?

Das Problem erinnert mich an das Auto, das einen Unfall hatte und, beim 
Transport zur Werkstatt vom Abschleppwagen, gefallen ist.

Eine Verzögerung, von der verwendeten Länge, in einer Unterbrechung ist 
ein Unding.
Das erzwingt ja praktisch die Unterbrechung der Unterbrechung.
Wird diese dann noch mit Tastern ausgelöst, ist die Kacke erst richtig 
am Dampfen.
Lustig wird es aber auch, weil delay () selber unterbrochen wird und 
werden darf.

Ich habe das Gefühl, dass hier über eine Krücke diskutiert wird, obwohl 
es schon lange Zeit ist, das Bein zu behandeln. Sprich: Ab in die Tonne!
#4624452
Lesenswert?

Dieter schrieb:
> Arbeite doch mit Cli() und Sei(), damit der Interrupt sich nicht selber
> unterbricht.

Das ist Quatsch mit Soße.
Mir ist keine CPU-Architektur bekannt, die beim Eintritt in den Handler 
nicht automatisch Interrupts gleicher Priorität sperrt.
Eine CPU, die das nicht macht, wäre schlichtweg unbrauchbar, der Stack 
würde rasch überlaufen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren