www.leniwiec.org

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!

10 KOMENTARZY
sprae
5 styczeń 2012
ad

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

leniwiec
5 styczeń 2012
ad

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

sprae
5 styczeń 2012
ad

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 :?

leniwiec
5 styczeń 2012
ad

Nie ma atoma, jest sempron… ;-)

sprae
5 styczeń 2012
ad

Skleroza nie boli ;-)

leniwiec
5 styczeń 2012
ad

Starzejesz się ;)

Simple Electronic and Microcontroller Projects with tutorials
30 kwiecień 2012
ad

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

Bambzo
19 maj 2012
ad

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

Marcin
19 luty 2016
ad

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

fred114
12 styczeń 2017
ad

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

Wyślij