Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

czwartek, 3 marca 2011

EPP: Eliminacja drgań styków by ky3orr

Autor: ky3orr
Redakcja: dondu


Tematem zadania jest eliminacja drgań styków klawiatury złożonej z przycisków chwilowych zwiernych określone tutaj .

Układ testowy zrealizowałem tak:
  • mikrokontroler wystawia na pin logiczną jedynkę (przez załączenie wewnętrznego rezystora podciągającego do Vcc, zaś wciśnięty przycisk zwiera go do masy (GND). 
  • gdy przycisk jest zwolniony mikrokontroler odczytuje wartość logiczną wejścia jako 1, gdy przycisk zostanie wciśnięty mikrokontroler odczytuje wartość logiczną wejścia jako 0.

Aby na drodze programowej móc obsługiwać tak prostą klawiaturę należy uwzględnić opóźnienie, w czasie którego przycisk powinien pewnie złapać lub stracić kontakt. Nie uwzględnienie zjawiska drgań styków prowadzi do błędnych odczytów i działania programów korzystających z klawiatury (np. zmiana w menu o kilka pozycji podczas jednego przyciśnięcia przycisku). Więcej na ten temat dowiesz się z tego artykułu: Przycisk - drgania styków - bouncing

Zaproponowane przeze mnie rozwiązanie programowej eliminacji drgań styków opiera się o następujący, prosty, algorytm:

Rys. 1 - Algorytm deboucingu


Wydzielony obszar pamięci (w zadaniu: stan_przyciskow) zawiera informację o wartościach logicznych dla poszczególnych przycisków klawiatury. Obszar ten jest typu globalnego (zmienna globalna volatile), dzięki temu możliwe jest przekazywanie informacji wypracowanej przez program obsługi klawiatury do programu głównego lub innego dowolnego fragmentu programu.

Idea eliminacji drgania styków przycisku polega na:
  1. wykryciu faktu jego wciśnięcia lub puszczenia (zmiana ostatniego stabilnego stanu logicznego, występującego na odpowiadającym pinie mikrokontrolera, na przeciwny), 
  2. odczekaniu zdefiniowanego czasu (czasu drgania styków) 
  3. ponownym sprawdzeniu, czy nowy wymuszony stan logiczny nadal się utrzymuje. 
Jeśli tak jest oznacza to, że przycisk pewnie zmienił swoje położenie i należy przekazać do programu głównego zaktualizowaną informację o stanie klawiatury.

W przeciwnym wypadku uznaje się, że nastąpiło drganie zatem nie ma potrzeby aktualizowania informacji o stanie klawiatury.

Sytuacja stanów przejściowych polegających na drganiu styków podczas przełączania zobrazowana jest na rysunku poniżej (ze względów programistycznych wartość dla stanu stabilnego w przypadku wciśnięcia przycisku = 1).

Rys. 2 - Drgania styków w czasie naciśnięcia i puszczenia przycisku.


Aby pewnie wykrywać zmianę stanu przycisków klawiatury należy zapewnić odpowiedni czas zwłoki (rys: 3):

czas zwłoki >= MAX(t1, t2).

W praktyce zwłoka od 10ms do 20ms jest wystarczająca, ale spotyka się przyciski, które wymagają większych czasów.

Zatem należy cyklicznie badać stan wejścia, do którego podłączony jest przycisk i po wykryciu jego zmiany odczekać ustalony czas po czym ponownie zbadać stan wejścia. Jeśli nowy stan jest inny niż ostatnio wykryty stan stabilny oznacza to, że nastąpiło przełączenie.

Algorytm działa jednakowo tak w przypadku wciśnięcia jak i puszczenia przycisku. Zobrazowane to jest na poniższym rysunku.

Rys. 3 - Działanie algorytmu deboucingu.

W związku z powyższym należy cyklicznie badać stan pinów klawiatury i zapewnić możliwość odczekania zadanego czasu po wykryciu zmian w położeniach przycisków.

Esencją zadania jest opracowanie sposobu na obsługę klawiatury bez użycia funkcji opóźniających _delay(), które blokując wykonywanie się programu głównego wpłynęłyby na jego wydajność.

Zdecydowałem się na wykonanie obsługi klawiatury w programie obsługi przerwania timer0. Dodatkowo położyłem nacisk na dowolną konfigurację pinów przypisanych do klawiatury, co umożliwi swobodne projektowanie płytki drukowanej.

Program jest w miarę dobrze wyposażony w komentarze więc nie ma potrzeby jego omawiania. Zwrócę jednak uwagę na jego istotę. Otóż realizacja opóźnienia polega na zliczaniu ilości przepełnień timer0, które występuje, co około 2ms.

Zatem jeśli stan logiczny na wejściu mikrokontrolera po upływie zadanego czasu jest inny niż poprzednio zapisany w stan_przyciskow następuje aktualizacja informacji na odpowiedniej pozycji bitowej tej zmiennej. Dodatkowe tablice służą automatyzacji kodu obsługującego jednocześnie wszystkie przyciski klawiatury.
// EPP - Drgania stykow - zmora poczatkujacych
// Algorytm programowej obslugi drgajacych przyciskow
//  
// ky3orr, 2012.02.26  
// http://www.serwis-elektroniki.prv.pl
// ky3orr<mawpa>gmail.com
//  
// Atmega8, zegar 1[Mhz]

#define F_CPU 1000000UL     //wartosc sygnalu zegarowego w [Hz]

#define KEYBOARD_DEBOUNCE_MS 20   //czas zwloki debouncera w [ms]

#define KEY1_PIN PB0     //definicja klawiatury
#define KEY1_PORT PORTB
#define KEY1_PIN_REG PINB
#define KEY1_DIR DDRB
#define KEY2_PIN PB1
#define KEY2_PORT PORTB
#define KEY2_PIN_REG PINB
#define KEY2_DIR DDRB
#define KEY3_PIN PB2
#define KEY3_PORT PORTB
#define KEY3_PIN_REG PINB
#define KEY3_DIR DDRB
#define KEY4_PIN PB3
#define KEY4_PORT PORTB
#define KEY4_PIN_REG PINB
#define KEY4_DIR DDRB

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile uint8_t stan_przyciskow;  //4LSB zawieraja informacje o stanie 
                                   //przyciskow 1-wcisniety, 0-wolny
volatile uint8_t stable_state[4];  //tablica do szybkich operacji w petli
volatile uint8_t debounce_timer[4];  //tablica do szybkich operacji w petli


void SetupKeyboard (void) {    //konfiguracja klawiatury
 KEY1_DIR &= ~(1<<KEY1_PIN);   //pin przycisku jako wejscie
 KEY1_PORT |= (1<<KEY1_PIN);   //podciagniecie pinu do VCC
 KEY2_DIR &= ~(1<<KEY2_PIN);
 KEY2_PORT |= (1<<KEY2_PIN);
 KEY3_DIR &= ~(1<<KEY3_PIN);
 KEY3_PORT |= (1<<KEY3_PIN);
 KEY4_DIR &= ~(1<<KEY4_PIN);
 KEY4_PORT |= (1<<KEY4_PIN); 
}


void InitDebounceTimer (void)  //konfiguracja timera0
{
  TCNT0 = 0x1;    //zmiana ustawien powinna byc dla wartosci !0xFF i !0x0
  TCCR0 |= (1<<CS01);   //preskaler = 8 (dla 1[MHz] przepelnienia co 2.048[ms])
  TCCR0 &= ~((1<<CS00) | (1<<CS02));
  TIMSK |= (1<<TOIE0);  //obsluga przerwania od przepelnienia
}


void SetupHardware (void) 
{
  ACSR &= ~(1<<ACD);    //wylaczenie zbedznie pracujacego ACD
  SetupKeyboard();
  InitDebounceTimer();
}


ISR(TIMER0_OVF_vect) 
{
  uint8_t key_value[4];  //tablica wartosci dla klawiatury

  //odczyt klawiatury (przycisk: 1->wcisniety, 0-wolny)
  if(KEY1_PIN_REG & (1<<KEY1_PIN)) {key_value[0] = 0;} else {key_value[0] = 1;}
  if(KEY2_PIN_REG & (1<<KEY2_PIN)) {key_value[1] = 0;} else {key_value[1] = 1;}
  if(KEY3_PIN_REG & (1<<KEY3_PIN)) {key_value[2] = 0;} else {key_value[2] = 1;}
  if(KEY4_PIN_REG & (1<<KEY4_PIN)) {key_value[3] = 0;} else {key_value[3] = 1;}
 
  for(uint8_t i = 0; i < 4; i++) {  //obsluga kazdego przycisku z osobna
   if(debounce_timer[i] > 0) {   //gdy odmierzanie czasu zwloki
    if((--debounce_timer[i] == 0) && (stable_state[i] ^ key_value[i])) {
     stable_state[i] ^= 0x1;  //aktualizacja stanu klawiatury gdy koniec zwloki
     stan_przyciskow ^= (1<<i); //i zmienil sie stan logiczny na wejsciu
    }
   } else {       //skanowanie klawiatury
    if(stable_state[i] ^ key_value[i]) { //wykrycie zmiany stanu
     debounce_timer[i] = KEYBOARD_DEBOUNCE_MS / 2; //ustawienie czasu zwloki
    }
   }
  }
}  


int main(void) 
{
  sei();     //wlaczenie obslugi przerwan
  SetupHardware();  //konfiguracja sprzetu
  while(1) {    //petla glowna programu
  
    //kod programu korzystajacy ze zmiennej -> stan_przyciskow
  
  }
}
Komentarz Dondu:
To bardzo ciekawy algorytm radzenia sobie z problemem drgań styków. W szczególności w tym rozwiązaniu podoba mi się jego elastyczność, ułatwiająca szybką zmianę pinów, do których podpinamy przyciski.

Może to być bardzo przydatne, szczególnie na etapie budowania prototypów, ponieważ w czasie projektowania PCB często zdarza się, że warto przycisk podłączyć pod inny pin niż jest to na pierwotnym schemacie, by na PCB łatwiej rozmieścić elementy lub ścieżki. W takiej sytuacji wystarczy zmienić definicje przycisku na początku programu. :-)


Zobacz inne rozwiązania problemu drgań styków: 
Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

1 komentarz:

  1. Co się dzieje jak są 2 przyciski wciśnięte ?

    Mirek

    OdpowiedzUsuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.