Mikrokontrolery - Jak zacząć?

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

czwartek, 3 marca 2011

EPP: Eliminacja drgań styków by xxx-xxx001

Autor: xxx-xxx001
Redakcja: dondu


Tematem dot. zadania eliminacji drgań styków klawiatury.

Mój program eliminuje drgania styków w przerwaniu. W każdym wywołaniu przerwania sprawdzany jest jeden z przycisków. Tylko jeden. Dzięki temu przerwanie trwa krócej i mniej ingeruje w wykonywany poza nim program.


Do zadania użyłem układu testowego zaprojektowanego tak:


Schemat Eagle 6:  schemat.zip

Do realizacji przerwania użyłem Timer0. Wybrałem go, ponieważ jest najmniej użytecznym timerem do innych celów. Nie pozwala na dokładną regulację częstotliwości i nie obsługuje sprzętowego PWM. Na szczęście w tym zastosowaniu precyzyjna regulacja częstotliwości nie jest konieczna.

//EPP: Drgania styków - zmora początkujących
//17 lutego 2012r.
//Kod napisany dla ATmega8
//Autor: xxx-xxx001
//dla: http://mikrokontrolery.blogspot.com

//Rozmiar:
// Program:     386 bytes (4.7% Full)
// (.text + .data + .bootloader)

// Data:          6 bytes (0.6% Full)
// (.data + .bss + .noinit)

//----------------------------------------------------------------------------
//Definicje stałych
#define F_CPU 8000000              //Częstotliwość taktowania 8MHz
#define Liczba_T 10                //Liczba testów przycisku

//----------------------------------------------------------------------------
//Biblioteki
#include <avr/io.h>                //Potrzebne biblioteki
#include <avr/interrupt.h>
#include <util/delay.h>

//----------------------------------------------------------------------------
//Definicje funkcji
void Init();

//----------------------------------------------------------------------------
//Potrzebne zmienne
volatile char stan_przyciskow;      //Zmienna zawierająca stabilny stan 
                                    //przycisków

volatile char licznik[]={0,0,0,0};  //Tablica liczników, każdy licznik ma
                                    //swoją komórkę w tebeli

volatile char flag =0;              //Flaga wskazująca na przycisk który
                                    //jest aktualnie testowany

//----------------------------------------------------------------------------
//Główna funkcja programu

int main()
{
  Init();                           //Wywołanie funkcji konfigurującej 
                                    //Timer0 i porty IO

  char port = 0;

  while(1) //Pętla główna programu
  {
    //tutaj Twój kod ...

    //przykład wykorzystania zmiennej globalnej: stan_przyciskow
    if(stan_przyciskow!=0)          //Jeśli któryś z przycisków
    {                               //jest naciśnięty
      port = port^stan_przyciskow;  //Zamień stan diody która mu
      PORTC = port;                 //odpowiada na przeciwny
      _delay_ms(250);               //Odczekaj 1/4 sekundy
    }
  }
}

//----------------------------------------------------------------------------
//Funkcja włączająca potrzebne układy i zajmująca się innymi nie ciekawymi
//rzeczami :-)

void Init()
{
  //-------------------
  //Konfiguracja Timer0
  TCCR0 |= _BV(CS00) | _BV(CS01);    //Uruchamiamy Timer0, preskaler 64
  TIMSK |= _BV(TOIE0);               //Zezwalanie na  przerwania
  
  //-------------------
  //Włącz przerwania globalne
  sei();       

  //-------------------  
  //Konfiguracja portów
   DDRC = 0b00001111;                //Pierwsze 4 piny portu C wyjściowe
   DDRB = 0;                         //Port B wejściowy (przyciski)

   PORTC = 0b00001111;               //Zaświeć diody i
   PORTB = 0b00001111;               //włącz PULL-UP dla przycisków
}


//----------------------------------------------------------------------------
//Obsługa przerwania od przepełnienia Timer0

ISR(TIMER0_OVF_vect)
{
  if(flag>=4)                    //Jeśli zostały przetestowane wszystkie 
    flag=0;                      //przyciski to ustaw flagę na pierwszy z nich
 
  //-----------------------
  //Testowanie przycisków
  if(bit_is_clear(PINB, flag))

    if(licznik[flag] < Liczba_T)    //Jeśli przycisk jest wciśnięty,
    licznik[flag] += 1;              //a licznik mniejszy od ustalonej
                                     //watrości dodaj 1 do licznika

  if(bit_is_set(PINB, flag))         //Jeśli przycisk nie jest aktywny
    licznik[flag] = 0;               //wyzeruj cały licznik

  if(licznik[flag] == Liczba_T)      //Jeśli licznik osiągnął wymaganą
    stan_przyciskow |= _BV(flag);    //ilość zaliczonych testów ustaw bit
                                     //odpowiadający właściwemu 
                                     //przyciskowi

  if(licznik[flag] == 0)             //Jeśli wykryty został stan wysoki
    stan_przyciskow &= ~_BV(flag);   //(przycisknie jest wciśnięty) wyzeruj
                                     //bit odpowiadający odpowiedniemu
                                     //przyciskowi

  flag++;                            //Inkrementuj flagę przycisku      
}
Projekt AVR Studio z plikiem C: deboucing.zip

Kiedy Timer0 przepełni się, program sprawdza, czy przycisk jest wciśnięty. Jeśli tak, do odpowiedniej komórki tablicy licznik[] dodajemy jeden. Jeśli jednak przycisk nie jest wciśnięty lub jest niestabilny (styki drgają) zerujemy licznik.

Odpowiedni bit w zmiennej stan_przyciskow jest ustawiany dopiero wtedy, gdy licznik doliczy do wartości ustalonej wcześniej jako stała Liczba_T.  Następnie inkrementujemy flagę flag, czyli przechodzimy do następnego przycisku.


Podsumowanie

Wadą tego rozwiązania jest duże zapotrzebowanie na czas procesora (w końcu wszystko jest realizowane przez CPU), choć nie tak jak w pokazanym przykładzie. Procesor nie jest blokowany w oczekiwaniu. Większa jest też pewność wskazań, test jest realizowany dowolną ilość razy (zależną od potrzeb), a nie tylko dwukrotnie.

Niestety, kiedy stosujemy takie rozwiązanie musimy zdecydować się na pewien kompromis. Trzeba znaleźć złoty środek pomiędzy obciążeniem procesora, czasem reakcji i pewnością wskazań. Stała Liczba_T decyduje o ilości testów jaka jest wymagana do uznania przycisku za wciśnięty. Kiedy pomnożymy tą liczbę przez ilość przycisków (w tym przypadku 4), a następnie przez czas pomiędzy przerwaniami, otrzymamy czas opóźnienia reakcji na naciśnięcie przycisku.

Zwiększenie tej stałej gwarantuje lepszą skuteczność, ale zwiększa czas reakcji. Aby uniknąć tego efektu należy zmniejszyć wartość preskalera. Niestety, przekłada się to na większe obciążenie CPU.

Na filmiku widać przykład gdzie specjalnie dobrałem parametry tak, aby było widać, że mikrokontroler sprawdza przycisk przez dłuższy czas, nie reagując na krótkie jego przyciśnięcia. Ale Ty możesz dobrać parametry do swoich potrzeb.




Komentarz Dondu:
W wielu projektach mikrokontroler (jego CPU) się nudzi, kręcąc się bezczynnie w pętli głównej przez bardzo duży procent czasu. W takich przypadkach powyższy sposób eliminacji drgań styków, w niczym nie przeszkadza i jest w pełni akceptowalny.

Co więcej daje on większą pewność eliminacji drgań przycisku, sprawdzając kilka razy (jeden po drugim), czy stan przycisku jest już stabilny. Jeżeli nie, to zaczyna procedurę sprawdzania przycisku od nowa.

Ten algorytm warto stosować, tam gdzie nie może dojść do pomyłki, nawet kosztem zwiększenia długości i częstotliwości skanowania przycisku.

Kompromis - to dobre słowo :-)

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. witam,
    super programik ... ale uwaga - kompiluje się z warning'ami (zmienna flag winna być uint8_t)
    po przeróbce na mega88 wszystko hula
    drobne zmiany kosmetyczne i można przystosować do własnych potrzeb
    gratulacje
    pozdrawiam

    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.