1
Politechnika Lubelska
Wydział Elektrotechniki i
Informatyki
Laboratorium Układów Mikroprocesorowych
Temat : Obsługa klawiatury matrycowej oraz wyświetlacza
LCD
Keller Jacek
Motycz Leśny dn. 09.12.2007
2
Cel ćwiczenia
Celem ćwiczenia była obsługa za pomocą mikrokontrolera AVR (ATMEGA32) klawiatury
matrycowej 4x4 oraz wyświetlacza LCD 2x16 w języku C.
Obsługa klawiatury
Sposób podłączenia klawiatury do mikrokontrolera:
Dokładny port, do którego jest podłączona klawiatura został zdefiniowany w programie:
#define klawiatura PORTA
#define klawiatura_DDR DDRA
#define klawiatura_PIN PINA
Obsługa klawiatury polega na wystawieniu stanu logicznego L na danej kolumnie (na
pozostałe kolumny i wiersze są skonfigurowane jako wejścia) a następnie odczytywaniu na
którym z wierszy pojawi się stan L spowodowanym przyciśnięciem jednego z przycisków w
kolumnie. Tym sposobem sterowane są pozostałe trzy kolumny.
Realizacja programowa została dokonana za pomocą konstrukcji typu switch.
Wykrywanie wciśniętych dwóch lub więcej przycisków (nie w jednym wierszu) odbywa się
poprzez sprawdzenie warunku czy w danym wierszu występuje więcej niż jeden stan L przy
jednoczesnym wyzwoleniu stanu L na wszystkich kolumnach. Jeżeli tak jest tzn. że wciśnięto
więcej niż jeden przycisk.
Sprawdzanie czy w wierszu zostały wciśnięte dwa lub więcej przyciski odbywa się na
zasadzie sprawdzenia czy wystąpił warunek odpowiadający naciśniętemu jednemu z czterech
przycisków lub nie wciśniętemu żadnemu. Jeżeli jeden z powyższych stanów nie wystąpił tzn.
ż
e wciśnięto więcej niż jeden przycisk w wierszu. W takich przypadkach funkcja
sprawdzająca stan klawiatury zwraca wartość 0xff.
3
int key(void)
{
klawiatura_DDR=0b00001111;
klawiatura=0b11110000;
// sprawdzenie czy dwa lub wiecej wcisniete
//(nie dotyczy sprawdzenia w jednym wierszu)
if ((klawiatura_PIN!=0b11100000 )&& (klawiatura_PIN!=0b11010000) &&
(klawiatura_PIN!=0b10110000) && (klawiatura_PIN!=0b01110000) &&
(klawiatura_PIN!=0b11110000)) return 0xff; //czyli wcisnieto ponad dwa
klawiatura_DDR=0b0001000; //zeby nie bylo zwarcia w momenie wcieniecia klawiszy w
//tym samym wierszu
klawiatura=0b11110111;
//kolumna1 11110111
switch(klawiatura_PIN)
{
case 0b11100111
: return 'C'; break;
// kolumna 1, wiersz 4
case 0b11010111
: return '8'; break;
// kolumna 1, wiresz 3
case 0b10110111
: return '4'; break;
// kolumna 1, wiersz 2
case 0b01110111
: return '0'; break;
// kolumna 1, wiersz 1
case 0b11110111
: break;
// nic nie wcisnieto
default : return 0xff; //inna wartosc tzn ze wcisniete
//dwa lub wiecej w wierszu
}
klawiatura_DDR=0b0000100;
klawiatura=0b11111011;
//kolumna2
switch(klawiatura_PIN)
{
case 0b11101011 : return 'D'; break;
// kolumna 2, wiersz 4
case 0b11011011
: return '9'; break;
// kolumna 2, wiersz 3
case 0b10111011
: return '5'; break;
// kolumna 2, wiersz 2
case 0b01111011
: return '1'; break;
// kolumna 2, wiersz 1
case 0b11111011
: break;
// nic nie wcisnieto
default : return 0xff;
}
klawiatura_DDR=0b0000010;
klawiatura=0b11111101;
//kolumna3
switch(klawiatura_PIN)
{
case 0b11101101
: return 'E'; break;
// kolumna 3, wiersz 4
case 0b11011101
: return 'A'; break;
// kolumna 3, wiersz 3
case 0b10111101
: return '6'; break;
// kolumna 3, wiersz 2
case 0b01111101
: return '2'; break;
// kolumna 3, wiersz 1
case 0b11111101
: break;
// nic nie wcisnieto
default : return 0xff;
}
klawiatura_DDR=0b0000001;
klawiatura=0b11111110;
//kolumna4
switch(klawiatura_PIN)
{
case 0b11101110
: return 'F'; break;
// kolumna 4, wiersz 4
case 0b11011110
: return 'B'; break;
// kolumna 4, wiersz 3
case 0b10111110
: return '7'; break;
// kolumna 4, wiersz 2
case 0b01111110
: return '3'; break;
// kolumna 4, wiersz 1
case 0b11111110
: break;
// nic nie wcisnieto
default : return 0xff;
}
return 0x00;
}
4
Należy zauważyć, że aby wyeliminować możliwość zwarcia w porcie (stan w którym
przyciśnięte są dwa przyciski w jednym wierszu, czyli zwarcie dwóch kolumn gdzie na jednej
kolumnie jest stan H a natomiast na drugiej stan L) trzeba określić aby stan H na kolumnach
był wymuszany nie poprzez wewnętrzny przerzutnik D zawarty w strukturze portu (sterowany
sygnałem WPx) a poprzez wewnętrzny rezystor podciągający do zasilania, w tym momencie
rezystor ogranicza płynący prąd
Stan ten osiągamy, gdy na wyjściu przerzutnika D sterowanego linią WDx jest stan L a na
wyjściu przerzutnika D sterowanego sygnałem WPx będzie panował stan H (dodatkowo bit
PUD (sterowany z rejestru SFIOR) powinien mieć wartość L. Czyli wszystkie bity portu do
którego podłączona jest klawiatura powinny być skonfigurowane jako wejścia a do bitów ich
rejestru wyjściowego powinny być wpisane stany H oprócz bitu na którym będzie
wystawiany stan L:
klawiatura_DDR=0b0001000; //zeby nie bylo zwarcia w momenie wcieniecia klawiszy w
//tym samym wierszu
klawiatura=0b11110111;
//kolumna1 11110111
Sytuację wyjaśnia schemat struktury portu noty katalogowej ATMEGA32:
5
Obsługa wyświetlacza LCD
Wyświetlacz LCD pracuje trybie 4 bitowym. Najstarsze 4 bity zostały podłączone do
najstarszych czterech bitów portu mikrokontrolera, który jest zdefiniowany jako LED_H w
programie:
#define EN 1 //jako bit1 portu gdzie podlaczono LCD_H
#define RS 0 //jako bit0 portu gdzie podlaczono LCD_H
#define LCD_H PORTD
#define LCD_H_DDR DDR
Sygnały EN oraz RS zostały zdefiniowane jako podłączone do tego samego portu tylko, że
dwóch najmniej znaczących bitów.
Sterowanie zapisem do LCD odbywa się za pomocą bitów EN (Enable) oraz RS (Register
Select) oraz starszej części LED_H, która pracuje jako magistrala dla LCD.
Dokładny sposób sterowania opisują przebiegi czasowe opisane w dokumentacji sterownika
HD44780:
Taki sposób sterowania wymaga aby zmieniać tylko bity portu do którego jest podłączony
LCD nie naruszając jego pozostałej części. Ten problem został rozwiązany poprzez
maskowanie portu.
void LCD_zapis(char dana)
{ SET_EN;
LCD_H = ((LCD_H & 0b00001111) | (dana & 0b11110000)); // zapis pierwszej
//połówki bajtu
CLR_EN;
SET_EN;
LCD_H = ((LCD_H & 0b00001111) | ((dana & 0b00001111) << 4)); // 2 połówka
CLR_EN;
delay(1);
}
6
Instrukcje sterujące bitami EN oraz RS zostały zdefiniowane jako SET_EN, CLR_EN,
SET_RS, CLR_RS dla większej przejrzystości programu:
#define SET_EN LCD_H = LCD_H | (1 << EN)
#define CLR_EN LCD_H = LCD_H & ~(1 << EN)
#define SET_RS LCD_H = LCD_H | (1 << RS)
#define CLR_RS LCD_H = LCD_H & ~(1 << RS)
Zapis instrukcji oraz danych odbywa się poprzez procedury sterujące bitem RS a następnie
odwołaniu do procedury bezpośredniego zapisu do LCD (LCD_zapis):
void LCD_instr(char dana)
{ CLR_RS;
LCD_zapis(dana);
}
void LCD_dana(char dana)
{ SET_RS;
LCD_zapis(dana);
}
Inicjalizacja wyświetlacza LCD odbywa się za pomocą wysłania sekwencji instrukcji do
niego zgodnych z zaleceniami z datasheet sterownika HD44780 (oczywiście pomijane jest
sprawdzanie flagi BF (Busy Flag), w zastępstwie zastosowano procedurę czekania
określonego czasu:
7
Działanie programu.
W pętli głównej konstrukcja switch wywołuje funkcję sprawdzającą stan klawiszy i na tej
podstawie zapala na diodach LED kod binarny odpowiadający wciśniętemu przyciskowi a
następnie wyświetla na wyświetlaczu LCD jaki klawisz został naciśnięty.
W przypadku wciśnięcia więcej niż jednego klawisza zapalają się wszystkie diody a na LCD
zostaje wyświetlona stosowna informacja.
W czasie gdy żaden z przycisków nie jest wciśnięty diody są wygaszone, natomiast na LCD
wyświetlony jest komunikat aby nacisnąć przycisk:
while (1)
{
switch(key())
{
case '0' : {LED=0; LCD_text_WCISNIETO(); LCD_text("0");LCD_spacje();} break;
case '1' : {LED=1; LCD_text_WCISNIETO(); LCD_text("1");LCD_spacje();} break;
case '2' : {LED=2; LCD_text_WCISNIETO(); LCD_text("2");LCD_spacje();} break;
case '3' : {LED=3; LCD_text_WCISNIETO(); LCD_text("3");LCD_spacje();} break;
case '4' : {LED=4; LCD_text_WCISNIETO(); LCD_text("4");LCD_spacje();} break;
case '5' : {LED=5; LCD_text_WCISNIETO(); LCD_text("5");LCD_spacje();} break;
case '6' : {LED=6; LCD_text_WCISNIETO(); LCD_text("6");LCD_spacje();} break;
case '7' : {LED=7; LCD_text_WCISNIETO(); LCD_text("7");LCD_spacje();} break;
case '8' : {LED=8; LCD_text_WCISNIETO(); LCD_text("8");LCD_spacje();} break;
case '9' : {LED=9; LCD_text_WCISNIETO(); LCD_text("9");LCD_spacje();} break;
case 'A' : {LED=10; LCD_text_WCISNIETO(); LCD_text("A");LCD_spacje();} break;
case 'B' : {LED=11; LCD_text_WCISNIETO(); LCD_text("B");LCD_spacje();} break;
case 'C' : {LED=12; LCD_text_WCISNIETO(); LCD_text("C");LCD_spacje();} break;
case 'D' : {LED=13; LCD_text_WCISNIETO(); LCD_text("D");LCD_spacje();} break;
case 'E' : {LED=14; LCD_text_WCISNIETO(); LCD_text("E");LCD_spacje();} break;
case 'F' : {LED=15; LCD_text_WCISNIETO(); LCD_text("F");LCD_spacje();} break;
case 0xff :{LED=255;LCD_text_WCISNIETO(); LCD_text("wiecej");} break;
case 0x00 :{LED=0; LCD_instr(0b00000010); LCD_text("Wcisnij cos ");} break;
}
}
void LCD_spacje(void)
{ LCD_text(" ");}
void LCD_text_WCISNIETO(void)
{ LCD_instr(0b00000010); LCD_text("Wcisnieto ");}