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; }
Was generiert denn den interrupt? Kommt er vielleicht mehrmals? So wie deine isr gebaut ist, siehst du den unterschied nicht.
Normalerweise werden keine Pausen in Interrupt-Routinen eingesetzt. https://www.mikrocontroller.net/articles/Interrupt Dort steht: Im Mittel muss die Interruptroutine kürzer sein als die Periodendauer des Ereignisses, andernfalls wird es passieren, dass Interrupts "verschluckt" werden.
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.
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.
@ 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
Eventuell musst du Interrupts am Anfang der Interrupt Routine Deaktivieren und am Ende wieder Aktivieren. Sonst würde die Routine mehrmals rekursiv ausgeführt. Ist jetzt allerdings nur mal ins Blaue geraten.
:
Bearbeitet durch User
@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?
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.
Es wird langsam Zeit für RTFM, auch Datenblatt genannt. Wenns angelsächsische Probleme bereitet, hilft auch das Tutorial und die Artikel hier auf mikrocomtroller.net, zu finden über die Links links oben. Oliver
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?
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); }
Mit "EIFR |= (1 << INTF0);" funktioniert`s perfekt und blinkt zweimal. Vielen Dank Euch Allen und schönen Abend noch! Leo
Mit
1 | EICRA |= (1 << ISC00); |
brauchst Du dich über mindestens 2 Interrupts nicht wundern, selbst wenn Du einen idealen nicht prellenden Taster hättest.
Ja das stimmt, mit "EICRA |= (1 << ISC01);" funktionierts deutlich besser
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
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
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."
Dieter schrieb: > Arbeite doch mit Cli() und Sei(), damit der Interrupt sich nicht selber > unterbricht. Das macht er auf einem AVR grundsätzlich nicht. Spieleirein mit cli()/sei() in einer ISR sind daher sinnlos, und kann unschöne Nebenwirkungen haben. Oliver
Dieter schrieb: > Arbeite doch mit Cli() und Sei(), damit der Interrupt sich nicht selber > unterbricht. Das hat aber genau den gegenteiligen Effekt. Es sorgt dafür, dass der Interrupt sich selbst unterbricht.
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 ;-)
Nu ja, wenn der TO sich jetzt duch das Thema durchbeisst, und versteht, was da eigentlich passiert, dann ist das doch ok. Eine bessere Trainingseinheit zum Thema ISR auf dem AVR gibt es nicht, danach hat der das abgehakt. Oliver
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.
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!
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.