Kurs podstawowy
Drgania styków - jak sobie z nimi radzić

Przyciski to elementy mechaniczne, których jedną z właściwości jest powstawanie drgań styków podczas zmiany ich stanu. Jest to zjawisko niepożądane, lecz niemożliwe do wyeliminowania. Zobaczmy, czym ono jest i jak sobie z nim radzić.

 

Czym jest drganie styków? Jest to stan nieustalony występujący w czasie przyciskania i zwalniania przycisku. Powstaje wtedy szereg krótkotrwałych zwarć styków. Zjawisko to potrafi zakłócić pracę układów mikroprocesorowych. Układy mikroprocesorowe są układami sekwencyjnymi, gdzie operacje wykonywane są w takt zegara. Wejście dwustanowe, do którego podłączony jest przycisk sprawdzane jest wiele razy na sekundę. Wciśnięcie przycisku powoduje podanie na wejście określonego stanu, który wywołuje konkretne działanie mikrokontrolera. Zjawisko drgania styków powoduje, ze wciśnięcie przycisku interpretowane jest przez mikrokontroler jako seria wciśnięć i zwolnień przycisku. Sytuacja taka niesie za sobą funkcjonowanie układu nie do końca zgodne z oczekiwaniami. Liczba drgań styków jest losowa. Należy więc spowodować, że mikrokontroler nie będzie reagować w czasie stanu nieustalonego ustalonego.

 

Rys.1. Przebieg napięcia podczas wciśnięcia i zwolnienia przycisku.

 

Rysunek 1 przedstawia przebieg napięcia na stykach przycisku podczas jego wciskania oraz zwalniania. Zaprezentowane przebiegi pochodzą z prób ze zwykłym przyciskiem o niskim zaawansowaniu technologicznym. Przycisk ten generował najdłuższy czas przerzucania ze wszystkich badanych. Jak widać czasy przerzucania styków podczas wciśnięcia i zwolnienia wynoszą poniżej 0,5 ms. Analizując zjawisko drgania styków posługiwałem się układem z mikrokontrolerem ATmega32 taktowanym zegarem o częstotliwości 16 MHz, którego zadaniem było naprzemienne włączanie i wyłączanie diody świecącej po wciśnięciu przycisku. Reakcja mikrokontrolera wyzwalana była stanem niskim na wejściu z podłączonym przyciskiem. Analizę przeprowadzałem bez funkcji opóźniających, a także z z ich użyciem. Gołym okiem dało się zauważyć jedynie wpływ czasu wciśnięcia przycisku, podczas którego występował wielokrotny przebieg pętli programu, co skutkowało migotaniem diody do momentu zwolnienia przycisku. Czas występowania stanu niskiego na wejściu mikrokontrolera był dłuższy niż czas przebiegu pętli programu. Stan diody po zwolnieniu przycisku zależał, w którym przebiegu pętli przycisk został zwolniony. Wpływ drgań styków widoczny był na ekranie oscyloskopu w postaci zaburzeń w szerokości impulsów.

 

Rys. 2. Wpływ drgań styków.

 

Zjawisko drgań styków występuje zarówno podczas wciśnięcia przycisku, jak i jego zwolnienia. Aby mikrokontroler właściwie interpretował wciskanie przycisku konieczne jest wyeliminowanie samego zjawiska, lub skutków drgań styków powstałych po wciśnięciu i zwolnieniu przycisku. Zjawisko drgań styków możemy wyeliminować sprzętowo, natomiast programowo możemy wyeliminować tylko ich skutki. Który ze sposobów wybrać zależy tylko i wyłącznie od tego co chcemy osiągnąć.

 

Sprzętowa eliminacja drgań styków.

 

Metodą sprzętową wyeliminujemy zjawisko, które występuje w momencie wciśnięcia i zwolnienia. Zaletami sprzętowej eliminacji drgań styków są eliminacja zakłóceń elektromagnetycznych powstających podczas zmiany stanu styków, uproszczenie programu, a tym samym brak jego spowalniania. Wady natomiast związane są z kosztami wykonania, gdyż konieczne jest zwiększenie ilości elementów oraz przeznaczenie dodatkowego miejsca na płytce drukowanej. Realizuje się ją stosując filtr RC. Schemat podstawowego rozwiązania widoczny jest na rysunku 3.

 

Rys. 3. Eliminacja drgań styków za pomocą filtru RC.

 

Przeanalizujmy obwód widoczny na rysunku 3. Przyjmijmy, że napięcie zasilania jest włączona, a układ znajduje się w stanie ustalonym, przycisk S jest rozwarty. W chwili wciśnięcia przycisku zwierane są jego styki. Następuje rozładowanie kondensatora przez rezystancję R2. Potencjał na kondensatorze C osiąga po czasie wartość 0 względem GND. W momencie zwolnienia przycisku następuje rozwarcie styków i kondensator jest ładowany przez rezystancję R1. Dioda D niweluje wpływ rezystancji R2. Po czasie na kondensatorze potencjał osiąga wartość Vcc względem GND. Mamy tu do czynienia z rozładowaniem i ładowaniem kondensatora. Czas obu procesów uzależniony jest od stałej RC układu. W celu zobrazowania przebiegu napięć na kondensatorze w czasie ładowania i rozładowywania kondensatora możemy posłużyć się ich charakterystykami napięciowo czasowymi.

 

Rys. 4. Charakterystyki napięciowo czasowe ładowania i rozładowania kondensatora.

 

Aby zrealizować sprzętową eliminację drgań styków należy wziąć pod uwagę przy jakich wartościach napięć występują odpowiednie stany logiczne. Informacji tych szukamy w dokumentacji mikrokontrolera. Dla ATmega32 napięcie stanu niskiego zawiera się w granicach od -0,5 V do 0,2Vcc, natomiast stanu wysokiego od 0,6Vcc do Vcc+0,5 V. Musimy brać pod uwagę najwyższe napięcie stanu niskiego oraz najniższe napięcie stanu wysokiego gwarantujące prawidłowe odczytanie stanu logicznego na wejściu. Wartości tych napięć wynoszą odpowiednio 1 V oraz 3 V. Drgania styków będą powodowały wydłużenie czasu ładowania i rozładowywania kondensatora.

 

Rozpatrzymy przypadek wciśnięcia przycisku i określmy parametry układu dla podania stanu niskiego na wejście mikrokontrolera. Skorzystamy zatem z równania opisującego zależność napięcia od czasu na kondensatorze podczas rozładowania.

 

Uc(t)=Ue^{-\frac{t}{R2C}}

 

Musimy określić wartości elementów R1, R2 i C oraz czas w jakim ma być osiągnięte wymagane napięcie na wejściu mikrokontrolera. Określmy zatem wymagania układu. Mikrokontroler powinien dość szybko reagować na wciśnięcie przycisku, czyli interesuje nas jak najkrótszy czas. Przyjmijmy zatem, że 10 ms będzie czasem w jakim napięcie na wejściu ma osiągnąć wartość 1 V przy napięciu początkowym 5V. Z uwagi, że łatwiej dobrać rezystor niż kondensator, przyjmijmy wartość pojemności kondensatora równą 100 nF. Pozostaje nam do wyliczenia wartość rezystancji R2. Przekształcając podane równanie otrzymujemy wzór na obliczenie rezystancji w postaci:

 

R2=\frac{-t}{Cln(\frac{U_{L}}{U_{Z}})}

Gdzie:

R2 - Wartość rezystancji R2

t - Czas w jakim napięcie na wejściu mikrokontrolera ma osiągnąć stan niski

C - Wartość pojemności kondensatora C

UL - Najwyższe napięcie stanu niskiego

UZ - Napięcie zasilania

 

Podstawiając wartości do wzoru i dokonując obliczeń otrzymujemy wartość rezystancji, która wynosi w przybliżeniu 62 k\Omega. Kolej na obliczenie  wartości rezystancji R1, przez którą kondensator jest ładowany aby w czasie 10 ms osiągnąć wartość 3V, czyli najniższego napięcia stanu wysokiego przy zasilaniu napięciem 5V. Korzystać będziemy z równania dla zależności napięcia od czasu na kondensatorze w czasie ładowania.

 

Uc(t)=U(1-e^{-\frac{t}{R2C}})

 

Przekształcając równanie otrzymujemy wzór na rezystancję R, przez którą ładowany jest kondensator.

 

R1=\frac{-t}{Cln(1-\frac{U_{H}}{U_{Z}})}

Gdzie:

R1 - Wartość rezystancji R1

t - Czas w jakim napięcie na wejściu mikrokontrolera ma osiągnąć stan wysoki

C - Wartość pojemności kondensatora C

UH - Najwyższe napięcie stanu niskiego

UZ - Napięcie zasilania

 

Wykonując obliczenia otrzymujemy, że rezystancja R1 ma wynosić około 109 k\Omega. Z uwagi, że Rezystancja R1 jest większa od rezystancji R2 można zaniechać stosowania diody i wykorzystać szeregowe połączenie rezystorów R1 i R2 w przypadku ładowania kondensatora. Uzupełnijmy więc schemat o wartości elementów. Wartości będą dopasowane dla szeregu E24.

 

Rys. 5. Schemat układu eliminacji drgań styków dla ATmega32 bez załączonego rezystora pull-up.

 

Wyniki naszych obliczeń postanowiłem sprawdzić w rzeczywistości. Za pomocą oscyloskopu zmierzyłem czasy rozładowania i ładowania kondensatora C do założonych poziomów napięć.

 

Rys. 6. Rozładowanie kondensatora.

 

Rys. 7. Ładowanie kondensatora.

 

Rysunki 6 i 7 przedstawiają przebiegi napięcia podczas rozładowywania i ładowania kondensatora po naciśnięciu i zwolnieniu przycisku. Czasy rozładowania i ładowania są nieznacznie różne. Wynika to z tolerancji użytych elementów, a także z występowania zjawiska drgania styków. Niemniej jednak czasy są porównywalne i oscylują w granicach 10 ms. Można uznać, że obliczenia są prawidłowe. Na oscylogramach widać, że zbocza są wygładzone i nie występują żadne anomalie. Stosując takie rozwiązanie nie powinno włączać się wewnętrznego rezystora pull-up, gdyż nie można dokładnie kształtować krzywej rozładowania kondensatora. Czas ładowania i rozładowania w granicach 10 ms gwarantuje poprawne działanie mikrokontrolera, a jego wejście jest odstresowane. Nie występują bardzo szybkie zmiany napięcia, a co za tym idzie i prądu. Zatem nie powstają zakłócenia elektromagnetyczne. Eliminuje to możliwość uszkodzenia mikrokontrolera ze strony przycisku.

 

Programowa eliminacja skutków drań styków.

 

W przeciwieństwie do sprzętowego, programowo możemy zniwelować jedynie skutki drgań styków, które będą wpływały na wejście mikrokontrolera, lecz program nie będzie na nie wrażliwy. Realizuje się to manipulując czasem reakcji na wciśnięcie przycisku. Po pierwszym wystąpieniu zmiany stanu na wejściu należy ponownie sprawdzić stan po określonym czasie i dopiero w przypadku, gdy zmiana będzie utrzymana wykonać procedurę obsługi przycisku. Czas jaki trzeba przyjąć, aby pominąć ewentualne drgania styków nie może być mniejszy niż najdłuższy czas ich występowania. W dokumentacji technicznej przycisku producenci umieszczają zwykle czas drgań styków jako bounce time. Nie zawsze można w ten sposób określić czas drgania styków, więc można przyjąć bezpiecznie, że czas ponownego sprawdzenia stanu na wejściu nie może być krótszy niż 20 ms. Dłuższy czas można wybierać dowolnie, lecz należy zwrócić uwagę na najczęstszy sposób korzystania z przycisku. 20 ms gwarantuje liczbę wciśnięć pa poziomie 25 na sekundę, co zapewnia, że żadne wciśnięcie przycisku przez człowieka nie zostanie pominięte.

Najprostszy sposób programowej eliminacji skutków drgań styków zaprezentowany został w artykule Obsługa przycisku część pierwsza. Zastosowane tam funkcje opóźniające zapewniały prawidłowe działanie programu, lecz zatrzymywały wykonywanie programu. W przypadku aplikacji wykonującej wiele zadań, na przykład kontrola procesu technologicznego, stosowanie funkcji opóźniających w pętli programu jest niedopuszczalne, gdyż w czasie zatrzymania programu może zaistnieć sytuacja, gdzie mikrokontroler powinien wykonać określone działania natychmiast po ich wystąpieniu. Mikrokontroler nie zarejestruje stanu czujników i proces technologiczny będzie zakłócony.  Należy więc tworzyć programy tak, aby ich wykonywanie nie było zatrzymywane w żadnym momencie.

Takim rozwiązaniem może być również prosty sposób z zastosowaniem inkrementacji zmiennej. Realizacja tego sposobu polega na wykonaniu procedury reakcji na pierwszą zmianę stanu na wejściu ignorując kolejne. Dodamy więc zmienną, która zablokuje nam tą reakcję już po pierwszym wystąpieniu stanu niskiego na wejściu. Nazwijmy ją lock. Przy każdym przebiegu pętli programu zmienna ta będzie inkrementowana, aż do jej przepełnienia, gdzie zostanie wyzerowana i program będzie mógł ponownie obsłużyć przycisk.

 

#include < avr/io.h > /*Dołączenie biblioteki z definicjami rejestrów i bitów I/O*/
#define F_CPU 16000000UL /*Definicja stałej określająca częstotliwość taktowania mikrokontrolera dla funkcji delay.h*/
#include < util/delay.h > /*Dołączenie biblioteki z funkcjami opóźnień*/
#define LED (1 << PA0) /*Definicja stałej określającej pin do którego podłączona jest dioda LED*/
#define BUTTON (1 << PA1) /*Definicja stałej określającej pin, do którego podłączony jest przycisk*/

uint_8 lock = 0;

int main(void) {
   /*Ustawienie wszystkich pinów jako wyjścia. Wszystkie wyjścia mają stan niski*/
   DDRA = 0xFF;
   DDRB = 0xFF;
   DDRC = 0xFF;
   DDRD = 0xFF;
	
   DDRA &= ~BUTTON; /*Ustawienie pinu PA1 jako wejście. Zapisanie wartości 0 do bitu nr 1 rejestru DDRA)*/
   PORTA |= BUTTON; /*Załączenie rezystora podciągającego na pinie PA1. Zapisanie wartości 1 do bitu nr 1 rejestru PORTA*/
   _delay_ms(10); /*Zatrzymanie programu na 10 ms celem załączenia rezystora podciągającego i ustalenia się stanu wysokiego na wejściu.*/
	
   while (1) {
      if(!(PINA & BUTTON) && !lock) /*Reakcja na wciśnięty przycisk. Reakcja na stan niski na pinie PA1, gdy zmienna lock = 0*/
      { 
         lock++; /*zwiększenie zmiennej lock o 1*/
         PORTA ^= LED; /*Zmiana stanu na pinie PA0*/
      } else if((PINA & BUTTON) && lock) { /*sprawdzenie warunku czy stan na pinie PA1 jest wysoki i czy zmienna lock jest różna od 0*/
         lock++; /* jeżeli warunek jest pełniony zwiększenie zmiennej lock o 1*/
      }
    }
}

 

Przeanalizujmy teraz działanie programu. Po włączeniu zasilania zmienna lock ma wartość 0, a na wyjściu PA0 jest stan niski, czyli dioda jest zgaszona. Wciskając przycisk podajemy na wejście PA1 stan niski. Wartość zmiennej lock jest równa 0. Spełniony jest więc warunek wykonania reakcji na wciśnięcie przycisku i zmienna lock zwiększana jest o 1, a na wyjście PA0 podawany jest stan wysoki, czyli dioda zapala się, Wszystko dzieje się w momencie pierwszego wystąpienia stanu niskiego na wejściu PA1. Jeżeli wystąpią drgania styków, czyli stan na wejściu PA1 zmieni się z niskiego na wysoki i ponownie na niski, nie przyniesie to żadnego rezultatu, gdyż zmienna lock ma ustawioną wartość większą od 0. Tym samym drgania styków przestają nas interesować. Stan wysoki pojawiający się na wejściu PA1 spowodować może jedynie kolejne zwiększenie zmiennej lock o 1. Inkrementacja zmiennej lock wykonywana jest tylko i wyłącznie przy stanie wysokim na wejściu PA1 i gdy zmienna lock ma wartość większą od 0. Ponowna reakcja na wciśnięcie przycisku jest możliwa, gdy zmienna lock samoczynnie się wyzeruje, co nastąpi po osiągnieciu przez nią wartości 255 i wykonaniu kolejnej inkrementacji. Po tym program będzie gotowy na ponowne wciśnięcie przycisku.  Sposób ten jest prosty i skuteczny. Nie powoduje zatrzymywania programu i jest odporny na drgania styków. Praktycznie każdy przycisk może być obsłużony za pomocą tego programu. Jeżeli zdarzyłoby się, że pomimo zastosowania tego sposobu wpływ drań styków spowodowałby błędne funkcjonowanie układu, to oznaczać może, że przycisk nie jest odpowiedni do współpracy z urządzeniami cyfrowymi, a w szczególności z mikrokontrolerami.

Zmodyfikujmy zatem kod programu z migającą diodą. Na listingu przedstawiony tylko fragment kodu, w którym dokonano zmian.

 

while(1) {
   if(!lock && !(PINA & BUTTON)) /*Reakcja na wciśnięty przycisk. Sprawdzenie, czy zmienna lock ma wartość 0 i czy występuje stan niski na pinie PA1*/
   { 
      lock = 1; /*Zapisanie do zmiennej lock wartości 1. Zablokowanie klawisza.*/
      blink = (blink == 0)? 1 : 0; /*Zmiana wartości zmiennej blink między wartościami 1 i 0*/
   } else if (lock && (PINA & BUTTON)) /*Sprawdzenie czy zmienna lock ma wartość 1 i czy na pinie PA1 jest stan wysoki. Sprawdzenie, czy przycisk został zwolniony.*/
   {
      lock++; /*Zwiększenie zmiennej lock o 1*/

   }

 

Prosta modyfikacja, która została zastosowana spowodowała, że program odporny jest na skutki drgań styków i jednocześnie nie jest spowalniany przez funkcje opóźniające w procedurze obsługi klawisza, pozostały jeszcze w funcji zmieniającej stan wyjścia PA0. Czeka nas jeszcze wyeliminowanie i tego opóźnienia, ale najpierw zapoznamy się z przerwaniami i timerami.

 

Autor: Orici
Literatura
1. Bolkowski S. Elektrotechnika, WSiP, Warszawa 1993
Wyświetleń: 3831|Komentarzy: 0|Ocena: 0|Głosów: 0