Hi
Leider kann ich kein C (oder will es nicht können
) aber vielleicht hilft dir die Erklärung mit einem Assemblerbeispiel. Dazu hab ich zwei Variablen Old_in und New_In.
In New_In liegen die entprellten Signale der Eingänge. Nun folgt eine Exclusiv-Oder Opeeration zwischen Old_In und New_In. Nur veränderte Bits haben eine logische "1". Mit einer Und-Operation zwischen dem Ergebnis und der Variablen Old_In hast du den Wechsel von "1" nach "0". Mit einer Und-Operation zwischen Ergebnis und New_In erkennst du den Wechsel von "0" nach "1". Nach dieser Auswertung kopierst du New_In nach Old_In. Die ermittelten Bits nimmst du als Flankenbits und rufst entsprechend die Aktionen auf, die du damit bearbeiten willst. Nach Bearbeitung wird das Flankenbit gelöscht. Eine erneute Bearbeitung wird erst beim nächsten Flankenwechsel erfolgen. Das heißt: Taster loslassen und erneut drücken.
In Assembler
LDS r 16, old_in
LDS r 17, New_In
EOR r 17, r16 ; Ergebnis in r17
AND r16, r17 ; Ergebnis steht in r16
STS In_To_Low,r16 ; Wechsel von 1 nach 0
LDS r16, New_In ; nochmal laden
AND r17, r16 ; Ergebnis steht in r16
STS in_To_High, r17 ; Wechsel von 0 nach 1
STS old:In, r16 ; neu nach alt
Ach ja, Taster in interrupt ist nicht sehr sinnvoll. Du weißt nichts über das Prellverhalten. Ich frage im Polling ab, da ein Controller idR schnell genug ist, ein paar hundert mal vorbeizurauschen, bevor ich den taster wieder loslassen kann. Entprellt wird mit Zeitzählern ( ca. 5mSek) Auch hier hilft EOR oder Exclusiv.
Angenommen , deine Eingänge werden in einer Variablen InDebounce gehalten, bis sie Stabil sind ist auch hier das Vorgehen:
Port laden, Exclusiv mmit der Variablen InDebouncce. <> 0 dann Zeitzählerwert auf 5
Zeitzähler wird in der Timer ISR runtergezählt.
Ist der Zeitzähler 0 ist nix passiert und die folgenden Schritte werden übersprungen. Erreicht der Zeitzähler den Wert 0 beim Runterzählen, dann ist dein Eingang stabil und kann nach New_In kopiert werden. Kommen deine Eingänge von verschiedenen Ports, musst du statt der direkten Portabfrage eine Variable mit den gesammelten Bits zwischenschalten. Hier mal eine kleine Assemblerroutine, die von Port B 4 Bits benutzt.
Read_IO:
In r16, PortB ; lesen Port B
ANDI r16, 0b00001111 ; ungültige Bits ausblenden
LDS r17, InDebounce ; Lade letzen Bitstatus
EOR r17, r16 ; Unterschiedlich zur Ablage InDebounce ?
BREQ weiter ; wenn nicht, dann Ende
STS InDebounce, r16 ; sonst gelesenen Wert in die Ablage
LDI r16, 5 ; Zeitzähler mit 5 setzen
STS Debounce_Time, r16
Weiter:
RET
Timer_ISR:
.... ; irgendwelche Bearbeitung
Is_mSek: ; Einstieg mSek , kann aber auch Anfang sein
LDS r16, Debounce_Time ; Prellzeit laden
CPI r16, 0 ; ist 0 ?
BREQ Next_mSek ; dann überspringen
DEC r16 ; runterzählen
STS Debounce_Time, r16 ; aktuelle Prellzeit speichern
BRNE next_mSek ; nicht 0 , dann überspringen
LDS r16, InDebounce ; InDebounce ist stabil
STS New_In, r16 ; dann nach New_In kopieren
Next_mSek:
.... ; weitere Interrupt -Bearbeitungen
RETI
Die Flankenauswertung erfolgt dann auch in der Hauptschleife und wird einfach bei jedem Zyklus durchlaufen. Zum Beispiel mit einer kleinen Subroutine Set_IO_Event:
Ok, ich weiß, du sprichst C, aber das Prinzip ist in C genauso abzuarbeiten. Deshalb und für andere Neugierige hab ich es mal nieder geschrieben.
gruß oldmax