Hallo zusammen, ich habe folgendes Problem. Ich möchte über einen PCF8574 Tasten einlesen. Damit dies interruptgesteuert ist, habe ich den Portexpander an INT0 angeschlossen. Jetzt habe ich aber das Problem, das der externe Interrupt 0 Mal ausgelöst wird. Hier die Konfiguration der Interrupts EIMSK|=1<<INT1|1<<INT0; EICRA|=1<<ISC11|1<<ISC01; sei(); sowie die zunächst ganz banale ISR ISR(INT0_vect){ _delay_ms(500); i++; _delay_ms(500); } Ziel war es den Interrupt auf fallende Flanke zu konfigurieren, sodass Jede zustandsänderung a, PCF8574 genau einen Interrupt auslöst Übersehe ich dabei irgendetwas? Liebe Grüße und schönen Tag M²H
M²H schrieb: > Hier die Konfiguration der Interrupts > > EIMSK|=1<<INT1|1<<INT0; > EICRA|=1<<ISC11|1<<ISC01; > sei(); > > sowie die zunächst ganz banale ISR > > ISR(INT0_vect){ > _delay_ms(500); > i++; > _delay_ms(500); > } > Übersehe ich dabei irgendetwas? Ja. Wenn du zwei Interrupts erlaubst, brauchst du auch Handler für zwei Interrupts...
Mit dem Codesschnipsel kann man nix anfangen. 1 Sekunde delay in einer ISR macht man nicht. Der µC macht in der Zeit überhaupt nix mehr. ISR sollten immer kurz und schnell abgearbeitet werden.
M²H schrieb: > Übersehe ich dabei irgendetwas? Wo hängt der INT1 Pin? Wenn er ein "floating input" ist und du keinen Handler für INT1 hast, kann nur schief gehen. Schalte INT1 ab, am INT0 mit Oszilloskop messen ob Signal vorhanden.
Erstmal danke für alle Antworten :) @ Chris Mir ist klar das dieses delay sehr lang ist ich hab das "Entprellung" verwendet, mir ist durchaus klar, dass das in der Länge eigentlich nicht notwendig wäre. Es stört aber meines WIssens an der Stelle aber auch erstmal nicht. @Ozvald Der INT1 ist ebenfalls über einen 10K Widerstand an 5V und wird über einen Taster nach Masse gezogen. Der Pin ist also nicht floating und ich bekomme für diesen auch nur Interrupts wenn ich den Taster drücke. allerdings mit dem selben Effekt, dass ich die ISR für INT1 zweimal ausführe. Ich hab den Effekt auf INT0 auch wenn ich den INT1 in EIMSK nicht freigebe.
M²H schrieb: > Es stört aber meines WIssens an der Stelle aber auch > erstmal nicht. Problem: Der Delay verhindert nicht, dass ein zweiter Interrupt "getriggert" wird. d.H. wenn während des _delay_ms in der ISR eine neue Flanke kommt, dann wird das Interrupt-Request-Bit (in EIFR) auch wieder neu gesetzt. Nach dem Return aus dem Interrupt steht also sofort der nächste an => CPU führt einen "normalen" Befehl aus, und springt sofort wieder in die ISR.
> Interrupt 0 Mal ausgelöst > selben Effekt, dass ich die ISR für INT1 zweimal Also für mich passen die beiden Aussagen nicht zusammen, was übersehe ich? Und Letztere klingt nach Tasterprellen.
M²H schrieb: > @ Chris > Mir ist klar das dieses delay sehr lang ist ich hab das "Entprellung" > verwendet, mir ist durchaus klar, dass das in der Länge eigentlich nicht > notwendig wäre. Es stört aber meines WIssens an der Stelle aber auch > erstmal nicht. An diesem Ort kann das nicht funktionieren! Εrnst B. schrieb: > Problem: Der Delay verhindert nicht, dass ein zweiter Interrupt > "getriggert" wird. > d.H. wenn während des _delay_ms in der ISR eine neue Flanke kommt, dann > wird das Interrupt-Request-Bit (in EIFR) auch wieder neu gesetzt Du brauchst einen Timer, der in der ISR gestartet wird. Der ISR BLEIBT gesperrt! Außerhalb der ISR, wird durch den Timer dieser erst wieder freigegeben, nachdem das zugehörige Flag gelöscht wurde.
Εrnst B. schrieb: > M²H schrieb: >> Es stört aber meines WIssens an der Stelle aber auch >> erstmal nicht. > > Problem: Der Delay verhindert nicht, dass ein zweiter Interrupt > "getriggert" wird. > d.H. wenn während des _delay_ms in der ISR eine neue Flanke kommt, dann > wird das Interrupt-Request-Bit (in EIFR) auch wieder neu gesetzt. Nach > dem Return aus dem Interrupt steht also sofort der nächste an => CPU > führt einen "normalen" Befehl aus, und springt sofort wieder in die ISR. Danke Ernst für deine Antwort. Das klingt schlüssig. Frage wie verhindere ich das Triggern des zweiten Interrupts softwaremäßig? wäre folgendes in der ISR denkbar? ISR(INT1_vect){ EIMSK&=~(1<<INT1);// Sperren des Interrupts _delay_ms(20); EIFR|=1<<INTF1;// löschen des zugehörigen Flags(laut Datenblatt durch setzen) nach delay falls prellen vorhanden EIMSK|=1<<INT1;//Wiederfreigabe des Interrupt ... ... // gewünschter Code für die ISR ... ... }
Beitrag #6134004 wurde von einem Moderator gelöscht.
M²H schrieb: > allerdings mit dem selben Effekt, dass ich die ISR für INT1 zweimal > ausführe. Klar, der Taster prellt. Die erste negative Flanke löst den Interrupt aus. Während der µC den Interrupt abarbeitet (delay), setzen weitere negative Flanken das Interruptflag wieder. Taster abfragen macht man besser mit Polling oder du musst mit Hardware den Taster entprellen lassen.
M²H schrieb: > Das klingt schlüssig. Frage wie verhindere ich das Triggern des zweiten > Interrupts softwaremäßig? in dem man das ganze so anlegt, dass das Problem garnicht erst auftaucht. es gibt kaum Anwendungen, wo du einen Tastendruck auf die millisekunde genau brauchst. Deshalb fragt man Tasten normalerweise auch nicht mit einem Interrupt-Pin ab. Besser: Timer/Task in der main-loop, das ganze in die PeDa-Entprellung füttern. Interrupt für Tasten hab ich normalerweise nur zum Wake-Up aus dem sleep. Dann ist die ISR leer (oder schaltet sich direkt selber ab)
1 | EMPTY_INTERRUPT(INT0_vect); |
2 | // Oder
|
3 | ISR(INT0_vect) { |
4 | GIMSK &= ~_BV(INT0); |
5 | }
|
und der trigger steht auf LEVEL. Abfrage in der Timer-ISR ist bei Tasten über I2C-Portexpander natürlich etwas blöde, je nachdem was sonst noch am I²C hängt. Da würde ich das auslesen/entprellen in die main-loop packen, und mit dem Timer nur eine Zeitbasis dafür bereitstellen.
M²H schrieb: > Das klingt schlüssig. Frage wie verhindere ich das Triggern des zweiten > Interrupts softwaremäßig? > wäre folgendes in der ISR denkbar? > > ISR(INT1_vect){ > EIMSK&=~(1<<INT1);// Sperren des Interrupts > _delay_ms(20); > EIFR|=1<<INTF1;// löschen des zugehörigen Flags(laut Datenblatt durch > setzen) nach delay falls prellen vorhanden > EIMSK|=1<<INT1;//Wiederfreigabe des Interrupt > ... > ... > // gewünschter Code für die ISR > ... > ... > } Nein, das hilft garnix. Erstens: Das Löschen des Bits in der Interruptmaske verhindert NICHT, dass das zugehörige Interuptflag gesetzt wird. Es kann nur verhindern, dass der Interrupt auch tatsächlich ausgelöst wird. Das würde aber frühestens nach Ende deiner ISR passieren. Jedenfalls so lange du nicht anfängst, in der ISR auch noch mit sei() zu hantieren, wovon man dir bei deinem Kenntnisstand nur sehr dringend abraten könnte... Aber nicht einmal diesen Job kann die Maske erledigen, weil du ja noch in der ISR das Bit wieder setzt. Sprich: de facto völlig sinnlose Operationen, sowohl das Löschen als auch das Setzen. Bewirkt garnix. Zweitens: Wenn während der sehr länglichen Laufzeit von "// gewünschter Code für die ISR" der Interrupt erneut erfolgt (was genau dein Problem ist), dann kehrt deine ISR zurück, es wird genau eine Instruktion aus main() ausgeführt und dann bist du wieder in deiner ISR. Vielleicht lernst du erstmal, wie diese Interrupts überhaupt funktionieren, bevor du sie benutzt? Weil: es fällt dann viel leichter, sinnvollen Code zu schreiben...
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.