Forum: Mikrocontroller und Digitale Elektronik Probleme mit externen Interrupts am ATmega328P


von M²H (Gast)


Lesenswert?

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

von c-hater (Gast)


Lesenswert?

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...

von Chris (Gast)


Lesenswert?

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.

von Ozvald K. (Gast)


Lesenswert?

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.

von M²H (Gast)


Lesenswert?

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.

von Εrnst B. (ernst)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> 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.

von Teo D. (teoderix)


Lesenswert?

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.

von M²H (Gast)


Lesenswert?

Ε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.
von Ozvald K. (Gast)


Lesenswert?

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.

von Εrnst B. (ernst)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.