STM32Butterfly2: obsługa klawiatury matrycowej i graficznego LCD
W pierwszym kroku wykonywana jest funkcja time_init(), odpowiada ona za skonfigurowanie licznika SysTick. Sprowadza się ona do skonfigurowania priorytetu przerwania, określenia częstotliwości występowania oraz włączenia przerwania. Natomiast w samym przerwaniu realizowana jest jedynie inkrementacja wartości zmiennej wykorzystywanej do określenia opóźnień w programie.
W następnym kroku realizowana jest konfiguracja podłączonego wyświetlacza (moduł KAmodLCD1). Funkcja ta w pierwszej kolejności włącza zegary dla używanych peryferii (porty GPIO oraz SPI), następnie konfiguruje używane linie oraz ustawia i włącza magistralę SPI. Po tych czynności wysyła dane przy wykorzystaniu magistrali SPI do wyświetlacza w celu jego inicjalizacji i wstępnej konfiguracji.
Następnym krokiem jest wywołanie funkcji keyscan_init(), odpowiedzialnej za konfigurację linii, do których podłączona jest klawiatura matrycowa. Listing tej funkcji został przedstawiony poniżej.
static void keyscan_init(void) { RCC->APB2ENR |= RCC_APB2Periph_GPIOE; //Input push pull +GND io_config_ext( KEYSCAN_PORT, KEYSCAN_COL_PINS, GPIO_MODE_INPUT, GPIO_CNF_IN_PULLUP ); io_clr_mask(KEYSCAN_PORT, KEYSCAN_COL_PINS); //Output row to zero io_config_ext( KEYSCAN_PORT, KEYSCAN_ROW_PINS, GPIO_MODE_10MHZ, GPIO_CNF_GPIO_PP ); io_clr_mask(KEYSCAN_PORT, KEYSCAN_ROW_PINS); }
W pierwszej kolejności funkcja uruchamia zegar dla portu GPIO, do którego podłączana jest klawiatura. Następnie przeprowadzana jest konfiguracja linii podłączonych do kolumn klawiatury (PE0, PE1, PE2 i PE3), linie te są konfigurowane jako wejścia. Natomiast następne polecenie – io_clr_mask(KEYSCAN_PORT, KEYSCAN_COL_PINS) – powoduje, że powyższe linie zostają podciągnięte przez rezystor do masy. Kolejne polecenia konfigurują linie podłączone do wierszy (PE4, PE5, PE6 i PE7) klawiatury matrycowej. Najpierw realizowana jest konfiguracja linii jako
wyjścia symetryczne (push – pull), natomiast polecenie io_clr_mask(KEYSCAN_PORT, KEYSCAN_ROW_PINS) powoduje ustawienie stanu niskiego na liniach.
Po przeprowadzaniu konfiguracji linii podłączonych do klawiatury matrycowej, przy użyciu polecenia nlcd_put_string program główny wyświetla na wyświetlaczu komunikat powitalny. Po czym przechodzi to nieskończonej pętli for, w której przez funkcję keyscan_get() sprawdzane jest czy został wciśnięty klawisz. W przypadku wciśnięcia klawisza funkcja zwraca jego kod, w innym przypadku zwracana jest wartość 0. Wyświetlenie kodu wciśniętego klawisza odbywa się przez wstępne sprawdzenie czy wartość zmiennej jest większa od 0. W przypadku spełnienia warunku program przy użyciu funkcji nlcd_set_position(6,2) ustawia pozycję kursora na wyświetlaczu, a następnie funkcja nlcd_put_char(key) wyświetla kod wciśniętego klawisza.
Budowa klawiatury matrycowej jest bardzo prosta. Składa się ona z linii określanych jako wiersze oraz linii określonych jako kolumny (nazewnictwo wynika z fizycznej budowy klawiatury), drugim elementem są mechaniczne przyciski zwierające ze sobą poszczególne wiersze i kolumny. Budowa klawiatury matrycowej determinuje sposób działania programu wykrywającego wciśnięcia klawisza. Działanie to polega na sprawdzaniu stanu na liniach poszczególnych kolumnach, przy przemiennym zmienianiu potencjału linii wierszy – ustawiając konkretny wiersz w stan wysoki szukamy na której linii kolumny występuje stan wysoki (pozostałe linie wierszy powinny mieć ustawiony stan niski). Linie wierszy i kolumn oczywiście mogą zostać zamienione.
Za wykrywanie wciśnięcia klawisza, jak zostało to wspomniane powyżej, odpowiada funkcja keyscan_get(), listing jej został przedstawiony poniżej.
static key_t keyscan_get(void) { static tick_t pscan_time; static int row = KEYSCAN_FIRST_ROW; static bool check_col = false; key_t key = 0; if(timer_elapsed(pscan_time,check_col?KEY_CHECK_INTERVAL:KEY_SCAN_INTERVAL)) { if(!check_col) { io_set_clr_mask(KEYSCAN_PORT, row, KEYSCAN_ROW_PINS); } else { int col = io_get_mask(KEYSCAN_PORT, KEYSCAN_COL_PINS); if(col>0) { key = key_translate(row, col); } if(row<=KEYSCAN_LAST_ROW) row<<=1; else row=KEYSCAN_FIRST_ROW; } check_col = !check_col; pscan_time = read_tick(); } return key; }
W pierwszym kroku mamy zdefiniowane zmienne, część z nich posiada modyfikator static, powoduje on, iż te zmienne nie tracą swojej wartości po zakończeniu działania funkcji. Po definicji mamy sprawdzanie warunku służącego do wprowadzenia opóźnienia w skanowaniu klawiatury. Na pierwszy rzut oka warunek wydaje się bardzo skomplikowany, jednak w rzeczywistości sprowadza się do porównania pierwszej zmiennej (pscan_time) względem drugiej, która może przyjmować jedną z dwóch wartości, która zależy od tego czy aktualnie ma wystąpić próbkowanie czy przełączenie stanów linii wyjściowych mikrokontrolera (określa to wartość zmiennej check_col). Zmienna check_col jak i zmienna check_col są aktualizowane na samym końcu funkcji.
W przypadku braku spełnienia powyższego warunku funkcja zwraca wartość 0 (w wyniku braku modyfikacji zmiennej key). Jeśli warunek został spełniony realizowane jest sprawdzanie kolejnego warunku – key. Warunek ten jest spełniony jeśli zmienna posiada wartość false. W takim przypadku realizowany jest proces zmiany stanów linii wierszy, odpowiada za to polecenie io_set_clr_mask(KEYSCAN_PORT, row, KEYSCAN_ROW_PINS). Jako pierwszy parametr podawany jest port, do którego podłączone są linie wierszy, ostatni parametr stanowi maskę blokującą wprowadzanie zmian na linia, które nie powinny być modyfikowane. Szczególną uwagę należy zwrócić na parametr drugi, który ustawia odpowiednie stany na liniach – odpowiada za to zmienna row (zmienna ta modyfikowana jest w dalszej części funkcji).