Redakcja: dondu
Tematem dot. zadania eliminacji drgań styków klawiatury.
Eliminacja drgań styków przycisków mechanicznych, generalnie polega na odczytaniu stanu przycisku, a następnie odczytaniu go ponownie po pewnym czasie ok 5-20ms, jak to ma miejsce w przykładzie z zadania.
Jednak taka realizacja eliminacji drgań styków ma podstawową wadę – program staje w miejscu (pętli oczekującej) na te kilka - kilkanaście milisekund, a dla mikrokontrolera to wieczność (przy taktowaniu 8MHz daje to 40.000-160.000 zmarnowanych cykli procesora!). Dlatego należy podejść do problemu z trochę innej perspektywy.
Układ testowy zaprojektowałem tak:
Plik Eagle: schemat.zip
Procesor Atmega8 wyposażony jest w sprzętowy 8-bitowy timer/counter Timer0. Można go z powodzeniem wykorzystać do naszego celu. Użyjemy przerwanie od przepełnienia tego licznika, w którym:
- sprawdzimy stan pinów z przyciskami,
- w następnym przerwaniu wpiszemy je do zmiennej stan_przyciskow, ale tylko wtedy, gdy aktualny stan pinów jest taki sam jak poprzedni,
- w przeciwnym wypadku wartość zmiennej stan_przyciskow pozostanie nietknięta.
W efekcie zmienna stan_przyciskow zawsze zawiera aktualną informację nt. wciśniętych przycisków, ale ignorowane są szybkie zmiany ich stanów, które mogłyby zakłócić pracę pozostałej części programu.
W tym przykładzie timer0 pracuje z 256-krotnym prescalerem, co daje przerwanie co ok. 8ms:
więc opóźnienie między zmianą stanu pinu, a uaktualnieniem zmiennej stan_przyciskow będzie zawierać się w granicach 8-16ms, w zależności od tego, w którym momencie nastąpi rzeczywista zmiana logicznego stanu pinu.
Efekt końcowy jest taki, że czas jaki procesor wykorzystuje na obsługę pinów spadł do wartości 5,5us (44cykle) jest to zmiana o 99,945% w stosunku do opóźnienia programowego, a sam algorytm wykonuje się w tle i możemy o niej zapomnieć.
/* * Data: 18.02.2012 * Autor: omicronNs * E-Mail: omicronns[maupa]gmail.com * Opracowano dla: http://mikrokontrolery.blogspot.com * Tytuł: Szkielet programu z zaimplementowaną eliminacją drgań * styków przycisków * Procesor: Atmega8 * F_CPU: 8MHz * * Przyciski podłączone do portu B piny PB0-PB3 (4 przyciski) */ #include <avr/io.h> #include <avr/interrupt.h> volatile uint8_t stan_przyciskow; ISR(TIMER0_OVF_vect) { static uint8_t stan_przyciskow_stary = 0, stan_przyciskow_nowy; //Pobranie stanu przycisków, i wpisanie do zmiennej //stan_przyciskow_nowy w taki sposób, że 1 oznacza wciśnięty //ponieważ przyciski zwierają do masy (GND) należy odwrócić odczytaną //wartość z portu gdzie przyciski są podłączone stan_przyciskow_nowy = (~PINB & 0b00001111); //jeżeli stan przycisków jest taki sam jak poprzednio if(stan_przyciskow_stary == stan_przyciskow_nowy) stan_przyciskow = stan_przyciskow_nowy; //to aktualizuj zmienną glonalną //zapamietaj nowy stan stan_przyciskow_stary = stan_przyciskow_nowy; } int main(void) { //Konfiguracja pinów DDRB = 0b11110000; PORTB = 0xff; //Uruchomienie timera0, odblokowanie przerwań TCCR0 |= (1<<CS02); TIMSK |= (1<<TOIE0); sei(); //pętla główna while(1) { //Tutaj Twój program } }Projekt AVR Studio z plikiem C: drgania.zip
Komentarz Dondu:
To jeden z najprostszych i skutecznych algorytmów eliminacji drgań styków, który dodatkowo charakteryzuje się krótkim kodem wynikowym. Jego stosowanie polecam w szczególności początkującym, ze względu na jego nieskomplikowany kod ułatwiający zrozumienie jego działania.
Zobacz inne rozwiązania problemu drgań styków:
Jak będzie wyglądał taki kod dla bascoma?
OdpowiedzUsuńNiestety tego na blogu nie znajdziesz, bo tutaj tylko język C.
OdpowiedzUsuńPytaj na Elektrodzie
Co zrobić jeśli chciałbym przy wciśnięciu dowolnego przycisku np. zwiększyć zmienną a o 1. Jeśli zinkremenduję ją w pętli if(stan_przyciskow_stary == stan_przyciskow_nowy) to inkremenduje się ona w nieskończoność. Czy ktoś jest w stanie mi pomóc?
OdpowiedzUsuńZgadza się, ponieważ w powyższym przykładzie przerwanie jest wywoływane ze stałym odstępem czasowym wynoszącym około 8ms. Musisz to uwzględnić w swoim programie i dodać rozpoznawanie faktu, że nastąpiło naciśnięcie przycisku.
UsuńMożesz to zrobić porównując w pętli głównej stan zmiennej stan_przyciskow zapamiętując jej poprzedni stan i inkrementować Twoją zmienną "a" tylko w przypadku, gdy stan zmiennej stan_przyciskow wskazuje na naciśnięcie przycisku, a nie jego przytrzymanie.
a jak przy takim kodzie napisac program zapalajacy i gaszacy diode z jednego przycisku?? Moze mi ktos pomoc??
UsuńZainteresuj się darmową biblioteką: MegaSuperDebounce ™ - Zaawansowana obsługa klawiatury ARM, AVR, PIC i inne
Usuń