Raspberry Pi

25) Maticová klávesnice

Nedávno se mě ptal jeden začínající "raspíčkář", jak má připojit maticovou klávesnici jako je třeba tahle:
 http://www.tme.eu/.../klavesnice/, a jak má zjišťovat, která tlačítka jsou stisknutá.

Já jsem stejnou klávesnici použil ve své krabičce pro Raspi.

Protože se mi to zdá jako zajímavé téma, vytvořil jsem tento článek ve kterém se pokusím popsat principy snímání takovéto maticové klávesnice. Možná se bude hodit i někomu dalšímu.

 

V několika minulých článcích jsem popisoval, jak se dá Raspíčkem číst obyčejné tlačítko. (Buď se připojí na GPIO vstup, a nebo k expandéru). V případě, že je tlačítek více, je však výhodnější použít takzvané maticové zapojení. Při tomto způsobu zapojení tlačítek dochází k úspoře potřebných GPIO portů.

Pro porovnání: 16 tlačítek zapojených "běžným" způsobem spotřebuje 16 vstupních pinů. Naproti tomu maticové uspořádání 4x4 tlačítka spotřebuje pouze 8 pinů (4 vstupní a 4 výstupní). To je úspora 8 pinů.

Při větším počtu tlačítek se tato úspora dále zvětšuje: Při 64 tlačítkách uspořádaných do matice 8x8 se ušetří 48 pinů. 

Maticové zapojení má ale i své nevýhody:

1) Nelze stisknout větší množství tlačítek zároveň (bez problémů jdou stisknout 2 tlačítka najednou, ale při třech už může v určitých kombinacích docházet k problémům. Níže se tomuto problému budu věnovat detailněji.)

2) Vyhodnocení stisknutých kláves trvá o něco delší dobu.

 

Pro následující příklady jsem vytvořil maticovou klávesnici 4x3 tlačítka. Její fotka je v úvodu článku a schéma vypadá takto:


Vlevo je skutečné schéma, vpravo zjednodušené zobrazení, které budu používat níže.

Připojení k raspíčku je sice možné přímo na GPIO konektor, ale v tom případě vás to bude stát 7 GPIO portů. Já jsem proto volil připojení přes expander MCP23017. Připojení expanderu k RasPi jsem vysvětlil tady, proto už se k tomu tady vracet nebudu. Nakreslím pouze připojení klávesnice k GPB portu tohoto expanderu:


Ty 3 diody jsou obyčejné diody (např. 1N4148). Slouží k ochraně před zkratem (vysvětlím níže).
 Je možné použít jakékoliv běžné křemíkové nebo germaniové diody - nesmí se použít LEDky.

 

Princip funkce:

Princip spočívá v tom, že se nečte stav celé klávesnice najednou, ale po řádkách. V našem případě tedy ve třech krocích (3 řádky).
Řádka, jejíž stav se má zjišťovat, je vybrána pomocí stavu logické "0" na jednom ze tří výstupních pinů (GPB0, GPB1 nebo GPB2).

Stisknutá tlačítka v takto vybrané řádce přenesou tuto logickou "0" na některé ze čtyř vstupních pinů (GPB4, GPB5, GPB6, GPB7).
Ovládací program pak musí vyhodnotit, jaké tlačítko odpovídá přečtenému kódu pro příslušnou řádku.

Zde jsem připravil několik animací, které by měly princip fungování názorně ukázat. 


Příklad 1: Bez stisku kláves

První příklad ukazuje stav, kdy není stisknuto žádné tlačítko.

V prvním kroku vybere počítač horní řádku (nastaví na ní "0"). Protože v ní ale není stisknuto žádné tlačítko, tak se ta "0" nedostane na žádný vstupní pin expanderu. Pokud jsou vstupní piny "ve vzduchu" (tlačítka jsou rozpojená) jsou uměle udržovány pomocí Pull-Up rezistorů ve stavu logické "1".

Stejná situace nastává i v druhém a třetím kroku.

Počítač tedy v tomto prvním příkladě získá při čtení klávesnice takovéto údaje:

číslo kroku krok 1 krok 2 krok 3
označení vstupu GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7
přečtená hodnota 1 1 1 1 1 1 1 1 1 1 1 1
význam není
"Q"
není
"W"
není
"E"
není
"R"
není
"A"
není
"S"
není
"D"
není
"F"
není
"Z"
není
"X"
není
"C"
není
"V"

 


Příklad 2: Jedna klávesa

Ve druhém příkladě byla stisknuta klávesa "S".

První krok je stejný, jako v předchozím příkladě - v první řádce není stisknutá klávesa, proto je na všech vstupech uměle udržovaná "1".

Ve druhém kroku se ovšem "0", která byla vyslána na drátě "b1" (GPB1), přenese přes stisknutou klávesu "S" do sloupce "b5" (GPB5).

Třetí krok je stejný jako první - není stisknuta klávesa, takže se nula nepřenese na vstupní piny.

Počítač ve druhém příkladě získá takovéto údaje:

číslo kroku krok 1 krok 2 krok 3
označení vstupu GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7
přečtená hodnota 1 1 1 1 1 0 1 1 1 1 1 1
význam není
"Q"
není
"W"
není
"E"
není
"R"
není
"A"
je
"S"
není
"D"
není
"F"
není
"Z"
není
"X"
není
"C"
není
"V"

 


Příklad 3: Dvě klávesy

Třetí příklad ukazuje, že je možné bez problému vyhodnotit i 2 klávesy, které jsou stisknuté současně.
Takto je možné některým klávesám přiřadit například funkci "Shift".

V prvním kroku se logická "0" z horního řádku přes sepnutou klávesu "R" přenese na sloupec "b7".

Ve druhém kroku se "0" z prostředního řádku přenese přes sepnutou klávesu "S" na sloupec "b5".

V posledním kroku se "0" nikam nepřenese, protože ve spodní řádce není stisknutá žádná klávesa. 

V tomto třetím příkladě získá počítač následující údaje:

číslo kroku krok 1 krok 2 krok 3
označení vstupu GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7
přečtená hodnota 1 1 1 0 1 0 1 1 1 1 1 1
význam není
"Q"
není
"W"
není
"E"
je
"R"
není
"A"
je
"S"
není
"D"
není
"F"
není
"Z"
není
"X"
není
"C"
není
"V"

 


Příklad 4: Více stisknutých kláves v jednom sloupci

Na čtvrtém příkladě se pokusím vysvětlit význam ochranných diod.

Tyto diody zabraňují zkratu, ke kterému by došlo v případě, že by bylo stisknuto několik kláves v jednom sloupci.

Pro příklad jsem si vymyslel stisknuté klávesy "E", "D" a "C"

V prvním kroku se "0" z horní řádky přenese přes stisknuté tlačítko "E" do sloupce "b6". Jenže ve sloupci "b6" je stisknuto zároveň tlačítko "D", které tu nulu přenese na prostřední řádku. Pokud by na prostřední řádce nebyla dioda, došlo by k tomu, že se expander bude snažit nastavit na výstupním pinu "b1" logickou "1" (+5V), ale zároveň by bylo toto napětí zkratováno na "0", která přichází z klávesnice. Díky diodě, která je pro tento případ orientována v závěrném směru, však ke zkratu nedojde.
Ta samá situace nastává i na výstupním pinu "b2" (kvůli stisknutému tlačítku "C", které přenáší logickou "0" ze sloupce "b6" na spodní řádku).

Ve druhém a třetím kroku se situace opakuje. Vzhledem k tomu, že jsou stisknuta všechna tlačítka ve sloupci "b6" dochází k přenášení nuly na zbylé dvě řádky. Diody na těchto řádkách pak brání zkratu.

Získané údaje:

číslo kroku krok 1 krok 2 krok 3
označení vstupu GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7
přečtená hodnota 1 1 0 1 1 1 0 1 1 1 0 1
význam není
"Q"
není
"W"
je
"E"
není
"R"
není
"A"
není
"S"
je
"D"
není
"F"
není
"Z"
není
"X"
je
"C"
není
"V"

 


Příklad 5: Chybná vyhodnocení při stisku více tlačítek 

V posledním příkladu ukážu hlavní nevýhodu maticového uspořádání klávesnice. Pokud je stisknuto více tlačítek zároveň, může v některých případech dojít k chybě při vyhodnocení.
Sice v praxi asi moc často nebude nastávat situace, kdy by byly stisknuty více než 2 klávesy zároveň, ale někdy se to stát může.

K tomuto chybnému vyhodnocení dochází tehdy, když některá ze stisknutých tlačítek tvoří pravoúhlý trojúhelník, jehož odvěsny kopírují směr řádek a sloupců. V tom případě počítač vyhodnotí, že je stisknuto ještě další tlačítko, které jakoby doplňuje pravoúhlý trojúhelník na obdélník, nebo čtverec.

Tady je několik příkladů:


Stisknuté tlačítko je zobrazeno šedou barvou.
Falešně vyhodnocené tlačítko je žluté.


A tady je rozkreslený příklad chybného vyhodnocení pro současně stisknuté klávesy "R", "S" a "F".

V prvním kroku se logická "0" přenese z horní řádky přes stisknutou klávesu "R" do sloupce "b7".
Protože je v tomto sloupci stisknuta zároveň klávesa "F", přenese se "0" i na prostřední řádku.
Jenže v prostřední řádce je zároveň stisknuta klávesa "S", která přenese "0" i na sloupec "b5". To je špatně.
Počítač si totiž bude myslet, že když má v prvním kroku na vstupním pinu "b5" logickou "0", tak to znamená stisknutou klávesu "W".
Ve skutečnosti ale klávesa "W" stisknutá není.

Druhý krok už je vyhodnocen správně. "0" z prostřední řádky se pomocí sepnutých kláves "S" a "F" přenese na piny "b5" a "b7".
Sice se na nulu nastaví i horní řádka (kvůli stisknuté klávese "R"), ale to už nemá na vyhodnocení stavu vliv.

Ve třetím kroku se nastaví na "0" spodní řádka, ale protože na ní není stisknutá žádná klávesa, zůstávají vstupy kvůli Pull-Up odporům ve stavu "1".

Takto vyhodnotí získané údaje počítač:

číslo kroku krok 1 krok 2 krok 3
označení vstupu GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7 GPB4 GPB5 GPB6 GPB7
přečtená hodnota 1 0 1 0 1 0 1 0 1 1 1 1
význam není
"Q"
je
"W"
není
"E"
je
"R"
není
"A"
je
"S"
není
"D"
je
"F"
není
"Z"
není
"X"
není
"C"
není
"V"

Klávesu "W" tedy počítač vyhodnotí jako stisknutou, i když ve skutečnosti stisknutá není.


Software

Zde je program v Pythonu, který čte a vyhodnocuje stav kláves na maticové klávesnici se 4x3 tlačítky, připojené k expanderu:

#!/usr/bin/python
import smbus
import time

bus = smbus.SMBus(0)) # starsi varianta RasPi (256MB)
#bus = smbus.SMBus(1) # novejsi varianta RasPi (512MB)

addr = 0x27                          # I2C adresa expanderu 
radka = ['QWER' , 'ASDF' , 'ZXCV']   # rozlozeni klaves na klavesnici

bus.write_byte_data(addr,0x01,0xF0)  # B-port: 0,1,2,3 = radky (OUT) ; 4,5,6,7 = sloupce (IN)
bus.write_byte_data(addr,0x0D,0xF0)  # Pripojeni vnitrnich Pull-Up odporu na bity 4,5,6,7 (na vstupy) 



# hlavni podprogram pro zjistovani aktualne stisknutych tlacitek
def cteni_klavesnice():
  indexradky = 0
  stisknuto = ""
  for r in [254 , 253 , 251]:                  # postupne se nastavi "0" na kazde ze tri radek
    bus.write_byte_data(addr,0x13,r)
    time.sleep(0.1)                            # pauza desetina sekundy na kazdou radku
    kodsloupce = bus.read_byte_data(addr,0x13) # precteni stavu portu (celeho, vcetne stavu radek)
    jenhornibity = (kodsloupce >> 4)           # zajimave jsou pouze horni 4 bity (vstupni)

    for s in range(0,4):                       # prochazeni 4 vstupnich bitu a hledani stavu "0"
      if (jenhornibity & 2**s) == False:       # prevod nulovych bitu na tlacitkovy znak
        stisknuto = stisknuto + radka[indexradky][s] 

    indexradky = indexradky + 1
  return stisknuto                             # vysledkem je retezec, ktery obsahuje seznam stisknutych klaves 


# a tady je hlavni smycka 
klavesy=""
while klavesy != "RZ":              # Kombinace klaves, pri kterych skonci program
  klavesy = cteni_klavesnice()
  if (klavesy != ""):
    print klavesy



úvodní strana webu AstroMiK.org

poslední úprava stránky 7.11.2012