Tym razem artykuł prezentujący kod sterownika w języku C, służący do zaawansowanej obsługi klawiatury na praktycznie dowolny mikrokontroler wraz z przykładem dla LPC1114.
Oprócz zamieszczenia kodów źródłowych, szczegółowo zostały opisane funkcje oraz przedstawione zostały przykłady jak z tych funkcji korzystać.
Możliwości sterownika:
debouncing czyli eliminacja drgań styków,
dynamiczna autorepetycja z możliwością blokady i zmiany międzyczasów,
dowolny typ klawiatury – pojedyncze klawisze, klawiatura matrycowa,
obsługa naciśnięć kombinacji klawiszy,
pomiar czasu wciśnięcia klawisza lub kombinacji,
implementacja niezależna od typu procesora. Można więc dostosować niniejszą bibliotekę także do innych mikrokontrolerów np. AVR, PIC, itp.
//***********************************************************************
// Plik: keyb.c
//
// Zaawansowana obsługa przycisków i klawiatur
// Wersja: 1.0
// Licencja: GPL v2
// Autor: Deucalion
// Email: deucalion#wp.pl
// Szczegóły: http://mikrokontrolery.blogspot.com/2011/04/jezyk-c-biblioteka-obsluga-klawiatury.html
//
//***********************************************************************
#include "keyb.h"
#define PERIOD_1S 100
#define PERIOD_750MS 75
#define PERIOD_500MS 50
#define PERIOD_100MS 10
#define PERIOD_30MS 3
// ***********************************************************************
static unsigned int keys;
// Wewnętrzna zmienna w której przechowywany jest stan klawiszy
// Zawartość tej zmiennej pobierana jest przez program za pomoca funkcji
// GetKeys(); jeśli zmienna keycnt jest większa od zera.
// ***********************************************************************
// ***********************************************************************
static unsigned int keycnt;
// Wewnętrzna zmienna w której przechowywana jest licznik autorepetycji
// Zwiększany okresowo w momencie gdy są naciśnięte klawisze i ich stan
// nie zmienia się przez dłuższy czas. Zmniejszana podczas każdego
// wywołania funkcji GetKeys();
// ***********************************************************************
// ***********************************************************************
static unsigned int keytime;
// Wewnętrzna zmienna reprezentująca czas od ostatniego naciśnięcia
// klawiszy. Zwracana do programu za pomocą funkcji KeysTime();
// Jeśli nie ma wciśniętego żadnego klawisza, zmienna utrzymuje wartość 0;
// ***********************************************************************
// ***********************************************************************
static unsigned int prevKeybSt;
// Wewnętrzna zmienna pamiętająca stan klawiszy z poprzedniego wywołania
// funkcji KeybProc(). Służy do wykrycia zmiany stanu klawiatury
// ***********************************************************************
// ***********************************************************************
static unsigned int arTime;
// Wewnętrzna zmienna reprezentująca czas w którym ma nastąpić zwiekszenie
// licznika klawiatury. Zwiększana o odpowiedni czas zależny o czasów
// autorepetycji po każdym zwiekszeniu licznika klawiatury
// ***********************************************************************
// ***********************************************************************
static unsigned char arIndex ;
// Wewnętrzna zmienna indeksująca tablicę z kolejnymi czasami autorepetycji
// ***********************************************************************
// ***********************************************************************
static unsigned char keyblock;
// Wewnętrzna zmienna ustawiana na 1 funkcją KeybLock() lub ClrKeyb()
// z parametrem KBD_LOCK. Jeśli zmienna ma wartość 1 obsługa klawiatury
// zostaje zablokowana do momentu zwolnienia wszystkich klawiszy.
// ***********************************************************************
// ***********************************************************************
// Domyślna tablica z kolejnymi czasami autorepetycji. Ostatnia pozycja różna
// od zera jest czasem autorepetycji nieskończonej. Ilość pozycji dowolna,
// ostatnia pozycja musi być równa 0;
static const unsigned short DefaultAutoRepeatTab[] =
{
PERIOD_30MS,
PERIOD_1S,
PERIOD_500MS,
PERIOD_500MS,
PERIOD_500MS,
PERIOD_500MS,
PERIOD_100MS,
0
};
static unsigned short
* volatile _art = (unsigned short *)DefaultAutoRepeatTab,
* volatile art = (unsigned short *)DefaultAutoRepeatTab;
// ***********************************************************************
// Funkcja dostarczająca surowy stan klawiatury.
// Stan wysoki dla wcisniętych klawiszy. Jeśli funkcja KeybProc()
// będzie wywoływana z przerwania to funkcja GetKeybSample() musi
// trwać jak najkrócej
// ***********************************************************************
unsigned int
GetKeybSample( void )
{
Tu należy dopisać ciało funkcji, która będzie zwracać stan klawiszy,
stan niski oznacza klawisz nienaciśnięty, stan wysoki klawisz naciśnięty
Przykład:
// zakładamy, że wciśnięcie klawisza zwiera pin do masy
return ( ~PIND ) & ( KEY0 | KEY1 | KEY2 | KEY3 );
}
// ***********************************************************************
// Funkcja wywoływana z jakiegos przerwania w tym przypadku co 10ms
// ***********************************************************************
void
KeybProc( void )
{
unsigned int realKeybSt;
// Pobranie stanu klawiszy
realKeybSt = GetKeybSample();
// Sprawdzenie czy stan sie zmienił
if( prevKeybSt != realKeybSt )
{
// Stan sie zmienił więc resetowanie klawiatury i wyjście z funkcji
ClrKeyb( KBD_NOLOCK );
return;
}
// Sprawdzenie czy brak naciśniętych klawiszy lub klawiatura zablokowana
if( !realKeybSt || keyblock )
{
// Ponowne sprawdzenie czy brak nacisniętych klawiszy
// Jeśli tak to odblokowanie klawiatury
if( !realKeybSt ) keyblock = 0;
return;
}
// Zwiekszenie licznika czasu klawiatury
keytime++;
// Zachowanie stanu klawiszy
keys = realKeybSt;
// Obsługa autorepetycji
// Sprawdzenie czy licznik czsu klawiatury osiągnął czas następnej
// autorepetycji
if( keytime >= arTime )
{
// Zwiększenie licznika autorepetycji
keycnt++;
// Obliczenie kolejnego czasu autorepetycji
_art = art;
if( _art[ arIndex + 1 ]) arIndex++;
arTime += _art[ arIndex ];
}
}
// ***********************************************************************
// Funkcja zwraca stan klawiszy do programu jeśli licznik autorepetycji
// rózny od zera
// ***********************************************************************
unsigned int
GetKeys( void )
{
if( keycnt )
{
keycnt--; // Jeśli funkcja KeybProc() będzie wywoływana z przerwania
// to ta instrukcja musi być wykonana atomowo.
return keys ;
}
return 0;
}
// ***********************************************************************
// Funkcja zwraca czas wciskania aktualnej kombinacji klawiszy
// ***********************************************************************
unsigned int
KeysTime( void )
{
return keytime;
}
// ***********************************************************************
// Funkcja zwraca stan klawiszy zgodnie z podana maską jako argument funkcji
// ***********************************************************************
unsigned int
IsKeyPressed( unsigned int mask )
{
return keys & mask;
}
// ***********************************************************************
// Funkcja zwraca stan klawiszy zgodnie z ustawiona maską podana jako
// argument funkcji, jest brany pod uwage licznik autorepetycji
// Ale pobranie stanu klawiwszy nie zminiejsza licznika autorepetycji
// ***********************************************************************
unsigned int
IsKey( unsigned int mask )
{
if(keycnt)
{
return keys & mask ;
}
return 0;
}
// ***********************************************************************
// Funkcja resetuje stan klawiatury. Jako parametr należy podać stałą
// KBD_LOCK lub KBD_NOLOCK, które odpowiednio blokują lub nie klawiaturę
// Jeśli funkcja KeybProc() będzie wywoływana z przerwania to funkcja
// ClrKeyb() musi być wykonana atomowo.
// ***********************************************************************
void
ClrKeyb( int lock )
{
prevKeybSt = GetKeybSample();
keys = 0;
keytime = 0;
keycnt = 0;
arIndex = 0;
arTime = _art[0];
if( lock ) keyblock = 1;
}
// ***********************************************************************
// Funkcja blokuje klawiaturę. Odblokowanie następuje po zwolnieniu
// wszystkich klawiszy.
// ***********************************************************************
void
KeybLock( void )
{
keyblock = 1;
}
// ***********************************************************************
// Funkcja podmienia tablicę z międzyczasami autorepetycji. Nowa tablica
// powinna być zgodna z wcześniej opisanym formatem
// ***********************************************************************
void
KeybSetAutoRepeatTimes( unsigned short * AutoRepeatTab )
{
if( AutoRepeatTab == KBD_DEFAULT_ART )
art = (unsigned short *)DefaultAutoRepeatTab;
else
art = AutoRepeatTab;
}
Definiowanie klawiszy
Do przedstawionego kodu należy dopisać własną wersję funkcji unsigned int GetKeybSample( void ). Funkcja ma zwracać stan klawiszy, np. jeśli klawiatura posiada 4 klawisze, to ich stan ma znajdować się w zwracanej wartości i wciśnięte klawisze mają reprezentować ustawione bity. Nie ma znaczenia, który bit będzie reprezentował dany klawisz.
Inną czynnością jest przyporządkowanie określonym bitom odpowiednich klawiszy w pliku keyb.h.
Dla przykładu przypuśćmy, że klawisze znajdują się na pinach PD1, PD3, PD6, PD7 i tym klawiszom przypisane są następujące funkcje PD1 - KEY_UP, PD3 – KEY_ENTER, PD6 – KEY_DOWN, PD7 – KEY_ESC. Nasze deklaracje powinny wyglądać w ten sposób:
Tych deklaracji będziemy używać w naszym programie.
W tym przypadku funkcja GetKeybSample( ) może wyglądać w ten sposób:
unsigned int GetKeybSample( void )
{
// zakładamy, że wciśnięcie klawisza zwiera pin do masy
return ( ~PIND ) & ( KEY0 | KEY1 | KEY2 | KEY3 );
}
Kolejną czynnością jaką musimy zrobić to wywoływać gdzieś w programie funkcję KeybProc() dokładnie co 10ms. Można to zrobić z przerwania lub gdzieś w głównej pętli programu – pełna dowolność. Jeśli zdecydujemy się na wywoływanie z przerwania należy wziąć pod uwagę dwa fragmenty kody z tej biblioteki (opis w komentarzach), które muszą być wykonywane atomowo, czyli nieprzerywalnie oraz funkcja GetKeybSample() powinna wykonywać się możliwie jak najszybciej. To wszystko co trzeba na ten moment zrobić, aby móc korzystać w programie z tej biblioteki. Teraz kilka przykładów jak jej używać.
1. Reakcja na naciśnięcie dowolnego klawisza
while( 1 )
{
if( GetKeys() )
{
// Tutaj kod reakcji na naciśniecie dowolnego klawisza
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
}
}
Funkcja GetKeys() zwraca stan klawiatury, ale tylko co czas określony w tabeli czasów autorepetycji, czyli standardowo po naciśnięciu przycisku po 30ms, 1030ms, 1530ms, 2030ms, 2530ms, 3030ms, 3130ms, 3230ms, 3330ms itd. co kolejne 100ms, aż do jakiejkolwiek zmiany stanu klawiatury.
2. Reakcja na naciśnięcie wybranego klawisza
while( 1 )
{
if( GetKeys() == KEY_ENTER )
{
// Tutaj kod reakcji na naciśniecie wybranego klawisza
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
}
}
3. Reakcja na naciśnięcie dowolnego z dwóch klawiszy lub ich kombinacji
while( 1 )
{
if( GetKeys() & ( KEY_UP | KEY_DOWN ))
{
// Tutaj kod reakcji na naciśniecie dowolnego
// z dwóch klawiszy lub ich kombinacji
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
}
}
4. Reakcja w zależności od wciśniętego przycisku lub ich kombinacji
while( 1 )
{
switch( GetKeys() )
{
case KEY_UP:
// Tutaj kod reakcji na naciśniecie klawisza KEY_UP
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_DOWN:
// Tutaj kod reakcji na naciśniecie klawisza KEY_DOWN
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_ENTER:
// Tutaj kod reakcji na naciśniecie klawisza KEY_ENTER
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_ESC:
// Tutaj kod reakcji na naciśniecie klawisza KEY_ESC
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_ENTER | KEY_ESC:
// Tutaj kod reakcji na naciśniecie kombinacji klawiszy KEY_ENTER i
// KEY_ESC. Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
default:
// Tutaj kod reakcji na naciśniecie pozostałych niewymienionych
// wcześniej kombinacji klawiszy. Kod będzie się wykonywał zgodnie
// z czasami autorepetycji
break;
}
}
Przy braku możliwości wyłączenia autorepetycji i dłuższym przytrzymaniu klawisza mogłoby dojść do sytuacji gdzie stracilibyśmy kontrole nad urządzeniem.
Co zrobić, jeśli nie chcemy aby w danym momencie działa autorepetycja, np. kolejne naciśnięcia klawisza KEY_ENTER powodują wejście i wyjście z menu lub kolejne wybieranie podmenu? W takim przypadku należy skorzystać z funkcji ClrKeyb().
Funkcja jako parametr przyjmuje dwie zdeklarowane wartości KBD_LOCK i KBD_NOLOCK. KBD_LOCK powoduje zablokowanie klawiatury, aż do momentu zwolnienia wszystkich klawiszy i analogicznie KBD_NOLOCK nie powoduje takiego zablokowania, wszystko zaczyna się od nowa, tak jak od naciśnięcia klawisza.
Funkcja ClrKeyb() w ogólnej postaci służy do resetowania klawiatury. Może się tak zdarzyć, że program będzie wykonywał czasochłonną operację trwająca kilka lub więcej sekund. Trzymanie w tym czasie wciśniętego klawisza powoduje naliczanie czasów autorepetycji. Gdy program wznowi pobieranie stanu klawiatury może dojść do takiego zachowania jakby został wielokrotnie naciśnięty przycisk. Można temu zapobiec poprzez zresetowanie klawiatury po wykonaniu takiej czasochłonnej operacji. Użycie funkcji ClrKeyb( KBD_LOCK) w takiej postaci powoduje również zatrzymanie autorepetycji.
5. Reakcja w zależności od wciśniętego przycisku lub ich kombinacji z zatrzymaniem autorepetycji na wybranych klawiszach.
while( 1 )
{
switch( GetKeys( ))
{
case KEY_UP:
// Tutaj kod reakcji na naciśniecie klawisza KEY_UP
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_DOWN:
// Tutaj kod reakcji na naciśniecie klawisza KEY_DOWN
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
case KEY_ENTER:
ClrKeyb( KBD_LOCK ); // <--------------------------
// Tutaj kod reakcji na naciśniecie klawisza KEY_ENTER
// Kod wykona się tylko raz po każdym naciśnięciu klawisza
break;
case KEY_ESC:
ClrKeyb( KBD_LOCK ); // <--------------------------
// Tutaj kod reakcji na naciśniecie klawisza KEY_ESC
// Kod wykona się tylko raz po każdym naciśnięciu klawisza
break;
case KEY_ENTER | KEY_ESC:
// Tutaj kod reakcji na naciśniecie kombinacji klawiszy KEY_ENTER i
// KEY_ESC. Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
default:
ClrKeyb( KBD_LOCK ); // <--------------------------
// Tutaj kod reakcji na naciśniecie pozostałych niewymienionych
// wcześniej kombinacji klawiszy. Kod wykona się tylko raz po
// każdym naciśnięciu klawisza
break;
}
}
6. Sprawdzenie czy naciśnięty dowolny klawisz niezależnie od czasów autorepetycji, ale z uwzględnieniem eliminacji drgań styków.
while( 1 )
{
if( IsKey( ANYKEY ))
{
// Kod wykonywany za kazdym razem gdy wciśnięty
// jest dowolny klawiasz z uwzględnieniem drgań styków
// Czasy autorepetycji nie mają znaczenia.
}
}
Funkcja unsigned int IsKey( unsigned int mask ) zwraca zamaskowany stan klawiszy. Jako parametr przyjmuje maskę, która przysłania stany nieistotnych klawiszy. Jeśli wywołamy funkcję w postaci IsKey( KEY_ENTER ) to funkcja zwróci tyko stan klawisza KEY_ENTER i jeśli klawisz ten będzie wciśnięty zostanie również zwrócona wartość KEY_ENTER. Jeśli chcemy sprawdzić stan kilku klawiszy wywołujemy tą funkcję podając ich nazwy: IsKey( KEY_ENTER | KEY_ESC )
7. Sprawdzenie czy naciśnięty którykolwiek ze wskazanych klawiszy niezależnie od czasów autorepetycji, ale z uwzględnieniem eliminacji drgań styków.
while( 1 )
{
if( IsKey( KEY_ENTER | KEY_ESC ))
{
// Kod wykonywany za kazdym razem gdy wciśnięty
// jest co najmniej jeden ze wskazanych klawiaszy
// z uwzględnieniem drgań styków
// Czasy autorepetycji nie mają znaczenia.
}
}
Funkcja unsigned int IsKeyPressed( unsigned int mask ) działa podobnie do funkcji IsKey() z tą tylko różnicą, że nie jest uwzględniony czas drgań styków tzn. funkcja zwraca stan klawiszy zgodny z podaną maską, jeśli w tym czasie będą drgania styków to funkcja również je przeniesie do programu.
8. Reakcja programu w zależności od czasu naciskania klawisza.
while( 1 )
{
switch( GetKeys( ))
{
case KEY_ENTER:
if( KeysTime( ) >= 500 )
{
ClrKeyb( KBD_LOCK );
// Tutaj kod reakcji na naciśniecie klawisza KEY_ENTER
// Kod wykona się tylko wtedy gdy czas trzymania
// klawisza przekroczy 5s
}
break;
case KEY_ESC:
// Tutaj kod reakcji na naciśniecie klawisza KEY_ESC
// Kod będzie się wykonywał zgodnie z czasami autorepetycji
break;
}
}
Wersja druga:
while( 1 )
{
if( IsKey( KEY_ENTER ) && KeysTime( ) >= 500 )
{
ClrKeyb( KBD_LOCK );
// Tutaj kod reakcji na naciśniecie klawisza KEY_ENTER
// Kod wykona się tylko wtedy gdy czas trzymania
// klawisza przekroczy 5s
}
}
Funkcja unsigned int KeysTime( void ) zwraca czas jaki upłynął od ostatniej zmiany na klawiaturze, jeśli żaden klawisz nie jest wciśnięty funkcja zwraca 0. Jednostką czasu jest 10ms czyli jeśli chcemy sprawdzić czy klawisz jest wciśnięty dłużej niż 1s zapisujemy to w taki oto sposób:
if( KeysTime( ) >= 100 ){ … }
Autorepetycja jest to funkcjonalność, która symuluje wciskanie klawisza co określony czas jeśli klawisz jest cały czas wciśnięty. Dzięki temu mamy możliwość „wciśnięcia” klawisza kilka, kilkanaście a nawet kilkadziesiąt razy w ciągu sekundy. Opcja ta przydaje się gdy mamy np. do przestawienia jakąś wartość o kilkadziesiąt lub kilkaset jednostek za pomocą tylko dwóch klawiszy. Odstępy czasów mogą być stałe lub zmieniać się w czasie.
W przypadku tej biblioteki do obsługi klawiatury mamy sporą dowolność. Sterownik posiada domyślne odstępy czasów, ale można również w trakcie programu je zmieniać. Po naciśnięciu klawisza, domyślnie za pomocą funkcji GetKeys() kody klawiszy udostępniane są po 30ms, 1030ms, 1530ms, 2030ms, 2530ms, 3030ms, 3130ms, 3230ms, 3330ms itd. co kolejne 100ms, aż do jakiejkolwiek zmiany stanu klawiatury. Za pomocą funkcji void KeybSetAutoRepeatTimes( unsigned short * AutoRepeatTab ) można sterownikowi dostarczyć tablicę opisującą inną sekwencję odstępów czasów.
KeybSetAutoRepeatTimes(( unsigned short * )KeyAutoRepeatTab );
Efektem w/w przykładu będzie symulacja naciśnięć klawisza w czasach 30ms, 530ms, 560ms, 590ms itd. co 30ms, co da nam około 33 pseudo naciśnięcia na sekundę. Tablica może mieć dowolną ilość odstępów czasów nie mniejszą niż 2. Pierwsza, przedostatnia i ostatnia pozycja mają specyficzne znaczenie. Pierwsza nie powinna być mniejsza niż 3 ( czyli 30ms), jest to czas na eliminację drgań styków. Ostatnia musi mieć wartość 0 i sygnalizuje koniec tablicy czasów. Natomiast wartość przedostatniej jest czasem autorepetycji nieskończonej. Należy pamiętać, że jednostką czasu w tablicy jest 10ms.
Podsumowanie
Aby móc zastosować tą bibliotekę w swoim projekcie należy:
skopiować i dołączyć do drzewa projektu pliki keyb.h i keyb.c,
utworzyć odpowiednie deklaracje w pliku keyb.h lub dołączyć własny plik z takimi deklaracjami,
napisać własną wersję funkcji GetKeybSample( ), która jest pomostem między sterownikiem a sprzętem,
umieścić w programie wywołanie funkcji KeybProc(). Funkcja musi być wywoływana co 10ms.
Ode mnie podziękowania za podzielenie się biblioteką z początkującymi. Dzięki takim osobom jak Deucalion mają oni znacznie łatwiej. Mam nadzieję, że korzystający z tej biblioteki mega superdebounce przyłączą się i miłym słowem skomentują dobry uczynek kolegi :D :D
Oceń artykuł. Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły. Pozdrawiamy, Autorzy
Witam. Przyznam że do tej pory pisałem bardziej skomplikowany program by osiągnąć podobne efekty. W twojej bibliotece podoba mi się ta uniwersalność przez co łatwo przerobić na inny mikrokontroler tej samej rodziny - ja pracuję tylko na AVR. Fajne, naprawdę fajne. Pozdrawiam
Witam. Ta wersja funkcjonuje już od około pół roku, wcześniej też używałem bardziej złożonej wersji, ale działającej na tej samej zasadzie. Z takiego podejścia do obsługi klawiatury korzystam już od kilku lat na różnych procesorach (ARM, AVR, Zilog) i dzięki temu w każdym kolejnym projekcie nie muszę się zastanawiać nad wszystkim co jest związane z obsługą klawiatury. Zazwyczaj implementacja polega na Ctrl+V Ctrl+C plus ta cała wymagana otoczka opisana w podsumowaniu. Zapraszam więc do testowania i dzielenia się uwagami. Pozdrawiam
Witam, jestem początkujący w temacie i możliwość skorzystania z takiej biblioteki to nieoceniona pomoc. Zrobiłem swój pierwszy projekt w którym obsługę jednego klawisza realizuje dedykowana funkcja.W drugiej wersji chciałem wprowadzić modyfikację polegającą na użyciu twojej biblioteki, ale brakuje funkcji realizującej obsługę jednego klawisza z rozróżnieniem: krótkie naciśnięcie i naciśnięcie długie z auto repetycją. Ładnie to działa jeżeli mamy dwa przyciski do dyspozycji, ale jak to zrobić na jednym ?. Przykład: if( IsKey( KEY)) { // Kod wykonywany za każdym razem gdy wciśnięty jest klawisz z uwzględnieniem drgań styków co jest w moim projekcie wadą, aby to usunąć trzeba wywołać funkcję ClrKeyb( KBD_LOCK );, ale wówczas nigdy nie zostanie spełniony 2 warunek } if( IsKey( KEY ) && KeysTime( ) >= 100 ) { // Tutaj kod reakcji na naciśniecie klawisza KEY Kod wykona się tylko wtedy gdy czas trzymania klawisza przekroczy 1s } Czy jest sposób aby taką obsługę zrobić z tą biblioteką ? Pozdrawiam,
if( IsKey( KEY ) && KeysTime( ) >= 100 ) { // Tutaj kod reakcji na naciśniecie klawisza KEY // Kod wykona się tylko wtedy gdy czas trzymania klawisza przekroczy 1s }
A masz jakieś konkretny problem, czy tak tylko pytasz? Można ją nawet wykorzystać do obsługi klawiatury znajdującej się po drugiej stronie globu, kwestia tylko cyklicznego dostarczenia fizycznego stanu klawiszy. Wykorzystywalem ją do obsługi klawiatury pojemnosciowej wykonanej w oparciu o układ MPR121, więc na pewno da radę z jakąś tam chińska klawiaturą.
Pytam bo nie mam pomysłu jak to zrobić, biblioteka z domysłu oczekuje odpowiedniego stanu na odpowiednim ustalonym pinie, a te klawiaturki matrycowe trzeba skanować zmieniając porty z wejść na wyjścia itp.
Odczyt stanu klawiszy realizuj w jakimś przerwaniu i zapisuj do jednej zmiennej która będzie odczytywać ta biblioteka. Ustaw jedna kolumnę i wyjdź z przerwania. Podzczas następnej obsługi tego przerwania odczytaj wiersze i ustaw następna kolumnę itd. Wszystkie wiersze powinny być odczytane przed odczytem zmiennej przez bibliotekę.
Hi, mam pytanie czy i w jaki sposób można zaadoptować tą bibliotekę do obsługi klawiszy które są podpięte pod różne porty tj np: trzy klawisze podpięte do portu B PB1, PB3, PB4 a czwarty klawisz do portu D - PD7 ?? Próbowałem na różne sposoby zmusić program do pracy ale nic mi nie wyszło (jeśli klawisze są na jednym porcie jest ok) ale ja potrzebuje mieć klawisze na różnych portach. Z góry dzięki za pomoc.
Niemam już nerwów do tego. Może mi ktoś powie co robie źle:
#include #include "keyb.h" #define F_CPU 1000000 //ustawienie oscylatora na 1MHz #include //dołączenie biblioteki z przerwaniami
int main(void) { //ustawienie wejśc/wyjść DDRC=0; //Piny na porcie C jako wejścia PORTC |= (1<<PC0) | (1<<PC1); //PC0 i PC1 jako wejscia do sterowania prawo-lewo DDRB = 0xFF; //PORTB jako wyjścia PORTB = 0xFF;
//Ustawianie przerwań co 10ms TCCR0 |= (1<<CS02) | (1<<CS00); //ustawienie preskalera na 1024, źródło CLK, czyli standardowo przerwanie bedzie co 256ms (jeżeli nie ustawimy TCNT0) TIMSK |= 1<<TOIE0; //włączenie przerwania od przepełnienia licznika TCNT0 = 246; //ustawienie wartości początkowej sei(); //zezwolenie na przerwania
while(1) {
switch( GetKeys( )) { case KEY_UP: PORTB=~PORTB; break; case KEY_DOWN: PORTB=~PORTB; break; }
} }
ISR(TIMER0_OVF_vect) //początek funkcji obsługi przerwania { KeybProc(); TCNT0 = 246; //ustawienie wartości początkowej } Dodam, że mam dodane do projektu keyb.c i keyb.h zgodnie z zaleceniami z powyższego linku z elektrody.
Szanowni blogowicze, Czy idzie w tej bibliotece zrobić tak żeby po wciśnięciu dwóch klawiszy jednoczesnie wykonała się instrukcja? Próbowałem tak: if( IsKey( KEY_ENTER & KEY_ESC ))
Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).
Sponsorzy:
Blog wykorzystuje pliki cookie zgodnie z ustawieniami Twojej przeglądarki. Aby dowiedzieć się więcej o polityce dot. plików cookie i javascript, kliknij ten link:
Polityka dot. plików cookie i javascript
Zapamiętaj ten artykuł w moim prywatnym spisie treści.
No faktycznie wygląda nieźle. Chyba dzisiejszy wieczór spędzę na testowaniu na jakimś AVR. Dzięki!
OdpowiedzUsuńWitam. Przyznam że do tej pory pisałem bardziej skomplikowany program by osiągnąć podobne efekty. W twojej bibliotece podoba mi się ta uniwersalność przez co łatwo przerobić na inny mikrokontroler tej samej rodziny - ja pracuję tylko na AVR. Fajne, naprawdę fajne. Pozdrawiam
OdpowiedzUsuńWitam. Ta wersja funkcjonuje już od około pół roku, wcześniej też używałem bardziej złożonej wersji, ale działającej na tej samej zasadzie. Z takiego podejścia do obsługi klawiatury korzystam już od kilku lat na różnych procesorach (ARM, AVR, Zilog) i dzięki temu w każdym kolejnym projekcie nie muszę się zastanawiać nad wszystkim co jest związane z obsługą klawiatury. Zazwyczaj implementacja polega na Ctrl+V Ctrl+C plus ta cała wymagana otoczka opisana w podsumowaniu.
OdpowiedzUsuńZapraszam więc do testowania i dzielenia się uwagami. Pozdrawiam
Witam, jestem początkujący w temacie i możliwość skorzystania z takiej biblioteki to nieoceniona pomoc.
OdpowiedzUsuńZrobiłem swój pierwszy projekt w którym obsługę jednego klawisza realizuje dedykowana funkcja.W drugiej wersji chciałem wprowadzić modyfikację polegającą na użyciu twojej biblioteki, ale brakuje funkcji realizującej obsługę jednego klawisza z rozróżnieniem: krótkie naciśnięcie i naciśnięcie długie z auto repetycją. Ładnie to działa jeżeli mamy dwa przyciski do dyspozycji, ale jak to zrobić na jednym ?.
Przykład:
if( IsKey( KEY))
{
// Kod wykonywany za każdym razem gdy wciśnięty jest klawisz z uwzględnieniem drgań styków co jest w moim projekcie wadą, aby to usunąć trzeba wywołać funkcję ClrKeyb( KBD_LOCK );, ale wówczas nigdy nie zostanie spełniony 2 warunek
}
if( IsKey( KEY ) && KeysTime( ) >= 100 )
{
// Tutaj kod reakcji na naciśniecie klawisza KEY
Kod wykona się tylko wtedy gdy czas trzymania klawisza przekroczy 1s
}
Czy jest sposób aby taką obsługę zrobić z tą biblioteką ?
Pozdrawiam,
O coś takiego chodziło?
OdpowiedzUsuństaic char _key,
static unsigned int _key_time;
if( IsKey( KEY ))
{
_key = 1;
_key_time = KeysTime();
}
else if ( _key )
{
_key = 0;
if( _key_time < 10 )
{
// Tutaj kod obsługi krótkiego naciśnięcia (t < 100ms)
....
}
}
if( IsKey( KEY ) && KeysTime( ) >= 100 )
{
// Tutaj kod reakcji na naciśniecie klawisza KEY
// Kod wykona się tylko wtedy gdy czas trzymania klawisza przekroczy 1s
}
Bardzo fajny kurs. Kiedy następny odcinek.
OdpowiedzUsuńP.S. Nie mogę się doczekać kontynacji !
Dondu, popraw listing keyb.h bo jest niekompletny. Potem czytelnicy bezmyślnie kopiują i nie wiedzą co jest grane.
OdpowiedzUsuńPorozmawiam z autorem, a na razie zapraszam na forum, gdzie jak sądzę pomogłeś pytającemu: [ATmega8][WinAVR] - biblioteka Zaawansowana obsługa klawiatury jak uruchomic.
UsuńDzięki Twoim uwagom pytający zrozumiał jak proste jest używanie tej biblioteki:
cyt.: "działa! dzieki wielkie! w sumie to prosta sprawa :) "
Dziękuję za pomoc,
:-)
Od kiedy GPL pozwala na limitowanie do zastosowań niekomercyjnych?
OdpowiedzUsuńCzy komuś się udało wykorzystać tą bibliotekę do obsługi chińskiej matrycy 4x4 z 8 pinami?
OdpowiedzUsuńA masz jakieś konkretny problem, czy tak tylko pytasz?
UsuńMożna ją nawet wykorzystać do obsługi klawiatury znajdującej się po drugiej stronie globu, kwestia tylko cyklicznego dostarczenia fizycznego stanu klawiszy. Wykorzystywalem ją do obsługi klawiatury pojemnosciowej wykonanej w oparciu o układ MPR121, więc na pewno da radę z jakąś tam chińska klawiaturą.
Pytam bo nie mam pomysłu jak to zrobić, biblioteka z domysłu oczekuje odpowiedniego stanu na odpowiednim ustalonym pinie, a te klawiaturki matrycowe trzeba skanować zmieniając porty z wejść na wyjścia itp.
UsuńOdczyt stanu klawiszy realizuj w jakimś przerwaniu i zapisuj do jednej zmiennej która będzie odczytywać ta biblioteka. Ustaw jedna kolumnę i wyjdź z przerwania. Podzczas następnej obsługi tego przerwania odczytaj wiersze i ustaw następna kolumnę itd. Wszystkie wiersze powinny być odczytane przed odczytem zmiennej przez bibliotekę.
UsuńNiestety u mnie nie działa.
OdpowiedzUsuńdostaje komunikaty
undefined reference to `GetKeys'
i
ld returned 1 exit status
Jak mogę naprawić ten błąd.
Hej nie mogę sprawdzać stanu kilku klawiszy w funkcji.
OdpowiedzUsuńJakby GetKeys() się blokowało lub działało tylko w funkcji main
void submenu()
{
lcd_locate(0,0);
lcd_str("tekst");
while( 1 )
{
if(GetKeys() == KEY_UP)
{
lcd_str("key_up");
}
if(GetKeys() == KEY_ENTER)
{
lcd_str("key_enter");
}
}
}
Hi, mam pytanie czy i w jaki sposób można zaadoptować tą bibliotekę do obsługi klawiszy które są podpięte pod różne porty tj np: trzy klawisze podpięte do portu B PB1, PB3, PB4 a czwarty klawisz do portu D - PD7 ?? Próbowałem na różne sposoby zmusić program do pracy ale nic mi nie wyszło (jeśli klawisze są na jednym porcie jest ok) ale ja potrzebuje mieć klawisze na różnych portach.
OdpowiedzUsuńZ góry dzięki za pomoc.
Niemam już nerwów do tego. Może mi ktoś powie co robie źle:
OdpowiedzUsuń#include
#include "keyb.h"
#define F_CPU 1000000 //ustawienie oscylatora na 1MHz
#include //dołączenie biblioteki z przerwaniami
int main(void)
{
//ustawienie wejśc/wyjść
DDRC=0; //Piny na porcie C jako wejścia
PORTC |= (1<<PC0) | (1<<PC1); //PC0 i PC1 jako wejscia do sterowania prawo-lewo
DDRB = 0xFF; //PORTB jako wyjścia
PORTB = 0xFF;
//Ustawianie przerwań co 10ms
TCCR0 |= (1<<CS02) | (1<<CS00); //ustawienie preskalera na 1024, źródło CLK, czyli standardowo przerwanie bedzie co 256ms (jeżeli nie ustawimy TCNT0)
TIMSK |= 1<<TOIE0; //włączenie przerwania od przepełnienia licznika
TCNT0 = 246; //ustawienie wartości początkowej
sei(); //zezwolenie na przerwania
while(1)
{
switch( GetKeys( ))
{
case KEY_UP:
PORTB=~PORTB;
break;
case KEY_DOWN:
PORTB=~PORTB;
break;
}
}
}
ISR(TIMER0_OVF_vect) //początek funkcji obsługi przerwania
{
KeybProc();
TCNT0 = 246; //ustawienie wartości początkowej
}
Dodam, że mam dodane do projektu keyb.c i keyb.h zgodnie z zaleceniami z powyższego linku z elektrody.
sory, że tak się rozciągnąłem, ale lubie przejrzystość w kodzie :)
UsuńDodam, że uC to ATmega8 a program piszę Atmel Studio 6.
Nie napisałeś co Ci nie działa i co chciałeś osiągnąć.
UsuńZałóż wątek na elektrodzie , dołącz cały kod i wklej tutaj link do tego wątku.
http://www.elektroda.pl/rtvforum/viewtopic.php?p=14156636#14156636
UsuńSzanowni blogowicze,
OdpowiedzUsuńCzy idzie w tej bibliotece zrobić tak żeby po wciśnięciu dwóch klawiszy jednoczesnie wykonała się instrukcja? Próbowałem tak:
if( IsKey( KEY_ENTER & KEY_ESC ))
ale nie działa.
Pozdrawiam Kamil