Reklama

Základy ovládání mikrokontroléru ATmega(16/32) 17.díl – Obsluha maticové klávesnice

Úvod

V tomto příspěvku se podíváme na to, jak zapojit a obsluhovat maticovou klávesnici. Zpracování stisknutí klávesy na maticové klávesnici patří k základům práce s mikrokontroléry. Pro demonstraci principu obsluhy klávesnice je využita klasická klávesnice 4×3, která obsahuje číslice 0 – 9 a poté dva znaky “*” a “#”.

Popis

Pokud bychom používali ke snímaní každého tlačítka jeden pin mikrokontroléru, tak bychom jich potřebovali dvanáct. To může být někdy nepoužitelné. Proto se používá maticové zapojení jednotlivých kláves, viz Obr. 1.

Obr. 1: Maticové zapojení klávesnice

Obr. 1: Maticové zapojení klávesnice

Na Obr. 1 lze vidět, že jednotlivé klávesy jsou rozmístěny do čtyř řad a třech sloupců. Pro toto rozložení jednotlivých kláves potřebujeme sedm pinů mikrokontroléru. Tím ušetříme pět pinů mikrokontroléru a pro klávesnici 4×4 bychom ušetřili osm pinů mikrokontroléru.

 

Princip funkce snímaní je velmi jednoduchý. Piny mikrokontroléru, které budou připojeny na jednotlivé řádky (P3 – P6), nastavíme jako vstupní a také jim zapneme vnitřní “pull-up” rezistory. Pokud chcete, můžete připojit i externí “pull-up” rezistory. Naopak piny mikrokontroléru, které jsou připojeny na jednotlivé sloupce (P0 – P2), nastavíme jako výstupní. Vždy pouze na jeden výstupní pin mikrokontroléru, kde je připojen jeden ze sloupců, nastavíme stav log. 0, zatímco na ostatních nastavíme stav log. 1. Poté snímáme jednotlivé řádky, jestli některý z nich neobsahuje stav log. 0, což by znamenalo stisknutou klávesu, protože v normálním stavu obsahují stav log. 1 díky interním, nebo externím “pull-up” rezistorům. Jako první začneme u prvního sloupce, pak u druhého atd. Tuto obsluhu klávesnice provádíme neustále dokola. Tímto stylem jsme schopni vždy jednoznačně identifikovat stisknutou klávesu. Princip funkce ukazuje jednoduchá animace na Obr. 2.

Obr. 2: Animaci stisknutí některých kláves

Obr. 2: Animaci stisknutí některých kláves

Samozřejmě je nutné ošetřit zákmity stejně jako u klasického tlačítka. Jeden z předchozích dílů se věnoval pouze této problematice a lze ho nalézt ZDE. Stejně jako u tlačítka jsem zvolil metodu krátkého zdržení cca 150 ms, jak při stisknutí tlačítka, tak při uvolnění tlačítka.

Princip snímaní klávesnice si ukážeme na jednoduchém příkladu kódového zámku. Vzorové zapojení obsahuje klávesnici, dvě LED diody a dvouřádkový LCD displej, viz Obr. 3.

Obr. 3: Elektronické schéma zapojení

Obr. 3: Elektronické schéma zapojení

Popis, jak pracovat s tímto LCD displejem, lze nalézt ZDE. Úkolem programu bude měnit stav dvou LED diod, které symbolizují stavy “Aktivován alarm” a “Deaktivován alarm”. Po zadání čtyřmístného kódu se zkontroluje, zda se jedná o správné heslo. Pokud ano, tak se zobrazí na LCD displeji informace o tom, že zadané heslo je správné a změní se stav obou LED diod. V opačném případě je zobrazena pouze informace o špatně vloženém heslu.
 
K obsluze klávesnice slouží funkce “ScanKeyPad”, která v případě stisknuté klávesy vrátí číslo, které bylo stisknuto. Pro klávesu “*” funkce vrátí hodnotu 10 a pro klávesu “#” je vrácena hodnota 11. V případě stisknutí více kláves pro daný sloupec najednou nebo v případě nestisknuté žádné klávesy funkce vrátí hodnotu 255. Po přečtení celé klávesnice jsou kontrolovány všechny načtené hodnoty z jednotlivých sloupců. Pro korektní vyhodnocení stisknuté klávesy musí být vždy pouze jedna hodnota jiná než 255. V jiném případě se jedná opět o stav, kdy bylo více stisknutých kláves najednou. Metod pro ošetření chybových stavů, zákmitů atd. existuje obrovské množství, takže tento způsob je pouze ukázka jedné z mnoha možností. Dále lze samozřejmě zdrojový kód vylepšit o mazání špatně zadané číslice, potvrzení celého hesla, přidání dalších součástek apod. Vytvořený zdrojový kód je pouze demonstračním příkladem kódového zámku.

Okomentovaný zdrojový kód
 

001: #define F_CPU 16000000UL// frekvence hodinoveho signalu (nutné pro delay.h)
002: #include <avr/io.h> // knihovna AVR pro Input/output
003: #include <util/delay.h>// hlavickovy soubor pro zpozdeni
004: #include <stdio.h> // hlavickovy soubor pro standardni IO operace
005:
006: #include "lcd.h"// hlavickovy soubor pro LCD display
007:
008: // prototyp funkce
009: uint8_t ScanKeyPad(uint8_t row);
010:
011: char cNum[5];// pole pro 4 znakovy kod
012: char codeResult[20];// pole pro vypis vysledku
013:
014: uint8_t currentColumn = 1;// aktualni sloupec
015: uint8_t indexNumber = 0;// aktlualni index cisla 0–3
016: uint8_t c1Number = 255;// cislo sloupce 1
017: uint8_t c2Number = 255;// cislo sloupce 2
018: uint8_t c3Number = 255;// cislo sloupce 3
019:
020: // definice ciselneho kodu
021: uint8_t codeN1 = 1;
022: uint8_t codeN2 = 2;
023: uint8_t codeN3 = 3;
024: uint8_t codeN4 = 4;
025:
026: uint8_t state = 0;// aktualni stav zamku
027: uint8_t keyPushed = 0;// informace o stisknutem tlacitku
028:
029: int main(void)
030: {
031: DDRC = 0b00000111;// (PC0–PC2 vystup), (PC3–PC6 vstup)
032: PORTC = 0b11111111;
033: DDRB = 0xFF;
034: PORTB = 0b11111110;// PB0–zel. LED, PB1–cer. LED
035:
036: lcd_init(LCD_DISP_ON);// nastaveni LCD
037: lcd_clrscr(); // Smazani LCD displeje
038: lcd_gotoxy(0,0);// Nastaveni kurzoru na pozici x0, y0
039: lcd_puts("www.tajned.cz");
040: lcd_gotoxy(0,1);// Nastaveni kurzoru na pozici x0, y1
041: lcd_puts("PASSWORD:");
042:
043: while(1)
044: {
045: if (currentColumn < 4)
046: {
047: switch (currentColumn)// vyber sloupce
048: {
049: case 1:
050: c1Number = ScanKeyPad(currentColumn);
051: break;
052:
053: case 2:
054: c2Number = ScanKeyPad(currentColumn);
055: break;
056:
057: case 3:
058: c3Number = ScanKeyPad(currentColumn);
059: break;
060:
061: default:
062: currentColumn = 1;// nastaveni prvniho sloupce
063: break;
064: }
065:
066: currentColumn++;
067: }
068: else
069: {
070: if (keyPushed == 1)// cekani na pusteni vsech tlacitek
071: {
072: if ((c1Number == 255) && (c2Number == 255) && (c3Number == 255))
073: {
074: keyPushed = 0;
075: _delay_ms(150);
076: }
077: }
078: else// kontrola stisknuti vsech tlacitek
079: {
080: if (c1Number != 255)
081: {
082: if ((c1Number != 10) && (c2Number == 255) && (c3Number == 255))
083: {
084: keyPushed = 1;
085: cNum[indexNumber] = c1Number;
086: }
087: }
088: else if (c2Number != 255)
089: {
090: if ((c1Number == 255) && (c3Number == 255))
091: {
092: keyPushed = 1;
093: cNum[indexNumber] = c2Number;
094: }
095: }
096: else if (c3Number != 255)
097: {
098: if ((c2Number == 255) && (c1Number == 255) && (c3Number != 11))
099: {
100: keyPushed = 1;
101: cNum[indexNumber] = c3Number;
102: }
103: }
104: else
105: {
106: keyPushed = 0;
107: }
108:
109: if (keyPushed == 1)// bylo vyhodnoceno korektni stisknuti tlacitka
110: {
111: // Nastavit pozici kurzoru na pozici x10, y1
112: lcd_gotoxy(10+indexNumber,1);
113: lcd_putc(‘*’);// Zapsat znak ‘*’
114: indexNumber++;
115: _delay_ms(150);
116: }
117: }
118:
119: currentColumn = 1;// nastaveni prvniho sloupce
120: }
121:
122: if (indexNumber >= 4)// pokud byl zadan cely kod
123: {
124: if ((cNum[0] == codeN1) && (cNum[1] == codeN2) &&
125: (cNum[2] ==codeN3) && (cNum[3] == codeN4))
126: {
127: if (state == 0)// Deaktivovano
128: {
129: PORTB = 0b11111101;// zel. LED–ON
130: state = 1;
131: }
132: else// Aktivovano
133: {
134: PORTB = 0b11111110;// cer. LED–ON
135: state = 0;
136: }
137:
138:
139: lcd_gotoxy(0,1);
140: lcd_puts("PASSWORD: OK ");
141: _delay_ms(1000);
142: }
143: else
144: {
145:
146: lcd_gotoxy(0,1);
147: lcd_puts("PASSWORD: ERROR");
148: _delay_ms(1000);
149: }
150:
151: for (int i = 0; i < 4; i++)
152: {
153: cNum[i] = 0;
154: }
155:
156: indexNumber = 0;
157:
158:
159: lcd_gotoxy(0,1);
160: lcd_puts("PASSWORD: ");
161: }
162: }
163: return 0;
164: }
165: // obsluha jednotlivych sloupcu
166: uint8_t ScanKeyPad(uint8_t column)
167: {
168: uint8_t result = 0;
169: uint8_t inputState = 0;
170:
171: if (column == 1)
172: {
173: PORTC &= 0b11111110;// nastavit log. 0 pro 1. sloupec
174: PORTC |= 0b00000110;// nastavit log. 1 pro 2. a 3. sloupec
175:
176: _delay_ms(1);
177:
178: inputState = ((PINC & 0b01111000) >> 3);
179:
180: switch (inputState)
181: {
182: case 0b00000111:// *
183: result = 10;
184: break;
185:
186: case 0b00001011:// 7
187: result = 7;
188: break;
189:
190: case 0b00001101:// 4
191: result = 4;
192: break;
193:
194: case 0b00001110:// 1
195: result = 1;
196: break;
197:
198: default:// zadny stisk, nebo mnohonasobny stisk
199: result = 255;
200: break;
201: }
202: }
203: else if (column == 2)
204: {
205:
206: PORTC &= 0b11111101;// nastavit log. 0 pro 2. sloupec
207: PORTC |= 0b00000101;// nastavit log. 1 pro 1. a 3. sloupec
208:
209: _delay_ms(1);
210:
211: inputState = ((PINC & 0b01111000) >> 3);
212:
213: switch (inputState)
214: {
215: case 0b00000111:// 0
216: result = 0;
217: break;
218:
219: case 0b00001011:// 8
220: result = 8;
221: break;
222:
223: case 0b00001101:// 5
224: result = 5;
225: break;
226:
227: case 0b00001110:// 2
228: result = 2;
229: break;
230:
231: default:// zadny stisk, nebo mnohonasobny stisk
232: result = 255;
233: break;
234: }
235: }
236: else if (column == 3)
237: {
238: PORTC &= 0b11111011;// nastavit log. 0 pro 3. sloupec
239: PORTC |= 0b00000011;// nastavit log. 1 pro 1. a 2. sloupec
240:
241: _delay_ms(1);
242:
243: inputState = ((PINC & 0b01111000) >> 3);
244:
245: switch (inputState)
246: {
247: case 0b00000111:// #
248: result = 11;
249: break;
250:
251: case 0b00001011:// 9
252: result = 9;
253: break;
254:
255: case 0b00001101:// 6
256: result = 6;
257: break;
258:
259: case 0b00001110:// 3
260: result = 3;
261: break;
262:
263: default:// zadny stisk, nebo mnohonasobny stisk
264: result = 255;
265: break;
266: }
267: }
268: else
269: {
270: PORTC |= 0b00000111;// nastavit log. 1 pro 1., 2. a 3. sloupec
271: inputState = 0b00001111;
272: result = 255;
273: }
274:
275: return result;
276: }

Vzorové zdrojové kódy slouží pouze k jednoduché demonstraci funkce, proto často obsahují globální proměnné, neobsahují většinou ukazatele, dále také neobsahují kontroly proměnných, definování nevyužitých pinů mikrokontroléru a podobné správné programátorské návyky. Proto je nutné tyto kódy brát s patřičnou rezervou.
 
Video s ukázkou funkce

 
[wpvp_flowplayer src=http://www.tajned.cz/wp-content/uploads/2015/04/video_AVR17.mp4 width=640 height=480 splash=http://www.tajned.cz/wp-content/uploads/2015/04/im_video1.png]

 
Aktualizace: 27.1.2016

Jiné příspěvky v kategorii:

Základy ovládání mikrokontroléru ATmega(16/32) 1.díl – První kroky

Základy ovládání mikrokontroléru ATmega(16/32) 2. díl – Kompilace a krokování programu

Základy ovládání mikrokontroléru ATmega(16/32) 3.díl – Nahrání vytvořeného zdrojového kódu do mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 4.díl – Ovládání vstupně/výstupních portů

Základy ovládání mikrokontroléru ATmega(16/32) 5.díl – Ošetření zákmitů na vstupním pinu mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 6.díl – Externí přerušení

Základy ovládání mikrokontroléru ATmega(16/32) 7. díl – Jednoduchá elektronická hrací kostka

Základy ovládání mikrokontroléru ATmega(16/32) 8.díl – A/D převodník (1.část)

Základy ovládání mikrokontroléru ATmega(16/32) 9.díl – A/D převodník (2.část)

Základy ovládání mikrokontroléru ATmega(16/32) 10.díl – A/D převodník (3.část)

Základy ovládání mikrokontroléru ATmega(16/32) 11.díl – Čítač / Časovač (1.část – Základní popis)

Základy ovládání mikrokontroléru ATmega(16/32) 12.díl – Čítač / Časovač (2.část – Popis registrů)

Základy ovládání mikrokontroléru ATmega(16/32) 13.díl – Čítač / Časovač (3.část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 14.díl – Dvouřádkový LCD displej

Základy ovládání mikrokontroléru ATmega(16/32) 15.díl – Popis implementace komunikace I2C a EEPROM paměti 24LC512

Základy ovládání mikrokontroléru ATmega(16/32) 16.díl – Watchdog

Základy ovládání mikrokontroléru ATmega(16/32) 18.díl – Jednotka USART (1. část – Popis)

Základy ovládání mikrokontroléru ATmega(16/32) 19.díl – Jednotka USART (2. část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 20. díl – Generování audio signálu pomocí PWM

Základy ovládání mikrokontroléru ATmega(16/32) 21. díl – Analogový komparátor

Základy ovládání mikrokontroléru ATmega(16/32) 22. díl – Krokování programu v jazyce symbolických adres (JSA)
 
Tajned facebook
 

Za případné chyby v textu, ve zdrojovém kódě, nebo ve schématickém zapojení se omlouváme.
AUTOŘI NEBEROU ŽÁDNOU ODPOVĚDNOST ZA PŘÍPADNÉ ÚJMY NA ZDRAVÍ ČI MAJETKU.