czwartek, 10 marca 2016

Wejście - Hello from the other side

Czy jest na sali tłumacz?!

Nasze urządzenie powinno umieć się z nami komunikować. Komunikacja jest ważna. Jak mamy być Agile, skoro komunikacja szwankuje. Mruganie diodą to sposób, w jaki Atmega nas informuje o jakimś istotnym wydarzeniu z jej zapętlonego życia - w najprostszym przypadku o rozkazie zmiany stanu na określonym pinie. Bardzo niskopoziomowy sposób pracy (poziom zmiany napięć) jest "tłumaczony na nasze zmysły" przy pomocy świecącej diody.
 Co musimy zrobić, żeby mikrokontroler zdał sobie sprawę, że oczekujemy od niego podjęcia jakiejś akcji? Przetłumaczyć "nasze" na "jego". Weźmy dotyk. My czegoś dotykamy, procesor wie, że czegoś od niego chcemy.

Input port

W tym celu musimy wykonać pracę odwrotną do załączania diody. Krok pierwszy - konfiguracja pinu jako wejście. Wykorzystajmy ponownie "rejestr kierunkowy".

DDRB &= ~(1 << PB3);


Gdy pin jest skonfigurowany jako wejście, rejestr PORTx służy do załączania rezystora podciągającego do zasilania. Jakkolwiek zagmatwanie to nie brzmi - włączmy to, przyda się :)

PORTB |= (1<<PB3);


Teraz, żeby odczytać stan pinu musimy się dobrać do rejestru PINx. Rejestr PINx możemy sobie zapisać do zmiennej i szukać stanu interesującego nas bitu (0b00000100 odczytane z PINB powie nam, że PB3 znajduje się w stanie wysokim) albo skorzystać ze skróconego i czytelnego zapisu

PINB & (1 << PB3);


który możemy opakować w konstrukcję if, gdyż prędzej czy później użyjemy wiedzy o stanie pinu do podejmowania istotnych dla programu decyzji.

Button

Krok drugi - przetłumaczenie ruchu na zmianę napięcia. W tym celu posłuży nam przycisk, który podpięty do mikrokontrolera i do masy (GND, poziom 0), po naciśnięciu sprawi, że na nóżce mikrokontrolera zmieni się stan. Weźmy najprostszy - tact-switch (to ten typ, który naciskasz długopisem albo szpilką jak chcesz zrestartować Twój stary router).

Transoptor

O transoptorze było już ostatnio - dla przypomnienia - dioda i fototranzystor zalane w jednej obudowie, "załączenie" diody sprawia, że tranzystor zaczyna przewodzić. Izolacja galwaniczna. Ten wdzięczny element możemy wykorzystać też w tym przypadku - wystarczy go podpiąć "odwrotnie". Naciśnięcie przycisku sprawi, że dioda się zaświeci, a działający tranzystor wymusi zmianę napięcia na pinie kontrolera

Kodzik!

Wiedząc, że prawidłowo skonfigurowany pin wejściowy posiada tylko 2 stany (1 i 0) mamy pełne prawo do użycia else. Zatem niech naszą wolą będzie załączenie diody gdy przycisk jest naciśnięty.

#include <avr/io.h>

int main(void)
{
   // pb0 - output
   DDRB |= (1 << PB0);
 
   // pb3 - input
   DDRB &= ~(1 << PB3);
 
   // pull-up for pb3
   PORTB |= (1 << PB3);
    
   // turn off led
   PORTB |= (1 << PB0);
 
   while (1)
   {
      if ((PINB & (1 << PB3)) == 0)
      {
         PORTB &= ~(1 << PB0);
      }
      else
      {
         PORTB |= (1 << PB0);
      }
   }
}


Dlaczego to zadziała?

Gdy nie naciskamy przycisku, na naszym pinie występuje stan wysoki (dzięki jego ekscelencji rezystorowi pull-up - "podciągającemu" - wyrównuje on napięcie na nóżce do napięcia logicznej 1, jeżeli już jesteś jego psychofanem - nie lękaj się! pull-up powróci w kolejnych postach!). Naciskając przycisk zwieramy obwód do masy. Prąd jest leniwym stworzeniem i szuka sobie najłatwiejszej drogi "przepływu" - o jak najmniejszym oporze - więc popłynie przez nasz przycisk - omijając mikrokontroler - a ten z braku przepływu prądu zreflektuje się, że gdzieś tam na jego nóżce jest 0 i skasuje 1 z rejestru PINx odpowiedzialnego za trzymanie tego stanu.


Dlaczego to nie zadziała?

Tyle w teorii. Teraz praktyka. Gdy naciśniemy przycisk, nasza dioda może zacząć nerwowo mrugać. Ale spokojnie, to nie oznacza, że od razu musimy ją wieźć do specjalisty. Co zaszło? Wszelkie mechaniczne połączenia nie są idealne, nie stykają się ze sobą w czasie t0. Ba! Styki naciśniętego przycisku nie zawsze stykają się idealnie, co powoduje przeskoki ładunku elektrycznego, co z kolei zmiany napięcia zauważalne przez nasz mikrokontroler. Zatem wszystko działa w zgodzie z powszechnie znanymi prawami. No OK, ale my nie chcemy, żeby nam ta dioda mrugała. W tym celu należy wyeliminować wspomniane drgania. Jak? Sprzętowo albo programowo.

Drgania zestyków mogą trwać krótko względem czasu, który będziemy trzymać przycisk - dlatego między kolejnymi odczytami stanu pinu możemy chwilkę zaczekać. Czas oczekiwania dobieramy eksperymentalnie - dopasowujemy do najlepszych zasad UX dotyczących naciskania przycisków, jakie nam przyjdą do głowy i okazuje się, że _delay_ms(200); jest w sam raz!  Niekoniecznie... Polecam zabawę z inkrementacją zmiennej i dołożenie do ifa sprawdzenia, czy ta zmienna ma wartość 0.

Rozwiązanie sprzętowe jest bardziej wdzięczne - nie wymusza na procesorze przebywania większości swojego życia w trybie oczekiwania. Każdy by się zirytował - szkoda na to prądu.
Wepnijmy zatem równolegle do przycisku kondensator ceramiczny 100nF. Powinno być o wiele lepiej :)

No dobrze, a co ja z tego będę miał?

...dozgonną sąsiedzką satysfakcję. I możliwość podpięcia czegokolwiek, co zamknie albo otworzy obwód elektryczny. Najprostszy przykład - zamontujmy przycisk we framudze drzwi. W momencie, gdy drzwi są zamknięte, układ jest zwarty, wszystko działa jak należy, gdy ktoś otworzy drzwi, nasz procesor powinien rozpocząć procedurę informowania o włamaniu - zaświecić wszystkim co ma i zacząć krzyczeć na lewo i prawo, że ktoś go próbuje ukraść.


Ta wiedza pozwoli Ci rozwijać projekty:
Alarm
Klawiatura

Brak komentarzy:

Prześlij komentarz