- Audio (2)
- Codes Scratches (4)
- Elektronika (23)
- Inteligentny dom (1)
- IT (9)
- Mikrokontrolery / Arduino (6)
Klawiatura numeryczna z wyjściem szeregowym lub spi
Tym razem mała odskocznia od teoretycznego cyklu opisującego budowę „cyfrowego zasilacza” i coś bardziej praktycznego. Choć kto wie? Może nie do końca niezwiązanego z tamtymi artykułami 😉
Dzisiaj chcę Wam przedstawić mini projekt klawiaturki numerycznej wyposażonej w wyjście szeregowe, które można bezpośrednio podłączyć do UARTu mikrokontrolera (u mnie były to np. Atmega8 i Atmega32).
Jak to działa?
Jest to typowa klawiaturka numeryczna 0-9 dodatkowo wyposażona w 4 przyciski funkcyjne (a,b,c,d), zasilana z 5V DC, z wyjściem szeregowym (9600 boud rate) lub spi. Przyciski w celu zaoszczędzenia pinów kontrolera są ułożone w macierz, tzn. wszystkie przyciski w danej kolumnie są połączone i wszystkie w danym wierszu również. Poniżej schemat takiego połączenia:
Następnie program zapisany w mikrokontrolerze (ja użyłem AT90S2313, jednak może to być cokolwiek innego rodziny avr np. jakaś atmega) „skanuje” taką macierz w poszukiwaniu zwartych styków. Odbywa się to w następujący sposób:
Wiersze od góry są podpięte do portów PD6, PB0, PB1 oraz PB7 mikrokontrolera, a kolumny do portów PB6, PB5, PB4, PB3, PB2, co widać na rysunku powyżej. W pierwszej kolejności porty podłączone do wierszy są ustawiane jako wyjścia:
DDRB |= (1<<PB0); //port as output
DDRB |= (1<<PB1); //port as output
DDRB |= (1<<PB7); //port as output
DDRD |= (1<<PD6); //port as output
a te podłączone do kolumn jako wejścia:
DDRB &=~ (1 << PB2); //port as input
DDRB &=~ (1 << PB3); //port as input
DDRB &=~ (1 << PB4); //port as input
DDRB &=~ (1 << PB5); //port as input
DDRB &=~ (1 << PB6); //port as input
z włączonymi wewnętrznymi rezystorami podciągającymi je do plusa:
PORTB |= (1 << PB2); //pull-up enable
PORTB |= (1 << PB3); //pull-up enable
PORTB |= (1 << PB4); //pull-up enable
PORTB |= (1 << PB5); //pull-up enable
PORTB |= (1 << PB6); //pull-up enable
a wszystkie porty ustawione jako wyjścia są ustawiane w stan wysoki.
Następnie po kolei od góry do dołu podawany jest stan niski na kolejne wiersze aż do ostatniego.
Po podaniu stanu niskiego na pierwszy wiersz program sprawdza po kolei od lewej do prawej strony, czy któryś z przycisków nie został zwarty, a tym samym nie powoduje stanu niskiego na jednym z wejść podłączonych do kolumn. Jeśli któreś z wejść jest ustawione na stan niski, wówczas odczytywana jest aktualna pozycja, tj. numer kolumny i wiersza, i na tej podstawie określany jest przycisk, który został wciśnięty. Jeśli w danej kolumnie żaden przycisk nie został wciśnięty, wówczas program kontynuuje przeszukiwanie aż do ostatniej kolumny i ostatniego wiersza, a następnie zaczyna od początku. Poniższa animacja obrazuje działanie algorytmu.
Po wykryciu, że któryś z przycisków został wciśnięty, zostaje uruchomiony prosty kod mający na celu debounce sygnału wejściowego z przycisku, a następnie zostaje wysłany przez port szeregowy znak odpowiadający danemu klawiszowi.
Obsługa portu szeregowego jest typowa i jest on skonfigurowany w trybie tylko do wysyłania znaków. Czyli po kolei mamy:
#define F_CPU 8000000L
Definiujemy sobie prędkość oscylatora mikrokontrolera, a następnie definiujemy żądaną prędkość transmisji:
#define UART_BAUD 9600
a także tworzymy sobie proste makro, które służy do obliczenia stałej dla portu wyjściowego:
#define UART_CONST (F_CPU/(16ul*UART_BAUD)-1)
której wartość następnie przypisujemy do rejestru UBRR, czym jednocześnie definiujemy prędkość transmisji
UBRR = (unsigned char)UART_CONST;
a następnie korzystamy z rejestru UCR, w którym ustawiamy bit TXEN (TX Enable), który oznacza zgodę na wysyłanie znaków (analogicznie istnieje w tym rejestrze bit dla odbioru danych RXEN).
Po tych operacjach mamy już działający port szeregowy z prędkością 9600.
Teraz czas, aby coś na niego wysłać. W tym celu mamy stworzoną procedurkę UART_putchar(), która wygląda tak:
void UART_putchar(char c)
{
UDR=c;
loop_until_bit_is_set(USR,TXC);
USR |= (1<<TXC);
}//end of UART_putchar()
UDR to rejestr wyjściowy portu szeregowego – jego zawartość zostanie wysłana przez port, a kiedy się już to stanie (transmisja zostanie zakończona), zostanie ustawiony bit TXC w rejestrze USR, który po wysłaniu możemy już skasować (ostatnia linijka powyższej procedury), tym samym umożliwiając wysłanie kolejnego znaku.
Korzystając z portu szeregowego w swoich aplikacjach mikrokontrolerowych, należy zwrócić uwagę na dobór odpowiedniego kwarcu, którym napędzamy nasz układ. Jest to o tyle istotne, że dla różnych wartości prędkości oscylatora występują różne procentowe wartości błędów transmisji, które mogą wynosić od zera do kilku procent. W poniższej tabelce, która pochodzi z noty katalogowej, jest pokazana ta zależność.
Konstrukcja
Ja swój prototyp wykonałem na dwustronnym laminacie FR4 (szklano-epoksydowy), ścieżki przenosiłem termotransferem (pozdrowienia dla mojej laminarki ;), a całość jest zabezpieczona termoutwardzalną solder-maską.
Gumki stykowe oraz klawisze są wymontowane z kalkulatora ActiveJet ASC-8003 (koszt ok. 3 do 9zł), w kalkulatorku jest też fajny wyświetlacz LCD o dużych czytelnych cyfrach, który myślę, że w najbliższym czasie zhakuję i opiszę jak go podłączyć do kontrolera.
Obrazki, filmiki, pliki, szał!
Poniżej na filmiku prezentuję mój układ prototypowy klawiaturki. Jest ona na nim podłączona przejściówką USB->RS232 z wyjściami TTL bezpośrednio do komputera, na którym jest uruchomiony gtkterm.
Poniżej pliki do ściągnięcia oraz galeria zdjęć prototypu, have fun!
Fajne! Można jeszcze dorobić wsad, żeby SPI(?) robiło za protokół PS2 klawiatury. 🙂
Można, mi nie było potrzebne. Może kiedyś w wolnej chwili coś tutaj zupgrejduje 😉
Pomyślałem o tym jakby ktoś chciał zrobić z PC jakieś urządzenie uproszczone do wystawiania faktur czy coś. Mógłby się wtedy oprzeć na twym projekcie 🙂
A jak tam twój Atom 😕
Nie ma atoma, jest sempron… 😉
Skleroza nie boli 😉
Starzejesz się 😉
Thank you a bunch for sharing this with all folks you actually understand what you are talking about! Bookmarked. Please additionally consult with my website =). We could have a link alternate agreement among us
Ten algorytm obsługi klawiatury matrycowej ma poważny błąd. Otóż w sytuacji gdy naciśniemy przez nieuwagę lub też celowo jednocześnie dwa klawisze może dojść do uszkodzenia portów uP. Np jeżeli naciśniemy jednocześnie klawisze 4 i 7 i wystawimy stan niski na port PB0 (aby skanować ten wiersz) to poprzez zwarcie ww klawiszy port ten zostanie zwarty z portem PB1 na którym będzie w tym momencie stan wysoki czyli VCC. I mamy zwarcie VCC z GND poprzez dwa porty czyli klops. Linie te nie są w żaden sposób zabezpieczone no i uszkodzimy któryś z portów. Dodam że problem ten można rozwiązać hardware’owo lup softwer’owo. Drugie rozwiązanie jest lepsze oczywiście bo nie wymaga dokładania dodatkowych elementów. Pozdrawiam
Nigdy nie dawaj #define F_CPU w kodzie programu, dodawaj to w makefile albo w ustawieniach Eclipse/Avr Studio 😉
Czy taką klawiaturkę szło by wykorzystać
np. do sterowania winampem ?
Witam
Bezsensowne wykorzystanie dwóch portów. To przecież można na jednym 8-bitowym porcie podłączyć.
Pozdrawiam
ProDarek