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).

Klawiatura numeryczna z wyjściem szeregowym lub spi

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:

Schemat ideowy

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.

Zasada działania skanowania klawiszy przy pomocy mikrokontrolera

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!

11 odpowiedzi na “Klawiatura numeryczna z wyjściem szeregowym lub spi”

  1. sprae pisze:

    Fajne! Można jeszcze dorobić wsad, żeby SPI(?) robiło za protokół PS2 klawiatury. 🙂

  2. leniwiec pisze:

    Można, mi nie było potrzebne. Może kiedyś w wolnej chwili coś tutaj zupgrejduje 😉

  3. sprae pisze:

    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 😕

  4. leniwiec pisze:

    Nie ma atoma, jest sempron… 😉

  5. sprae pisze:

    Skleroza nie boli 😉

  6. leniwiec pisze:

    Starzejesz się 😉

  7. Simple Electronic and Microcontroller Projects with tutorials pisze:

    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

  8. Bambzo pisze:

    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

  9. Marcin pisze:

    Nigdy nie dawaj #define F_CPU w kodzie programu, dodawaj to w makefile albo w ustawieniach Eclipse/Avr Studio 😉

  10. fred114 pisze:

    Czy taką klawiaturkę szło by wykorzystać
    np. do sterowania winampem ?

  11. ProDarek pisze:

    Witam
    Bezsensowne wykorzystanie dwóch portów. To przecież można na jednym 8-bitowym porcie podłączyć.
    Pozdrawiam
    ProDarek

Skomentuj leniwiec Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *