_delay_ms() innerhalb einer ISR

Gast #4622295
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
Leo schrieb:
> Wenn ich folgendes Programm auf meinem Atmega168 ausführe, leuchtet die
> Lampe an PB0 für 5 Sekunden anstatt 2.5.

Wie hast du das festgestellt? Bist du sicher, dass sie nicht zwei mal 
für 2.5s leuchtet? Ein Unterbrechung im Mikrosekundenbereich siehst dú 
nicht ohne sauberen Trigger und ausreichend hohe Abtastrate.
Gast
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.
Gast
@ 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?
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
@oilver: ja das klingt plausibel! Wenn ich während die ISR läuft den 
Flag "händisch" überschreiben würde dann sollte es funktionieren oder?

Kann man auf den Flag irgendwie zugreifen, beim Atmega168?
Gast
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
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
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
Mit
1
EICRA |= (1 << ISC00);
brauchst Du dich über mindestens 2 Interrupts nicht wundern, selbst wenn 
Du einen idealen nicht prellenden Taster hättest.
Gast
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
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
Gast
Tastaturabfrage per Interrupt.
Delays in der ISR.

Die zwei Kardinalfehler in der Microcontroller-Programmierung in einem 
Programm vereint. Wie war noch mal der Spruch? "Jeden Morgen steht ein 
Dummer auf."
Gast
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 ;-)
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
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!
Gast
Vielen Dank nochmal für die Tips und Erklärungen!

Für die Skeptiker sei noch erwähnt, dass es hier weniger darum ging eine 
echte Applikation zu entwickeln, sondern eher darum sich mit den 
Grundprinzipien auseinander zusetzen.

Schönen Tag noch!

Leo
Gast
Dann hoffe ich, dir ist dabei klar geworden, dass zu diesen 
Grundprinzipien auch gehört, dass man keine Delays in ISRs steckt und 
dass man Tasten entprellt.
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

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.