Forum: Mikrocontroller und Digitale Elektronik Erkennen, was den Interrupt ausgelöst hat.


von Sidey (Gast)


Lesenswert?

Hallo,

ich verwende einen Interrupt (INT_EXT_0) eines Arduino Nano.
Der hat einen ATMega 328.

Der Interrupt soll bei steigender und fallender Flanke auslösen.
Das klappt auch wunderbar.

Im ISR, benötige ich jedoch den Grund er Auslösung.
Ich frage bisher den Status vom Port ab, allerdings kann ich mir 
vorstellen, dass in einem Register hinterlegt ist, was den Interrupt 
ausgelöst hat. Also ob eine steigend oder fallende Flanke.

Im Datenblatt habe ich zum EXT_INT0 aber nichts gefunden und im Forum 
hier leider auch nicht.
Gibt es so ein Register?

Grüße Sidey

von STK500-Besitzer (Gast)


Lesenswert?

Wozu sollte es noch ein anderes Register geben, wenn man auch einfach 
den Portpin abfragen kann?

von Mobi (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> Wozu sollte es noch ein anderes Register geben...
Weil sicher der Status des Portpins zwischzeitlich geaendert haben kann.

von dunno.. (Gast)


Lesenswert?

Das Datenblatt gibt da nichts her..

Ich würde mal behaupten, dass es (so) nicht  geht.
Du hast momentan die einstellung auf 01, any logical change?
Dann kriegst du natürlich einen Interrupt bei jedem logical change..

Wenn dich wirklich die Art der Flanke interessiert, könntest du 
natürlich beide ExtInts mit der Quelle verbinden, einen auf rising, 
einen auf falling, und schon hast du die klare unterscheidung?

von Walter S. (avatar)


Lesenswert?

Mobi schrieb:
>> Wozu sollte es noch ein anderes Register geben...
> Weil sicher der Status des Portpins zwischzeitlich geaendert haben kann.

dann fragt man bzw. merkt sich den Zustand vorher, dann weiß man welche 
Flanke es gewesen sein muss

von 123 (Gast)


Lesenswert?

Walter S. schrieb:
> Mobi schrieb:
>>> Wozu sollte es noch ein anderes Register geben...
>> Weil sicher der Status des Portpins zwischzeitlich geaendert haben kann.
>
> dann fragt man bzw. merkt sich den Zustand vorher, dann weiß man welche
> Flanke es gewesen sein muss

Blödsinn.

Man muss eben das Interruptflag auswerten. Für Arduino Menschen geht das 
wie hier im Beispiel https://www.arduino.cc/en/Reference/attachInterrupt 
in der Funktion blink(). Diese ist die ISR für den gewählten Interrupt 
(CHANGE im Beispiel). Das ist genau was du brauchst.

von 123 (Gast)


Lesenswert?

Falls du wissen möchtest ob steigende oder fallende Flanke:
Zwei ISRs wie im oberen Beispiel. In der jeweiligen ISR änderst du eine 
Variable auf 1 oder 2 je nach Typ (fallend, steigen). In der loop() 
frägst du immer ab ob sie 0, 1 oder 2 ist. Wenn 1 oder der 2 entstanden 
rechend was passieren soll bei fallend oder steigend. Wenn du damit 
fertig bist, setzt du sie auf 0.

von 123 (Gast)


Lesenswert?

1
volatile char c_InterrType = 0;
2
3
void setup() {
4
    attachInterrupt(digitalPinToInterrupt(pin), risingISR, RISING);
5
    attachInterrupt(digitalPinToInterrupt(pin), fallingISR, FALLING);
6
}
7
8
void loop() {
9
    if(c_InterrType > 0){
10
     Switch(c_InterrType){
11
      Case 1: //irgendwas bei falling 
12
       Break;
13
      Case 2: //irgendwas bei rising 
14
       Break;
15
      }
16
    }
17
}
18
19
void fallingISR() {
20
    c_InterrType = 1;
21
}
22
23
void risingISR() {
24
    c_InterrType = 2;
25
}

von 123 (Gast)


Lesenswert?

Oh ich hab was vergessen:

In der loop() Nach dem Switch{} aber noch innerhalb dem if{} fehlt:
1
c_InterrType = 0;

von Karl H. (kbuchegg)


Lesenswert?

123 schrieb:
> Walter S. schrieb:
>> Mobi schrieb:
>>>> Wozu sollte es noch ein anderes Register geben...
>>> Weil sicher der Status des Portpins zwischzeitlich geaendert haben kann.
>>
>> dann fragt man bzw. merkt sich den Zustand vorher, dann weiß man welche
>> Flanke es gewesen sein muss
>
> Blödsinn.

Und das löst auf einem Mega328 das Problem wie genau?

Ist ja schön, dass das Arduino Framework die Portpin Auswertung für dich 
macht. Aber zaubern kann die auch nicht. Was der µC nicht hergibt, das 
gibt er nicht her. In diesem Fall eine Möglichkeit (ausser den Portpin 
abzufragen), welche Flanke es war.

von Walter S. (avatar)


Lesenswert?

123 schrieb:
> Blödsinn.
>
> Man muss eben das Interruptflag auswerten. Für Arduino Menschen geht das
> wie hier im Beispiel https://www.arduino.cc/en/Reference/attachInterrupt
> in der Funktion blink(). Diese ist die ISR für den gewählten Interrupt
> (CHANGE im Beispiel). Das ist genau was du brauchst.

123 schrieb:
> attachInterrupt(digitalPinToInterrupt(pin), risingISR, RISING);
>     attachInterrupt(digitalPinToInterrupt(pin), fallingISR, FALLING);

toll was der Arduino alles kann ...
falls du da wirklich beide Flanken getrennt zuordnen kannst dann schau 
doch bitte mal nach wie das in der Bibliothek gemacht wird, würde mich 
interessieren

von Dieter F. (Gast)


Lesenswert?

123 schrieb:
> attachInterrupt(digitalPinToInterrupt(pin), risingISR, RISING);
> attachInterrupt(digitalPinToInterrupt(pin), fallingISR, FALLING);

Schreiben kann man das - aktivieren wird man damit aber nur den 
Interrupt für die fallende Flanke (die letzte Einstellung zieht). Pro 
Pin kann man nur entweder oder bzw. generell Flankenwechsel einstellen. 
Kann man sogar im Datenblatt nachlesen.

Wenn der Flankenwechsel (deutlich) langsamer ist wie der ISR-Prolog + 
Abfrage des Port-Zustandes, dann kannst Du ja aus dem aktuellen Zustand 
in der ISR (bei Einstellung Interrupt bei jedem Flankenwechsel) auf den 
Flankenwechsel schließen. Wenn der Flankenwechsel schneller ist wie die 
Dauer der ISR insgesamt hast Du sowieso ein Problem ...

von Sidey (Gast)


Lesenswert?

Vielen Dank für die vielen Antworten.

Also, Flankenwechsel die unter 90 Mikrosekunden Abstand haben, sind für 
mich ohnehin nur Müll, wenn öfter welche reinkommen wird das bei mir 
ohnehin gefiltert.

Aktuell habe ich es wie empfohlen so gelöst, dass ich nach dem Auslösen 
des ISR den Pin Status abfrage und daraus schließe ob der port jetzt 
high oder low ist, was der Zustand zuvor war.

Allerdings bin ich mir nicht so sicher, ob der Zustand dauerhaft richtig 
erkannt wird. Ich hatte so einen Verdacht, dass das Abfragen des Port 
Zustandes vielleicht etwas langsam sein könnte und der ISR dann ggf. 
zwischenzeitlich noch mal auslöst.

(ich nutze die Arduino Funktionen um den pin abzufragen)

Das invertieren von State bei jedem ISR könnte ich auch machen.
Initial müsste ich dann nur den richtigen Zustand einmal abfragen (geht 
je vor Aktivieren des ISR) und anschließend hoffen, dass der ISR nicht 
öfter auslöst, als ich die Variable negieren kann.

Die Variante mit dem 2. ISR geht, aber den möchte ich ggf. noch mal für 
was anderes verwenden. Alternativ könnte ich ja auch jedes mal wenn der 
ISR ausgelöst wird, den trigger anpassen.

von Petra (Gast)


Lesenswert?

Und hardwaremäßig ein Flip Flop vor den INT setzen, das dann über einen 
Port resetiert wird?

von Ulrich F. (Gast)


Lesenswert?

Sidey schrieb:
> Ich hatte so einen Verdacht, dass das Abfragen des Port
> Zustandes vielleicht etwas langsam sein könnte und der ISR dann ggf.
> zwischenzeitlich noch mal auslöst.

Das passiert nur wenn du das explizit erlaubst.
Also eine unnütze Angst.

Sidey schrieb:
> (ich nutze die Arduino Funktionen um den pin abzufragen)
Das kannst du ändern.

von Thomas E. (thomase)


Lesenswert?

Karl H. schrieb:
> Was der µC nicht hergibt, das
> gibt er nicht her. In diesem Fall eine Möglichkeit (ausser den Portpin
> abzufragen), welche Flanke es war.

Ein Atmega8 gibt das natürlich nicht her. Aber ein 328er...

Wenn man den INT0 Sense auf Falling Edge stellt und diesen NICHT 
enabled, stattdessen aber den entsprechenden Pin-Change einschaltet, 
kann man durch Auswertung des INTF0 und ggf. des PCIF0 erkennen, ob der 
Pin-Change mit steigender oder fallender Flanke ausgelöst hat.

Wird er mit steigender Flanke ausgelöst, ist das INTF0 nicht gesetzt und 
die Abfrage des Flags ist eindeutig.

Wird mit fallender Flanke ausgelöst, ist INTF0 gesetzt, aber die Abfrage 
nicht eindeutig. Denn es könnte zwischen dem Auslösen des PCINT mit 
steigender Flanke und der Abfrage des INTF0 ein weiterer Flankenwechsel 
stattgefunden haben, der erst dann das INTF0 setzt. In diesem Fall ist 
aber auch das PCIF0 erneut gesetzt.

Somit kann aus einer Kombination der Abfrage beider Flags eindeutig 
bestimmt werden, welche Flanke den Interrupt zuerst ausgelöst hat und in 
welchem Status er sich bei der Abfrage befindet.

PCIF0 | INTF0 = 0 >> Rising Edge
PCIF0 | !INTF0 = 0 >> Falling Edge
PCIF0 & INTF0 = 1 >> Rising Edge, aber noch vor der Abfrage
                                 Wechsel auf Falling Edge

mfg.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Thomas E. schrieb:

> mfg.

clever!

von Thomas E. (thomase)


Lesenswert?

Thomas E. schrieb:
> PCIF0 & INTF0 = 1 >> Rising Edge, aber noch vor der Abfrage
>                                  Wechsel auf Falling Edge

Autsch:

Dieser Zustand ergibt sich auch bei Falling Edge und nachfolgendem 
Wechsel auf Rising. Hier muß zusätzlich die Portabfrage herhalten:

PCIF0 & INTF0 & !PIND2 = 1 >> Rising Edge, aber noch vor der Abfrage
                                           Wechsel auf Falling Edge


PCIF0 & INTF0 & PIND2 = 1 >> Falling Edge, aber noch vor der Abfrage
                                            Wechsel auf Rising Edge

mfg.

von Peter D. (peda)


Lesenswert?

Sidey schrieb:
> Also, Flankenwechsel die unter 90 Mikrosekunden Abstand haben, sind für
> mich ohnehin nur Müll,

Sidey schrieb:
> Allerdings bin ich mir nicht so sicher, ob der Zustand dauerhaft richtig
> erkannt wird.

90µs sind bei 8MHz Takt 720 CPU-Zyklen, da besteht keine Gefahr, daß der 
MC zu langsam ist.
Hauptsache Du verwendest keine Delays im Interrupthandler.
Oder LCD-, UART-Ausgaben, Float, Division und anderes lahmes Zeugs.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Peter D. schrieb:
> 90µs sind bei 8MHz Takt 720 CPU-Zyklen, da besteht keine Gefahr, daß der
> MC zu langsam ist.

Da wäre ich vorsichtig, wegen:

Sidey schrieb:
> (ich nutze die Arduino Funktionen um den pin abzufragen)

von Peter D. (peda)


Lesenswert?

Interessant wäre natürlich, woher das Signal kommt und was Du damit 
machen willst.
Je genauer man eine Aufgabe beschreibt, umso einfacher läßt sie sich 
implementieren.
Wenn man aber nur wenig preisgibt, wird die Lösung oft nur unnötig 
kompliziert.

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.