Beim Tastenfeld muss ich weiter ausholen. Wie ist es
möglich, 16 Tasten mit nur 8 Leitungen abzufragen? Schauen wir uns einmal die
folgende Abbildung an.
Die Tasten sitzen an den Kreuzungspunkten der Zeilen- und
Spaltendrähte. Wird eine Taste gedrückt, dann wird eine bestimmte Zeilenleitung
mit einer genau definierten Spaltenleitung verbunden. Aufgabe unseres Programms
ist es jetzt, herauszufinden, wer mit wem verbunden ist. Dafür gibt es
verschiedene Algorithmen. Zwei davon stelle ich Ihnen hier vor. Die
Vorgehensweise orientiert sich an der Art der Verdrahtung und der Hardware der
vorhandenen Schnittstellen.
Wie muss der Tastenblock an den ESP32 überhaupt angeschlossen
werden? Wir können für jede der 8 Leitungen einen GPIO-Pin vorsehen. Allerdings
ist die damit verbundene Decodierung der Tasten durch verschachtelte Schleifen die
aufwendigere Softwarelösung, weil eben einzelne Leitungen angesprochen
werden müssen. Der ESP32 hat keine Portregister wie die AVR-Controller (Arduino
und Co.) mit 5- bis 8-Bit Datenbreite.
Die zweite Anschlussvariante benutzt daher den
Porterweiterungsbaustein MCP23017, der an dem I2C-Bus hängt, welcher evtl. bereits
ein Display versorgt. Anhand dieser Schaltung stelle ich die raffiniertere Reversal-Decoderlösung vor. Beide Lösungen bedienen sich der
Pollingmethode zur Tastaturabfrage. Immer dann, wenn eine Tastenbetätigung
erwartet wird, schaut das Programm nach, ob eine Taste gedrückt wird und wartet
gegebenenfalls so lange, bis das geschieht.
Eine dritte Abfragemöglichkeit bestünde darin, durch
zeitgesteuerte Programmunterbrechungen (aka Timer-Interrupts) die Tasten in
festen Intervallen abzufragen und die Ergebnisse in einem Pufferspeicher
abzulegen. Aus diesem Tastaturpuffer könnte sich das Hauptprogramm dann bei
Bedarf die Zeichencodes, die den Tasten entsprechen, abholen. Wir nehmen hier die
einfachere Pollingmethode.
Fassen wir das Bisherige zusammen. Wir haben also
·
zwei Methoden, die Tasten-Hardware
anzuschließen: Einzelleitungen oder parallel
·
zwei Methoden, der Tastenabfrage: Polling oder
Interruptbetrieb und
·
zwei Methoden, die Tasten durch Software zu
decodieren: Schleifen oder reversal
Weil es beim ESP32 keine "Sammelports",
wie bei den AVR-Controllern gibt, wo man mehrere Leitungen zu einem
Portregister zusammenfasst, müssen die GPIOs eben einzeln bedient werden.
Hardwaremäßig sieht das wie folgt aus. Ich habe die einzelnen Leitungen wie die
farbcodierten Jumperkabel eingefärbt, um die Zuordnung eindeutig festzulegen.
Das Schaltschema zeigt die folgende Abbildung. Die Pinbelegung und die
elektrischen Eigenschaften des Tastenblocks kann man im Datenblatt
nachlesen. Die elektrischen Werte sind alle unkritisch, weil die Kontakte ja
kaum belastet werden.
Die Tastenabfrage ist in Form der Klasse KEYPAD_P gelöst,
die ich in das Modul keypad.py integriert habe. Im gleichen Zug wurde die
Tastenabfrage des LCD-Keypads so angepasst, dass sich auch dafür dieselbe API
ergibt. Bei allen Klassen gibt es eine Methode key(),
die angesprochen wird, wenn das aufrufende Programm eine Tastenbetätigung
wünscht.
Aber der Reihe nach. Der Konstruktor der Klasse KEYPAD_P
erwartet zwei Listen mit je 4 Pinnummern für die Zeilen und die Spalten des
Tastenblocks. Sie werden im Hauptprogramm bestückt, etwa so wie es in der
Abbildung vorgegeben ist.
col=[15,5,18,19]
row=[13,12,14,27]
Dann rufen Sie damit den Konstruktor auf
from keypad import KEYPAD_P
kp=KEYPAD_P(row, col)
Hinweis:
Im Handel sind auch Folientastaturen erhältlich. Die sind
aber nicht pinkompatibel mit der hier verwendeten Tastatur.
Programmtechnisch steckt Folgendes dahinter:
class
KEYPAD_P: # indexed mit Schleifen
# Index ist die Tastennummer
keyNumber=[0x31,0x00,0x01,0x02,
0x10,0x11,0x12,0x20,
0x21,0x22,0x03,0x13,
0x23,0x33,0x30,0x32]
asciiCode="0123456789\x08\x0b\x0c\x0d*+"
# row und col sind Listen der Pinnummern)
# z.B. col=[15,5,18,19]
row=[13,12,14,27]
def __init__(self,
row, col):
self.rowPin=[Pin(i,Pin.OUT) for i in row]
self.colPin=[Pin(i,Pin.IN,Pin.PULL_UP) for i in col]
Damit die Zuweisung der Pinnummern auf Pin-Objekte in
einem Rutsch geht, habe ich mich eines Tricks von MicroPython bedient, der List-Comprehension.
In den Listenkontext (eckige Klammern) ist durch die Anweisung Pin(i,Pin.OUT) die Vorschrift verpackt, wie mit den Elementen
der Lisen row oder col zu verfahren ist, um daraus ein Pinobjekt zu
generieren. Die Instanzvariablen rowPin und colPin sind also Listen von Pinobjekten. In rowPin sind die Objekte Ausgänge, in colPin
Eingänge mit aktiviertem Pullup. Letzteres spart hier externe Widerstände.
Die Lösung mit den Pin-Listen habe ich deshalb gewählt,
damit die Abfrage wenigstens in Form von for-Schleifen geschehen kann und nicht
für jede der 16 Kombinationen eigener Programmcode erzeugt werden muss. Die
Methode key() erledigt die Hauptarbeit. Sie
stellt die Taste fest und liefert eine Tastennummer zurück, während die Methode
debounceKey() zusätzlich, falls erforderlich, für
das Entprellen der Tasten sorgt und als Ausgabe ebenfalls die Tastennummer als
Ausgabe zur Verfügung stellt.
def key(self):
for i in range(4):
self.rowPin[i].value(1)
for j in range(4): # row setting
self.rowPin[j].value(0)
for k in range(4): # query cols
w=self.colPin[k].value()
if
w==0:
code=j<<4 | k
#print(hex(code))
self.rowPin[j].value(1)
try:
return
KEYPAD_P.keyNumber.index(code)
except:
return-1
self.rowPin[j].value(1)
return -1
def debounceKey(self,
debounce=1):
for i in range(debounce):
k1=self.key()
if k1 !=
-1:
sleep(0.01)
k2=self.key()
if k2
== k1:
return
k1
return -1
Wie arbeitet key()?
Die Zeilenpin-Objekte 0..3 werden alle auf 1 gesetzt. (Sie
erinnern sich, MicroPython sieht die obere Bereichsgrenze (4) als exclusiv an.)
In der Grafik wird die Taste 6 gedrückt. Sie schließt Zeile 1 mit Spalte 2
kurz.
In der folgenden j-Schleife werden die Zeilenleitungen von
oben nach unten der Reihe nach einzeln auf GND-Pegel gesetzt. Die
eingeschlossene k-Schleife prüft nun, ob eine der Spaltenleitungen auf
0-Potenzial liegt. In diesem Fall bilden wir den rohen Tastencode aus Zeilen-
und Spaltennummer. Die Zeilennummer j liefert das höherwertige Nibble des code-Bytes,
die Spaltennummer das niederwertige Nibble. Dann setzen wir den Zeilenausgang wieder
auf 1 und verlassen mit return und der
Tastennummer im Gepäck die k-Schleife und die Funktion. Wurde keine Taste
gedrückt, laufen beide Schleifen bis zum Ende durch, und die Rückgabe ist der
Wert -1. Die rohen Tastencodes werden in diesem Beispiel in positiver Logik
ermittelt. Die Bits erhalten ihre Wertigkeit aus den Laufindizes der Schleifen,
nicht vom Pegel auf den Leitungen.
Der Tastencode wird als Index des rohen Tastencodes in der
Liste keyNumber ermittelt. Die rohen Tastencodes
müssen also einfach nur an die Position in der Liste gesetzt werden, deren
Index der gewünschten Tastennummer entspricht. Hier erst einmal die Codeliste:
keyNumber=[0x31,0x00,0x01,0x02,
0x10,0x11,0x12,0x20,
0x21,0x22,0x03,0x13,
0x23,0x33,0x30,0x32]
Zur Erinnerung, Listen werden beginnend mit der 0
indiziert. Die Taste, die in der 3. Zeile in der Spalte 1 liegt, ist die 0.
Also muss der Hexcode 0x31 an die Position 0 in der Liste. Alles klar?
Nein - nicht so ganz? Gut, noch ein Beispiel. Denken Sie
daran, Zeilen, Spalten und Listeneinträge werden ab der 0 hoch gezählt.
Die Taste C soll die Tastennummer 12 liefern. Sie liegt in
der 2. Zeile in Spalte 3. Die Zeilenbits bilden das High-Nibble des rohen
Tastencodes. Die 0x02 für Zeile 2, um 4 Bit nach links verschoben (oder mit 16
multipliziert) ergibt im Code-Byte 0x20. Das wird mit 0x03 oderiert.
Der rohe Tastencode ist demnach 0x23 und muss an der 12. Position in der Liste
stehen. Jetzt vergleichen Sie das mit der keyNumber-Liste
– stimmt!
KEYPAD_P.keyNumber.index(code)
Um den Index eines Listeneintrags feststellen zu können,
gibt es die eingebaute Funktion index(), die als
Methode des Listenobjekts aufgerufen wird. keyNumber
ist eine Klassenvariable und muss daher mit dem Klassenbezeichner KEYPAD_P als Prefix referenziert
werden. In code wird der rohe Tastencode übergeben.
Aus dieser Beschreibung können wir schließen, dass die 1
am schnellsten entdeckt wird (0,50ms) und dass der Zustand "keine
Taste" am längsten braucht (1,34ms). Werden zwei Tasten oder mehr
gleichzeitig gedrückt, dann wird die weiter oben und/oder links liegende Taste
decodiert und die andere(n) verworfen, da die Schleifen diese Tasten nicht mehr
abfragen. Damit ist auch das Problem der Mehrdeutigkeit gelöst.
Die Methode debouceKey()
nimmt mit dem Parameter debounce eine Ganzzahl, die angibt, wie oft die
interne Schleife durchlaufen werden soll. Mechanische Tasten schließen und
öffnen nicht exakt zu einem festgelegten Zeitpunkt, sondern der Schaltkontakt
flattert jeweils während einer kurzen Zeitspanne, was zu chaotischem Öffnen und
Schließen des Kontakts führt. Diesen Vorgang nennt man Tastenprellen (aka engl.
Bouncing). Um nun sicherzustellen, dass eine Taste
wirklich gedrückt ist, muss man die Schaltzustände zu verschiedenen Zeitpunkten
einlesen und mit einander vergleichen. Werden in kurzem zeitlichem Abstand die
gleichen Zustände festgestellt, dann gilt die Taste als gedrückt. Diese Prüfung
führt die Methode debounceKey() durch, und der Wert im
Parameter debounce gibt an, wie oft diese Prüfung durchgeführt werden soll. Der
Defaultwert dafür ist 1.
Wenn der Vergleich positiv verläuft, wird der Tastencode
zurückgegeben, andernfalls der Wert -1, der andeutet, dass entweder keine Taste
gedrückt wurde oder, dass der Schaltzustand bis zuletzt nicht eindeutig war.
Zum Testen müssen eine Reihe von Modulen ins Flash des
ESP32 hochgeladen worden sein. Am besten ist es, wenn Sie alle eingangs
genannten Module herunterladen und zum ESP32 schicken. Das sind die Dateien:
HD44780U-I2C-Erweiterung
zum LCD-Modul
i2cbus-Modul
für standardisierten Zugriff auf den Bus
mcp.py
hardwarededizierte Methoden für den MCP23017
Die Datei keypad_p_test.py
öffnen sie bitte in einem Editorfenster. Bevor Sie loslegen, noch ein wichtiger
Hinweis. Suchen Sie bitte im Editor nach den folgenden beiden Zeilen.
#kp=KEYPAD_I2C(ibus,keyHwadr)
# Hardware Objekt
am I2C-Bus
kp=KEYPAD_P(rows,cols)
# HW-objekt mit Parallelanschluss
Die erste Zeile ist auskommentiert, weil sie nur für die
weiter unten beschriebene zweite Anschlussmethode via I2C-Bus gilt. Hier muss
die zweite Zeile ausgeführt werden, darf also kein Kommentarzeichen haben.
Wenn das passt, können Sie das Programm mit F5 starten.
Damit sind alle Importe und Declarationen für den Test des Tastenfelds
erledigt. Alles für jeden Test erneut von Hand einzugeben, dauert zu lange und ist
fehleranfällig.
Das Tastenfeld ist korrekt angeschlossen? Dann los! Geben
Sie bitte den folgenden Befehl ein.
>>> kp.key()
-1
Wenn Sie keine Taste gedrückt hatten, ist das OK!. Rufen
Sie jetzt mit Pfeil nach oben den letzten Befehl noch einmal in die
Eingabezeile zurück. Jetzt die Taste 1 drücken und die Eingabezeile mit Enter
beenden.
>>> kp.key()
1
Dasselbe mit der Taste C
>>> kp.key()
12
Prima! Einige höhere, von der Hardware unabhängige
Methoden zur Tastenabfrage besprechen wir nach dem folgenden Kapitel. Darin
geht es um die effektivere Softwarelösung und den Tastenfeldanschluss via I2C.
Der Vorteil dieser Methode liegt eindeutig darin, dass
nicht einzelne Leitungen der Reihe nach abgefragt werden müssen. Stattdessen
wird einer der 8-Bit-Ports (A) des MCP23017 halbiert. Das obere Nibble steuert
die Zeilenleitungen, das untere Nibble die Spaltenleitungen, aber eben nicht
einzeln, sondern parallel. Ebenso gut wäre es, den Port A für die Zeilen und B
für die Spalten einzusetzen. Für größere Tastenmatrizen mit mehr als zweimal
vier Leitungen ist das unumgänglich.
Angesteuert wird der MCP23017 über den I2C-Bus und damit
parallel zum Display und evtl. weiteren I2C-Einheiten. Das ist möglich, weil
alle Schnittstellen unterschiedliche Hardwareadressen haben. Für die Adresse
0x20 müssen die drei Adresspins des MCP23017 alle auf GND-Potenzial liegen. In
der obigen Darstellung sind die Leitungen AD0, AD1 und AD2 nicht beschaltet und
daher reagiert der Baustein auf die Adresse 0x27. Übrigens, passen Sie auf,
dass Sie wirklich einen MCP23017 bekommen. Sein Brüderchen, der MCP23S17, wird
über den SPI-Bus angesteuert und ist hier nicht brauchbar.
Für den MCP23017 habe ich ein Modul erstellt. Die Klasse MCP23017
stellt eine ganze Reihe von Konstanten und Methoden bereit, die eine
übersichtliche und einfache Programmierung des Bausteins ermöglichen, ohne dass
man sich mit den Methoden des I2C-Moduls herumschlagen muss. Die Tastenabfrage
ist hiermit in 7 Zeilen passiert. Obwohl keine Schleifen zu durchlaufen sind,
ist dieser Algorithmus scheinbar langsamer wie der oben beschriebene, dauert aber
für jede Taste gleich lang (ca. 4ms). Das liegt aber nicht an der Methode an
sich, sondern am I2C-Bus, der uns ausbremst. Hätte der ESP32 von vorn herein
ansprechbare Parallelports, dann wäre diese Methode eindeutig die schnellere.
Die AVR-Processoren mit ihren Parallelports profitieren also von diesem
Algorithmus.
Die Klasse KEYPAD_I2C erbt von der Klasse MCP23017 und
kann daher direkt auf deren Namensraum zugreifen. Die Liste keyNumber
der Rohcodes sieht etwas anders aus, wie die bereits
bekannte, der Konstruktor auch.
class
KEYPAD_I2C(MCP): # reversal
# Keypad
Reihe 0 1 2 3 Spalte 0 1 2 3
# MCP GPIOA Pin 4 5 6 7 0 1 2 3
keyNumber=[0x7D,0xEE,0xED,0xEB,
0xDE,0xDD,0xDB,0xBE,
0xBD,0xBB,0xE7,0xD7,
0xB7,0x77,0x7E,0x7B]
asciiCode="0123456789\x08\x0b\x0c\x0d*+"
HWADR=const(0x20)
KeyMask=const(0b00001111) #
OUT=0 IN=1
# 0 is OUTPUT - 1
is INPUT
# Die Zeilen sind zunächst Output
def __init__(self,i2cbus,hwadr=HWADR):
self.hwadr=hwadr
self.i =
i2cbus
super().__init__(i2cbus,hwadr)
print("Keypad_I2C
@", hex(hwadr))
Der Konstruktor nimmt vom Hauptprogramm als
Positionsparameter ein I2CBus-Objekt und als optionalen Parameter die
Hardwareadresse des MCP23017. Beide reicht er an die Klasse MCP23017 weiter,
die unter dem Alias MCP importiert wurde.
Aber schauen wir uns den Wunderalgorithmus einmal an.
def key(self):
self.changeIODIRA(0x00,KeyMask,True)
self.setGPIOA(KeyMask)
iod=self.getGPIOA()
self.invertIODIRA(True)
self.setGPIOA(iod)
iod=self.getGPIOA()
#print(hex(iod),bin(iod))
try:
return
KEYPAD_I2C.keyNumber.index(iod)
except ValueError
as e:
return -1
Der Code erscheint wesentlich geradliniger und besteht,
die Exception-Behandlung nicht mitgerechnet, aus 7 Anweisungen.
changeIODIRA(0x00,KeyMask,True)
KeyMask hat den Wert 0b00001111.
Wir undieren das
Datenrichtungsregister A mit 0b00000000, löschen also alle Bits und setzen dann
durch Oderieren mit KeyMask das Low-Nibble als
Eingänge. True sorgt dafür, dass für diese Eingänge die Pullups eingeschaltet
werden. Die vier Zeilenleitungen sind jetzt Ausgänge die Spaltenleitungen
Eingänge.
setGPIOA(KeyMask)
KeyMask hat immer noch den Wert
0b00001111. Somit werden alle Zeilenleitungen gleichzeitig auf GND-Potential
gelegt.
iod=self.getGPIOA()
Die Eingänge von GPIOA werden erfasst. Mit den Pullups
ergibt das den Wert
0bxxxx1101
Das High-Nibble interessiert im Moment (noch) nicht.
invertIODIRA(True)
Wir invertieren das Datenrichtungsregister A, Eingänge
werden zu Ausgängen und umgekehrt. True - die Pullups der Eingangsleitungen
werden aktiviert..
setGPIOA(iod)
S2 führt jetzt Low-Potential. Wir lesen GPIOA ein und
erhalten den Wert
0b10111101 = 0xDB
Wir treffen hier auf eine negative Logik, das heißt es
zählen die Bits, die nicht gesetzt sind. Man kann es auch so sehen, für
die Spalten, das Low-Nibble, fehlt von der 15 das Bit mit der Wertigkeit 4.
Somit bleiben 15 – 4 = 11 = 0x0B übrig. Bei den Zeilen liegt Bit1 auf Low, es
fehlt im Nibble also die 2. 15 – 2 = 13. Das High-Nibble erhält den Wert 0xD0. Bitweise
oderiert ergibt sich 0xD0 | 0x0B = 0xDB
KEYPAD_I2C.keyNumber.index(iod)
Die Rohwerte stehen wieder an entsprechender Stelle in der
Liste keyNumber. Der Index eines Werts liefert die
Tastennummer wie im ersten Beispiel. Damit haben beide Methoden denselben
Aufruf und liefern das sinngemäß gleiche Ergebnis. Der Weg dorthin ist ein anderer,
aber nach außen hin spielt das keine Rolle. Die Methode debounceKey()
besitzt in beiden Klassen sogar denselben Code. Die beiden Klassen liefern also
mit Ausnahme des Konstruktors Instanzen mit derselben API.
OK! Das war jetzt weit ausgeholt, aber ich denke, es ist
wichtig, die grundlegenden Mechanismen einer Matrixabfrage verstanden zu haben
und gegen einander abwägen zu können. Lassen Sie uns noch einen Blick auf die
Klasse KEYPAD werfen, welche hardwareübergreifende Methoden für die Benutzung
von Tastaturen anbietet.
Der Konstruktor erwartet eine Instanz der Klassen KEYPAD_P
oder KEYPAD_I2C. Sogar KEYPAD_LCD – Instanzen werden trotz des geringen
Zeichenumfangs akzeptiert. Ein Trick soll nicht unerwähnt bleiben. Die Methode kp.key(), besser deren Referenz, wird der Instanz-Variable self.key zugewiesen. In MicroPython kann man das tun. Das
kann helfen, ellenlange Aufrufe von importierten Methoden zu verkürzen. Aus self.k.key() wird self.key(). Sie
meinen, das sind doch Peanuts? Na ja, dann stellen Sie sich doch einmal vor,
statt k müsste keyPad_I2C_Instanz eingegeben werden und das 20 mal oder öfter.
class KEYPAD:
# kp ist ein KEYPADXXX-Objekt, wird uebergeben
def __init__(self,kp,d=None):
self.k=kp
self.disp=d
self.key=kp.key
def waitForKey(self,timeout=5,ASCII=False):
now=time()
end=(now+timeout
if timeout!=0 else now+10)
while 1:
k=self.key()
if k!=-1:
if
ASCII:
k=self.k.asciiCode[k]
return
k
if timeout==0: end=time()+10
if
time()>=end:
if
ASCII:
return
"\xFF"
else:
return
-1
def asciiKey(self):
n=self.key()
if
0<=n<=15:
return self.k.asciiCode[n]
return
"\xFF"
def padInput(self,delay=0.5,xp=0,yp=0):
s=""
x=xp; y=yp
while 1:
taste=self.asciiKey()
if taste
!= -1:
if
'0'<=taste<='9' or taste=='+' or taste=='*':
s+=taste
if
self.disp:
x=self.disp.writeAt(taste,x,yp)
else:
x+=1
sleep(delay)
elif
taste=="\x08":
if
self.disp and x>xp:
self.disp.clearFT(x-1,yp,x)
x=(x-1 if
x>xp else xp)
s=s[:x-xp]
sleep(delay)
elif
taste == "\x0d":
return s
Die drei Methoden dieser Klasse erfüllen nützliche Zwecke.
Die Methode waitForKey(delay) wartet delay Sekunden auf
die Betätigung einer Taste. Wird in dieser Zeit eine Taste gedrückt, dann gibt
die Methode die Tastennummer zurück, andernfalls -1. Die Methode wartet ewig,
falls an delay der Wert 0 übergeben wird. Als
Standard wird die rohe Tastennummer zurückgegeben. Setzt man ascii = True erfolgt stattdessen die Rückgabe des
ASCII-Codes der Taste.
Je nach dem Definitionsstring asciiCode
in den KEYPADXXX-Klassen liefert die Methode asciiKey()
ein normales ASCII-Zeichen statt der Tastennummer zurück. Welche Zeichen das
sein sollen, legen Sie mit Hilfe der Zeichenkette in asciiString
fest. Die Position des Zeichens im String entspricht der Tastennummer, welche
die Methode key() liefert. Nicht druckbare Zeichen,
wie \n werden als Hexcode angegeben. Zum Beispiel entspricht \n also \x0D. Meine
Definition sieh so aus:
asciiCode="0123456789\x08\x0b\x0c\x0d*+"
Übrigens, wenn Sie mehrere asciiCode-Definitionsstrings
anlegen, können Sie eine Tastenmehrfachbelegung etablieren. Allerdings ist dann
nicht nur die Beschriftung der Tasten eine Herausforderung.
Die Methode padInput()
erlaubt schließlich die Eingabe von Ziffernfolgen ergänzt durch "*"
und "+", welches durch die Taste "#" eingegeben wird. Taste
"A" löscht rückwärts und Taste "D" übernimmt den String zur
weiteren Verarbeitung. Wurde dem Konstruktor ein Display-Objekt übergeben, dann
erscheinen die Zeichen auch im Display. Ohne Display-Objekt ist Blindflug
angesagt.
Drei optionale Parameter steuern die Eingabe. delay (default = 0.5s)
schützt vor ungewollter Mehrfacheingabe eines Zeichens, weil die key-Methode einfach zu schnell ist, brauchen wir eine
Verzögerung. xp und yp
legen die Position im Display fest, ab der die Eingabe dargestellt wird.
Default ist die linke obere Cursorposition, entsprechend "home".
An dieser Stelle angekommen, testen wir jetzt die drei Methoden.
Falls Sie das noch nicht getan haben, schicken Sie jetzt bitte alle Module ins
Flash des ESP32 und öffnen Sie das Programm keypad_p_test.py in einem
Editorfenster. Je nach der gewählten Anschlussart der Tastatur muss genau eine
der folgenden Zeilen entkommentiert sein.
#kp=KEYPAD_I2C(ibus,keyHwadr)
# Hardware Objekt
am I2C-Bus
kp=KEYPAD_P(rows,cols)
# HW-objekt mit Parallelanschluss
Starten Sie das Programm mit F5. Wenn der REPL-Prompt
(>>> ) wieder erscheint, sind Sie bereit für die folgenden Tests über
die Kommandozeile.
>>> k.waitForKey(3)
5
>>> k.waitForKey(3)
-1
>>>
Im ersten Fall wurde innerhalb von 3 Sekunden die Taste 5
gedrückt. Beim zweiten Aufruf wurde der Tastendruck versäumt.
>>> k.asciiKey()
-1
>>> k.asciiKey()
'*'
>>>
Jetzt wurde beim ersten Aufruf keine Taste gedrückt und beim
zweiten die "*"-Taste. Beachten Sie, dass nicht der Tastencode 14
sondern der ASCII-Code für "*" zurückgegeben wurde.
>>> k.padInput(0.3,3,1)
'1234567'
>>>
Mit einer Verzögerung von 0,3 Sekunden wird das Tastenfeld
abgefragt. Die Eingaben werden ab der Position Spalte 3 und Zeile 1 im Display
angezeigt. Stellen Sie die Totzeit nicht zu lang ein, denn sonst werden Tastenbetätigungen
übersprungen. Bei zu kurzem Totzeitwert erscheinen Eingaben mehrfach. Um die
Eingabe abzuschließen, drücken Sie die Taste D.
Als Ergebnis des vorangegangenen Befehls sollten Sie Ihre
Eingabe sowohl auf dem Display als auch im Terminalfenster sehen.