Forum: Mikrocontroller und Digitale Elektronik Hilfe zur Tastenentprellung von P.Dannegger


von Tom B. (buzze11)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich habe mir zum Test ein Board auf Lochraster aufgebaut, auf dem sich 
zum Einlesen von 16 Tastern zwei 74HC165 befinden und zur Ausgabe auf 16 
Leds zwei 74HC595. Zur seriellen Ansteuerung benutze ich einen 
ATTiny2313.
Die Daten bekomme ich auch seriell eingelesen, und im SRAM abgelegt.Die 
Ausgabe der 2 Bytes funktioniert auch, zumindest soweit, dass ich sobald 
ich die Daten einlese und daraufhin gleich wieder an die Led`s ausgebe 
die jeweils zugehörige Led an geht und wenn ich sie loslasse wieder 
ausgeht.

Jetzt zum Problem:
Ich möchte die Tasten die an das Schieberegister angeschlossen sind 
entprellen. Anschließend soll nur bei Änderung der Tasten eine 
Aktualisierung der Ausgabe erfolgen. Der vorherige Schaltvorgang soll 
allerdings erhalten bleiben. Sprich die Tasten sollen die jeweils 
zugehörige Led einschalten und beim folgenden Tastendruck ausschalten.
Dazu hatte ich mir die 8-Bit Entprellroutine von Peter Dannegger im 
Tutorial angesehen, aber leider nicht 100%ig verstanden.

In meinem Code lasse ich im Hauptprogramm die Seriellen eingangsdaten 
jeweils in einem 2Byte grossen SRAM bereich mit dem Namen "outdaten" 
ablegen. Im nächsten Schritt sollen die Eingangsdaten dann mit den 
letzten daten jeweils Byteweise überprüft werden, und nur bei Änderung 
verändert im SRAM unter outdaten_old abgelegt und anschließend 
ausgegeben werden.

Ich muss leider zugeben, dass ich gerade daran scheitere, dass ich die 
Daten nicht so logisch miteinander verknüpft bekomme, dass ich die alten 
Tastenzustände beibehalte und nur nach erneutem drücken toggeln kann.
Mit einem XOR der neuen tastenflags mit den alten, bekomme ich die 
Anzeige, dass sich was geändert hat..hat sich nichts geändert hole ich 
mir das nächste Byte zur Überprüfung.Hat sich der Zustand geändert lasse 
ich die Tasten erneut nach Ablauf eines 16-Bit Zählers abfragen. Mit 
einem CP vergleiche ich dann den letzten erkannten Wechsel mit dem 
derzeitigen. Ist er immer noch gleich soll dann das Byte im SRAM 
gesichert und ausgegeben werden. Aber da hängt es irgendwie!! Gibts da 
irgendwo HILFE??

Vielen dank schonmal für Eure Antworten..
Lg Thomas

von Hannes Lux (Gast)


Lesenswert?

Die (ASM-)Entprellroutine von PeDa nutzt außer einem temporären Register 
4 weitere Register exklusiv. Dies sind zwei Prellzähler und die 
Register, die Peter "Key_state" und "Key_press" nennt. Die Routine 
entprellt 8 Bit zugleich (für 16 Bit müsste sie zweimal mit 
verschiedenen Registern implementiert werden oder die Werte 
zwischendurch ins RAM auslagern) und liefert Zustand und Flanke.

In Key_state steht der Tastenzustand, der interressiert aber nur, falls 
man so etwas wie Shift-Tasten implementieren will.

In Key_press wird ein Bit gesetzt, wenn eine Taste losgelassen und 
erneut gedrückt wurde (Flankenerkennung). Dieses Register ist für Deinen 
Zweck nutzbar.

Um den LED-Port zu schalten, muss er nur mit Key_press exor vernüpft 
werden, danach ist Kex_press zu löschen. Für den Fall, dass die Werte in 
Registern gehalten werden, sieht das so aus:

 eor leds1,key_press1     ;erste 8 LEDs gemäß Taster-Flanken toggeln
 clr key_press1           ;Tastenflags entwerten, haben Job ja erledigt
 eor leds1,key_press2     ;zweite 8 LEDs gemäß Taster-Flanken toggeln
 clr key_press2           ;Tastenflags entwerten, haben Job ja erledigt

Solltest Du die Werte im SRAM halten, dann kommen natürlich noch die 
entsprechenden LDS/STS (oder LD/ST über Pointer) dazu, die die Routine 
dann etwas aufblähen.

...

von Tom B. (buzze11)


Angehängte Dateien:

Lesenswert?

Hallo Hannes,

vielen Dank erstmal für deine schnelle Antwort.
Die Entprellung selbst wollte ich in meinem Projekt, ohne den TIMER0 
Overflow sprich ohne Interrupt lösen, da die E/A-zeit der Shift- 
eingangs und -Ausgangsregister relativ hohe Laufzeiten haben, und ich im 
späteren Programmablauf die Daten seriell an eine Gegenstelle auslagern 
möchte.
Die serielle Übertragung hatte ich aber weitgehend aus dem Programmcode 
gelöscht, da sie für das jetzige Problem nicht relevant war.
Das Entprellen per 16-Bit zähler sollte an dieser Stelle denke ich aber 
auch funktionieren, oder?

Zunächst wollte ich jetzt ungeachtet dessen, dass ich eigentlich 16 Bit 
(später mehr) zu verarbeiten habe, ein Byte prüfen, und die Leds am 
Ausgang ein und ausschalten.
Und genau da ist das Problem, denn ich bekomme die beiden Daten 
(outdaten_old), die ja immer den aktuellen Zustand der Leds haben, nicht 
mit den entprellten (Outdaten) verknüpft, so dass der alte zustand 
erhalten bleibt, und nur die "gedrückte Taste" getoggelt wird.

Habe ich z.b.

Outdaten_old mit 11110111 (derzeitiger Zustand der Leds) und bei 
Tastendruck
Outdaten     mit 11011111 (nach der Entprellung) komme ich nicht auf die 
Lösung, wie ich das (alte) gesetzte bit in Outdaten_old beibehalten kann 
und logisch mit den neuen (aktuellen Tastendrücken) verknüpfen muss um 
im Beispiel die     11010111 zu erhalten.

Der jetzige Code gibt mir jeden Tastendruck bei änderung entprellt 
weiter, und gibt ihn bei Änderung an die Leds aus. Jedoch löscht er die 
leds nach dem Loslassen auch wieder.
Den gesamten Code habe ich angehangen..

Viele Grüße Thomas

von spess53 (Gast)


Lesenswert?

Hi

Dein Problem ist, das du auf Drücken und Loslassen reagierst. Wenn du 
nur auf das Drücken reagieren willst ist eine zusätzliche Verknüpfung 
notwendig. Allerdings ist es notwendig, das eine gedrückte Taste durch H 
representiert wird. Mit:

    eor alter Wert,neuer Wert
    and alter Wert,neuer Wert

steht in 'alter wert' nur dort ein H wo eine Taste neu gedrückt wurde.
Damit lassen sich z.B. die LEDs umschalten:

    eor led,alter Wert

Die Werte für die Tasten und die LEDs würde ich in getrennten Werten 
speichern.

MfG Spess

von Hannes Lux (Gast)


Lesenswert?

> Dein Problem ist, das du auf Drücken und Loslassen reagierst.

Dann ist es aber nicht die Dannegger-Entprellung... ;-(

Ich bezog mich auf diesen Algorithmus, wobei ich allerdings meine 
eigenen Variablennamen benutze:
1
entprellung:            ;
2
 cbr flags,1<<entprell      ;Jobflag löschen
3
Tastenabfrage:  ;Entprellroutine (Algorithmus geklaut bei Peter Dannegger...)
4
 in temp,tap    ;Tastenport einlesen (gedrückt=L)
5
 com temp       ;invertieren (gedrückt=H)
6
 eor temp,tas   ;nur Änderungen werden H
7
 and tz0,temp   ;Prellzähler unveränderter Tasten löschen (Bit0)
8
 and tz1,temp   ;Prellzähler unveränderter Tasten löschen (Bit1)
9
 com tz0        ;L-Bit zählen 0,2,->1, 1,3,->0
10
 eor tz1,tz0    ;H-Bit zählen 0,2,->tz1 toggeln
11
 and temp,tz0   ;Änderungen nur dann erhalten, wenn im Prellzähler
12
 and temp,tz1   ;beide Bits gesetzt sind (Zählerstand 3)
13
 eor tas,temp   ;erhaltene Änderungen toggeln alten (gültigen) Tastenstatus
14
 and temp,tas   ;nur (neu) gedrückte Tastenbits bleiben erhalten
15
 or tfl,temp    ;und zugehörige Bits setzen (gelöscht wird nach Abarbeitung)
16
;tmp ist wieder frei, tas enthält den entprellten Tastenstatus,
17
;tfl die neu gerückten Tasten
18
Tastendauer:
19
 mov temp,tas       ;Tastenzustand kopieren
20
 andi temp,reptast  ;nur Tasten mit Wiederholfunktion stehen lassen
21
 tst temp           ;ist eine Taste betätigt?
22
 breq Tastendauer0  ;nein, Dauer auf Startwert...
23
 dec twz            ;ja, Zähler runter
24
 brne Tastenabfrage_e   ;Dauer abgelaufen? - nein...
25
 or tfl,temp        ;ja, noch aktive Tasten übernehmen
26
 ldi twz,twz1       ;und Zähler auf Wiederholwert setzen
27
Tastenabfrage_e:
28
 ;in "tfl" stehen jetzt wieder die Flags der länger betätigten Tasten
29
 ;sie werden nach Abarbeitung gelöscht
30
 dec blto                   ;runterzählen
31
 brne backlight1            ;schon unten? - nein...
32
 cbi blp,blb                ;ja, Backlight ausschalten
33
backlight1: 
34
 rjmp lcd_busywait_e        ;fertig, zurück...
35
Tastendauer0:       ;Reset Dauerzähler
36
 ldi twz,twz0           ;Tastendauerzähler auf Startwert
37
 rjmp Tastenabfrage_e   ;fertig...
Relevant ist hierbei das Register "tfl" (Tastenflags).

...

von Tom B. (buzze11)


Lesenswert?

Wenn ich dein Beispiel so durchgehe:

old              0b11110111 ;Bit3 war der alte zustand (Led an)
neu              0b11111101 ;Bit1 ist nun neu geändert
eor alt,neu      0b00001010
nach dem eor ist alt ja dann geändert..
and alt,neu      0b00001000

eor leds,alt     0b11110101

Jetzt mal umgekehrt (wiederausschalten)

old              0b11110101
neu              0b11110111
eor alt,neu      0b00000010
and alt,neu      0b00000010

eor leds,alt     0b11110101 ???????????

Wenn ich das so richtig interpretiere, dann funktioniert das nicht, oder 
mache ich einen Fehler?

LG Thomas

von Hannes Lux (Gast)


Lesenswert?

Was willst Du eigentlich immere mit OLD und NEU?

Ich brauche dazu nur den LED-Status (dessen Kopie dann an die 
Schieberegister ausgeschoben wird) und die entprellten Tastenflags:
1
          ;Bit         76543210
2
          ;LED_Staus 0b00001111
3
          ;tfl       0b00100010
4
eor led_status,tfl  ;0b00101101
5
clr tfl

Es wurde also Bit 1 ausgeschaltet und Bit 5 eingeschaltet. Damit das nur 
einmal geschieht, muss tfl (Key_press bei PeDa) anschließend entwertet, 
also gelöscht werden. Nur ein erneuter Tastenzyklus setzt wieder ein Bit 
in tfl.

...

von buzze11 (Gast)


Lesenswert?

Hallo Hannes,

vielen Dank für den letzten Beitrag, der war der Schlüssel zum Erfolg.
Habs jetzt soweit!!

Noch nen schönen Sonntag..

Lg Thomas

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.