[068] Arduino i klawiatura PC - cz. 1
Projektowanie różnego rodzaju urządzeń może mieć różne priorytety. Amatorzy będą się kierować przyjemnością, praktycy natomiast – temu, co w danym momencie jest najważniejsze. Życie pokazuje, że najczęściej są to koszty i czas, a w przypadku budowania dużej klawiatury obie te wartości są spore. Cena typowego panelu z pełną klawiaturą alfanumeryczną choćby w technice membranowej, przy ilości detalicznej to tysiące złotych. Tymczasem klawiatura komputerowa kosztuje kilkadziesiąt razy mniej, jest kompletna, każdy to umie obsługiwać i na pewno działa poprawnie.
Mimo, że od lat klawiatury pecetowe pracują już w standardzie USB, wersje ze złączem PS/2 wciąż są produkowane i dostępne. Do naszych dzisiejszych zabawa wybiorę taką właśnie klawiaturę, choć oczywiście wersja USB także będzie współpracować z Arduino, ale z nieco bardziej zaawansowanymi modelami, a z prostymi – po pewnych modyfikacjach drugiego mikrokontrolera znajdującego się na płytce, co dla początkujących niekoniecznie jest takie proste i na razie ten temat pozostawię sobie na później.
Klawiatury, zarówno w standardzie USB jak i PS/2, używają tylko czterech przewodów, co znakomicie ułatwia ich współpracę z systemami mikroprocesorowymi. Jeśli mowa o starszym standardzie, ten także początkowo używał dwóch rodzajów złącz – większego: DIN i mniejszego, zwanego PS/2. Różnice dotyczyły tylko mechaniki, sygnały były w stu procentach kompatybilne.
Do naszych zabaw będziemy potrzebowali tylko jednego elementu: gniazdka PS/2 z przewodami. Było one niegdyś dodawane obowiązkowo do płyt głównych. Ostatecznie można zawsze wtyczkę obciąć, przylutowując do przewodów goldpiny. Masę i zasilanie należy oczywiście dołączyć do masy i wyjścia +5V, które każda płytka Arduino pracująca w tym standardzie napięć oferuje. Linię danych należy podłączyć do dowolnego wyprowadzenia (użyłem ósmego), natomiast linię zegara – do 2 albo 3, ze względu na to, że biblioteka, o której zaraz opowiem, używa przerwań, a te w module Uno są dostępne tylko na tych dwóch portach. Zatem czy użyjemy najprostszego modułu: Nano, czy płytki edukacyjnej TME, nie będziemy potrzebować nawet jednego rezystora. I w tym tkwi prostota tego rozwiązania.
Przyjrzyjmy się teraz samej klawiaturze, choć wiedza, którą teraz w skrócie przedstawię, nie ma dla nas znaczenia, o ile nie zdecydujemy się na napisanie oprogramowania współpracującego z nią w całości na piechotę.
Urządzenie to posiada własny mikrokontroler, kompatybilny z prastarym układem Intela 8049. Jest to układ ośmiobitowy, ze skromną pamięcią programu równą 2 kB i wszystkimi peryferiami, które pozwalają zbudować dużą klawiaturę. Problemy mamy dwa: jeden, niewielki, ale łatwy do pokonania: klawiatura rozmawia w nieco mniej znormalizowanym narzeczu: szeregowo, synchronicznie, ale ze słowem jedenastobitowym, który zawiera także bit parzystości. Używając biblioteki, możemy się tym nie przejmować.
Drugi problem to słowa, którymi klawiatura się posługuje. O ile w pierwszej wersji, znanej z komputerów XT, był tam jeszcze jakiś porządek, w toku poprawek i usprawnień, reakcje przyciśnięcia bądź zwolnienia klawiszy zaczęły generować jeden, dwa, a nawet trzy bajty, do tego nie mające nic wspólnego z kodowaniem znaków w standardzie ASCII. Czas więc zabrać się za programowanie. Jak mówiłem, nie będziemy pisać procedury obsługi klawiatury na piechotę, choć byłoby to ciekawe ćwiczenie. Użyjemy praktycznej biblioteki, która nazywa się PS2Keyboard.h
#include <PS2Keyboard.h> // Biblioteka obsługi klawiatury PS/2
const byte PS2data = 8; // Adres linii DATA klawiatury.
const byte PS2clck = 3; // Adres linii CLCK klawiatury, dla wersji UNO może przyjmować wartość 2 lub 3
PS2Keyboard klawiatura; // Powołaj do życia obiekt o nazwie klawiatura.
void setup() {
Serial.begin(9600); // Inicjuj przesyłanie danych portem szeregowym.
klawiatura.begin(PS2data, PS2clck); // Deklaruj wejścia, do których podłączona jest klawiatura.
}
void loop() {
if (klawiatura.available()) { // Jeśli klawisz został wciśnięty, to...
Serial.println(klawiatura.read()); // Wyślij kod klawisza.
}
}
Zaraz po zaimportowaniu biblioteki należy zadeklarować linię danych i zegara. Biblioteka wymaga nazwania obiektu jakąś własną nazwą, naturalnie nasuwa się tutaj słowo: klawiatura. Kolejno należy zainicjować monitor, który wyświetli nam przychodzące kody z klawiatury. W końcu należy zadeklarować samą bibliotekę.
W głównej pętli dziać się będzie niewiele. Klawiatura.available sprawdza czy jakiś klawisz został wciśnięty. Jeśli tak się stało, klawiatura.read pobierze kod owego klawisza i wyśle go do monitora.
Możemy się już cieszyć konkretnym działaniem i w zasadzie to wystarczy, by zaprzęgnąć nasz fragment programu do jakiegoś większego zadania, interpretując odpowiednio wartości, które obecnie widzimy w okienku monitora. Trzeba jednak pamiętać, że klawisze będą generować powtarzalne, ale jednak użyteczne w ograniczonym stopniu wartości wyrażane liczbami. Tymczasem często potrzebujemy znaków zgodnych ze standardem ASCII, a nie jakichś cyferek, zupełnie człowiekowi obcych. Zobaczmy co w tej kwestii da się zrobić.
#include <PS2Keyboard.h> // Biblioteka obsługi klawiatury PS/2
const byte PS2data = 8; // Adres linii DATA klawiatury.
const byte PS2clck = 3; // Adres linii CLCK klawiatury, dla wersji UNO może przyjmować wartość 2 lub 3
PS2Keyboard klawiatura; // Powołaj do życia obiekt o nazwie klawiatura.
char wcisnieto; // Zmienna przechowująca znak wciśniętego klawisza.
void setup() {
Serial.begin(9600); // Inicjuj przesyłanie danych portem szeregowym.
klawiatura.begin(PS2data, PS2clck); // Deklaruj wejścia, do których podłączona jest klawiatura.
}
void loop() {
if (klawiatura.available()) { // Jeśli klawisz został wciśnięty, to...
wcisnieto = klawiatura.read(); // zapamiętaj jego kod w zmiennej wcisnieto.
Serial.print(wcisnieto); // Wyślij kod klawisza.
}
}
Program będzie podobny do poprzedniego. Zadeklarujemy sobie dodatkową zmienną znakową, którą nazwę wcisnieto. Teraz pobrane kody będziemy przekazywać bezpośrednio do niej i już niejako z automatu dostaniemy znane nam literki.
Wszystko działa w przypadku wciskania kolejnych liter, cyfr i znaków specjalnych. Jednak próby wciskania klawiszy związanych z nawigacją nic nie dają oprócz wstawiania spacji i to nie za każdym razem. Okazuje się, że te klawisze także dają swoje kody, ale char nie potrafi ich zaczarować w nic konkretnego. Czy da się coś z tym zrobić? O tym napiszę w kolejnym artykule.