Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Obsługa klawiszy ATmega8, sprawdza który klawisz naciśnięty.

21 Lis 2009 07:27 3611 13
  • Poziom 28  
    Witam. Chcę obsłużyć AT8 dwoma klawiszami. W tym celu w pętli głównej sprawdzam, czy któryś z nich (a może oba) nie zostały naciśnięte. Do tego służy mi:
    Code:
    unsigned char klawisz (void)         //który klawisz
    
    {
       unsigned char aktyw = 0;
       PINB |= _BV(1) | _BV(2);
       _delay_ms(30);
       if (bit_is_clear(PINB,1))
       {
          aktyw = aktyw + 1;
       }
       if (bit_is_clear(PINB,2))   
       {
          aktyw = aktyw + 2;
       }   
       return (aktyw);
    }

    Klawisz() różny od 0 przenosi mnie do:
    Code:
    void nastawy (unsigned char poziom)      //menu ustawienia
    
    {
       switch (poziom)
       {
       case 1:                        // ustaw program
       break;
       case 2:                        // karmienie ręczne
       break;
       case 3:                        //czasy
          poziom += klawisz();
          switch (poziom)
          {
          case 4:                     //zegar
          break;
          case 5:                     //czas karmienia
          break;   
          }   
       break;
       }
    }

    I wszystko jest bardzo pięknie póki używam pojedynczego klawisza. Przy wciśnięciu dwóch na raz (prawie na raz bo nigdy nie uda się wcisnąć idealnie) cały misternie wymyślony plan bierze w łeb. Raz przechodzi do obsługi case 1, innym razem do 2. A jak już uda mu się trafić w 3 to też trzeba mieć szczęście by przejść do tego, które akurat jest potrzebne z 4 - 5. Przyznaję, że są to moje początki z AVR-ami, ale mam nadzieję, że przy pomocy dobrych ludzi z Elektrody uda mi się je polubić.
  • Pomocny post
    Poziom 28  
    Wywal linie:
    PINB |= _BV(1) | _BV(2);

    Ustaw DDRB tak aby mieć wejście na PB1 i PB2
  • Poziom 28  
    :arrow: snow
    To co piszesz mam ustawione.
    Code:
    int main (void)
    
    {
       /*********** Definicje ****************/
       
       DDRB = 0x1;                     // Port B 0 wyjście, reszta wejścia
       PORTB = 0x7;                    // Pin 0,1,2 stan wysoki
    ...
    }

    Ta linia jest tak na wszelki wypadek, żeby, jak ATmedze odbije w dekiel miała piny podciągnięte :D. Myślę, że to raczej nie tu jest pies pogrzebany :cry:.

    PS.
    Na próbę jednak zrobiłem jak radzisz. Różnicy żadnej.
  • Pomocny post
    Specjalista - Mikrokontrolery
    Code:
    unsigned char klawisz (void)         //który klawisz
    
    {
       unsigned char aktyw = 0;
       PINB |= _BV(1) | _BV(2);
       _delay_ms(30);
       if (bit_is_clear(PINB,1) || bit_is_clear(PINB,2))
       _delay_ms(30);
       if (bit_is_clear(PINB,1))
       {
          aktyw = aktyw + 1;
       }
       if (bit_is_clear(PINB,2))   
       {
          aktyw = aktyw + 2;
       }
       return (aktyw);
    }

  • Poziom 28  
    :arrow: michalko12
    Twój kod wprowadza dodatkowe (niepożądane) opóźnienie po sprawdzeniu alternatywy, której (i tu dwa przypadki) nie ma lub jest. Uściślam. W VMLAB-ie na próbie jest. Ale w nim działał i mój kod. W zaprogramowanej ATmedze go nie ma i efekty są jak w pierwszym poście. Ale mimo wszystko dzięki za pomoc. Podtrzymuje mnie to w wierze, że nieprawdą jest, że nikt mnie nie lubi :D.
  • Pomocny post
    Poziom 33  
    Może zrób to inaczej. Podam sam pomysł bo osobiście nie programuję w C więc nie chcę głupot pisać, a podejrzewam że asembler Cię nie interesuje ;) Po naciśnięciu dowolnego przycisku wygeneruj opóźnienie. Po tym opóźnieniu sprawdź jakie przyciski są wciśnięte. Ale zwróć uwagę żeby przy każdej instrukcji if sprawdzać oba piny 1 i 2 portu B. Więc warunek będzie spełniony jak np. jeden przycisk będzie wciśnięty i jednocześnie drugi puszczony. Z tym case 4 i 5 nie wiem co chcesz osiągnąć. Może opisz jak mają działać te przyciski.
  • Poziom 28  
    Przyciski mają działać na zasadzie menu. Zgodnie z kodem po naciśnięciu jedynki wywołuje pierwszą procedurę, po naciśnięciu dwójki wywołuje drugą procedurę, po wciśnięciu dwóch jednocześnie mija dwie pierwsze i przechodzi do trzeciej, w której po sprawdzeniu wciśniętych przycisków wywołuje właśnie procedurę czwartą lub piątą (taka matematyka, że pierwsze wciśnięcie dwóch klawiszy daje rezultat 3 i następne wciśnięcie któregokolwiek dodaje się do niego dając 4 lub 5). Te dwie ostatnie procedury to drugi poziom menu. Mam nadzieję, że jasno ściemniłem? :D
    A z tym opóźnieniem muszę przemyśleć, choć nie chciałbym za bardzo spowalniać działania programu. To, które już zastosowałem jest moim zdaniem wystarczające.

    Dodane:
    A tak na marginesie to asm zawsze mnie korcił, ale nigdy nie starczyło samozaparcia do nauki. :cry:
  • Pomocny post
    Poziom 33  
    Mi chodziło o sytuację że dopiero po wciśnięciu dowolnego przycisku zostaje uruchomione opóźnienie. Ciągle w programie go nie ma, tylko przy odczycie klawiszy. Nie musi być duże, ale coś tam powinno być ze względu na drgania styków i nierówność wciśnięcia dwóch przycisków naraz. Trzeba zrobić parę prób co do jego długości. Ważne jest jak mówiłem sprawdzanie obydwu końcówek portu. Program wtedy uzna np. wciśnięty pierwszy przycisk tylko wtedy, jak ten pierwszy będzie wciśnięty, a drugi puszczony. Dzięki temu nie będzie problemu z wciskaniem dwóch przycisków, bo program uzna tylko trzecią opcję gdy obydwa są wciśnięte. Czyli muszą być trzy instrukcje if - dla pierwszego, drugiego i obydwu przycisków. Co do asemblera to nigdy za późno, choć C jest w porządku. Ale warto po prostu znać co nieco więcej.
  • Pomocny post
    Poziom 42  
    walek33 --> ktoś polecił ci usunąć linię:

    PINB |= _BV(1) | _BV(2);

    nie dlatego, że ona może w czymś przeszkadzać tylko dlatego, że ona po prostu nie ma sensu ;) ....... ustawiać bity to możesz ale w rejestrach typu PORTx lub DDRx a nie w rejestrze wejściowym PINx - on służy tylko i wyłącznie do odczytywania wartości. Natmomiast podciąganie do stanu wysokiego wejść wewnętrznym Pull'upem robi się ustawiając bity w rejestrze PORT

    Co do zasady działania twoich klawiszy to tak jak kolega szod - również polecam ci dogłębnie przemyśleć może nawet jeszcze raz zasady jej działania, które później chcesz oprogramować - bo myślę, że sam się mocno zapętliłeś z tymi opcjami gdzie piszesz, że dodajesz 4 lub 5 ;) .... ja nie mam pojęcia o co tu może chodzić a na podstawie przykładowego kodu tym bardziej nie da się tego wydedukować co autor miał na myśli.

    Z tym poziomem i dodawaniem kolejnych wartości w sytuacji gdy teoretycznie wcisnąłeś 2 przyski a potem piszesz że następne wciśnięcie któregokolwiek z nich dodaje coś tam - tzn co zakładasz, że np

    wciskam sobie 2 przyciski naraz - załóżmy że to sprawdzamy w programie a potem co? puszczam je i sprawdzam czy został wciśnięty jeszcze raz jeden lub jeszcze raz dwa - czy też kilka razy jeden albo drugi ?????

    to wygląda jak wprowadzanie w jakimś ustalonym czasie jakiegoś kodu z klawiatury - więc bez ew użycia tutaj jakichś przerwań i i tak odmierzaniu czasu wciskania takich kombinacji się nie obejdziesz - co oczywiście musi spowodować spory rozrost programu, niezłe pokomplikowanie (ale w końcu wszystko da się oprogramować) no i długie i żmudne testowanie.

    To troszkę tak - jakbyś chciał zamiast klawiatury w komputerze dać userowi tylko jeden albo dwa klawisze i wymyślił różne kody wciskania dla uzyskania odpowiedników poszczególnych znaków. Troszkę to przejaskrawiłem - ale myślę że mniej więcej taką drogą chcesz pójść i stąd komplikacje w twoim programie.

    Bo gdyby to miało obsłużyć ew 3 stany czyli jeden wciśnięty klawisz, drugi wciśnięty czy dwa naraz to ogólny sposób podany przez kolegę szod by spokojnie wystarczył - a tak? ;) .... hmmm powodzenia
  • Pomocny post
    Specjalista - Mikrokontrolery
    walek33 napisał:
    Przyciski mają działać na zasadzie menu. Zgodnie z kodem po naciśnięciu jedynki wywołuje pierwszą procedurę, po naciśnięciu dwójki wywołuje drugą procedurę, po wciśnięciu dwóch jednocześnie mija dwie pierwsze i przechodzi do trzeciej, w której po sprawdzeniu wciśniętych przycisków wywołuje właśnie procedurę czwartą lub piątą (taka matematyka, że pierwsze wciśnięcie dwóch klawiszy daje rezultat 3 i następne wciśnięcie któregokolwiek dodaje się do niego dając 4 lub 5). Te dwie ostatnie procedury to drugi poziom menu. Mam nadzieję, że jasno ściemniłem? :D
    A z tym opóźnieniem muszę przemyśleć, choć nie chciałbym za bardzo spowalniać działania programu. To, które już zastosowałem jest moim zdaniem wystarczające.

    Dodane:
    A tak na marginesie to asm zawsze mnie korcił, ale nigdy nie starczyło samozaparcia do nauki. :cry:


    Problem jest w tym że jest mało realne jednoczesne naciśnięcie 2 przycisków. Różnica czasu może być różna 5ms, 50ms, a może i więcej. Do tego dochodzą jeszcze drgania styków które trwają zazwyczaj kilka ms. Procedura pobierająca stan przycisków musi trwać więcej czasu jeśli chcesz sprawdzać jednoczesność naciskania przycisków. Kolejna sprawa to to że po wykonaniu pierwszego poziomu menu musisz czekać aż przyciski zostaną zwolnione, bo jeśli tego nie zrobisz to natychmiast wykonają ci się jakieś następne pozycje z menu. Najważniejsze w tym momencie jest wyeliminowanie drgania styków.
  • Poziom 28  
    No to teraz dopiero namieszam. Dzięki wszystkim za pomoc. To po pierwsze (i może najważniejsze). A teraz się będę tłumaczył.
    mirekk36 napisał:
    walek33 --> ktoś polecił ci usunąć linię:

    PINB |= _BV(1) | _BV(2);

    nie dlatego, że ona może w czymś przeszkadzać tylko dlatego, że ona po prostu nie ma sensu

    W pierwszej chwili miałem wyłącznie deklarację, którą podałem w drugim poście. Taki sposób podciągnięcia wejść wyczytałem w różnych zacnych materiałach dotyczących tego paskudztwa :D z którym walczę. Z początku program testowałem w sofcie VMLAB. Nawet mi się to podobało. Nie ma kabli, widać przebiegi, można ponaciskać przyciski, świecą diódki. Pełen relaks. I tu widziałem wejścia bardzo ładnie podciągnięte do H. Aż w pewnym momencie przerzuciłem się na AVR Studio. W nim zaczynałem ów program pisać, bo wyczytałem, że to najlepszy (?) soft do tego celu. W nim też jest możliwość debugowania. I tu zonk. Zmienna "aktyw" przestała reagować. Jej wartość na dzień dobry wynosiła 3 mimo, że nie był wciśnięty żaden z przycisków. Zaczęła dopiero po wprowadzeniu kodu, który jest powyżej. Po częściowym ukończeni pisaniny doszedłem do wniosku, że nie ma to jak testować w naturze i po niedługim namyśle zapakowałem swoje wypociny do ATmegi. Jakież było moje rozczarowanie, gdy tak dopracowywany z czasami, opóźnieniami kod przestał działać. Na szczęście budowane przeze mnie ustrojstwo dawało jakieś oznaki życia, więc trochę odetchnąłem, że to nie wina schematu (nota bene też mojego osobistego pomysłu) i trzeba pokombinować na klawiaturze. To byłoby tyle celem wyjaśnienia skąd wziął się wyżej wspomniany kod.
    Teraz o tych poziomach. Ma to działać na zasadzie menu. Po wciśnięciu dwóch przycisków na raz ma mi wskoczyć możliwość ustawiania czasów. Wtedy wciskając jeden z nich ustawiam czas bieżący, a wciskając drugi ustawiam czas w którym ustrojstwo się włącza. Ot coś w rodzaju np. budzika. Mam nadzieję, że teraz wytłumaczyłem trochę jaśniej.
    mirekk36 napisał:
    To troszkę tak - jakbyś chciał zamiast klawiatury w komputerze dać userowi tylko jeden albo dwa klawisze

    Tu przyznaję Ci rację. Przejaskrawiłeś i to mocno. to co próbuję stworzyć bardziej można porównać do zegarka niż do kompa.
    szod napisał:
    Czyli muszą być trzy instrukcje if - dla pierwszego, drugiego i obydwu przycisków.

    Nie do końca się z Kolegą mogę zgodzić. Po pobieżnej analizie kodu, który podałem na początku obstaję przy swoim, że wystarczą tylko dwa if-y. Idąc po kolei:
    1. Wciśnięty pierwszy klawisz. Zmienna przyjmuje wartość 1 z pierwszego if-a drugi jej nie zmienia.
    2. Wciśnięty drugi klawisz. Pierwszy if jest pomijany i zmienna przyjmuje wartość 2 z drugiego if-a.
    3. Wciśnięte są dwa klawisze. Zmienna w pierwszym if-e przyjmuje wartość 1 i w drugim if-ie dodawana jest do niej 2. efekt końcowy Zmienna = 3.
    Jeśli się mylę proszę mnie poprawić. Podobno należy oszczędzać miejsce w rozumku ATmegi bo się cały kod może nie zmieścić, a zapowiada się go sporo. Nie chciałbym w połowie zabawy przesiadać się na większą. Musi wystarczyć ósemka.
    Alem się nagadał. Mimo wszystko proszę jeszcze o jakieś sugestie. to, że teraz tak marudzę nie oznacza wcale, że w trakcie testów nie wykorzystam Waszych uwag. Podobno nie tylko książki ale i dyskusje kształcą. W szczególności, jeżeli adwersarz jest dobrym fachowcem.
  • Pomocny post
    Poziom 42  
    walek33 --> co do testowania na żywym organiźmie czyli procku to oczywiście racja - święta racja. Zwykle tak bywa, że tworząc na sucho programy i to rozbudowane w symulatorach różnej maści, rzadko kiedy działają w rzeczywistości. ;)

    A tak? masz procka - masz złącze do programowania ISP bezpośrednio w układzie - więc debugowanie można sobie robić wręcz na żywo. Procek zniesie na prawdę wiele cykli programowania ;)

    a wracając do rzeczy - no to teraz po tym opisie dopiero zrozumiałem o co koledze chodzi z tymi dwoma klawiszami. Takie super minimalistyczne podejście do obsługi Menu - i oczywiście jakoś może to wyjść - chociaż sposób obsługi dla kogokolwiek innego poza autorem będzie mało intuicyjny. Ale jeśli się robi urządzonko dla siebie to co tam.

    no i w takim przypadku oczywiście, że moje przejaskrawienie nie dotyczyło tematu ale to dlatego, że wcześniej nie wynikały z opisów takie założenia.

    w związku z powyższym - przyznaję, że jak najbardziej można to zrobić za pomocą takich trzech niezależnych If'ów tak jak piszesz - jest to jak najbardziej jedna z podstawowych metod..... z tym, że jak sam widzisz próba rozbudowaywania tej procedury jak wcześniej pokazałeś - jeszcze o jakiś poziom i mnóstwo switch'y wewnątrz wydaje się mało stosowna.

    ta podstawowa funkcja, z minimalnym opóźnieniem dla eleiminacji drgań styków oraz te 3 If'y powinna być niezależną funkcyjką zwracającą właśnie ten argument o stanie wciśniętych klawiszy - natomiast na odpowiednich poziomach Menu - powinno się po jej wywołaniu sprawdzać argument i podejmować decyzję o wykonywanych działaniach czy przejściach do poszczególnych poziomów. Ale to oczywiście tylko jakaś jedna z setek tysięcy wizji i sposobów na jakie można to oczywiście zrobić ;)
  • Pomocny post
    Poziom 33  
    walek33 napisał:
    Nie do końca się z Kolegą mogę zgodzić. Po pobieżnej analizie kodu, który podałem na początku obstaję przy swoim, że wystarczą tylko dwa if-y. Idąc po kolei:
    1. Wciśnięty pierwszy klawisz. Zmienna przyjmuje wartość 1 z pierwszego if-a drugi jej nie zmienia.
    2. Wciśnięty drugi klawisz. Pierwszy if jest pomijany i zmienna przyjmuje wartość 2 z drugiego if-a.
    3. Wciśnięte są dwa klawisze. Zmienna w pierwszym if-e przyjmuje wartość 1 i w drugim if-ie dodawana jest do niej 2. efekt końcowy Zmienna = 3.

    Oczywiście jak chcesz to możesz i tak robić. Problem może zacząć się wtedy, jak będziesz chciał oprócz dodawania umieścić w instrukcjach if jeszcze jakieś fragmenty kodu, bo nie będzie oddzielnej instrukcji uruchamiającej się po wciśnięciu dwóch klawiszy. Można to rozwiązać i w inny sposób, ale i tak bez rozbudowy programu się nie da.
  • Poziom 28  
    Poczytałem uwagi kolegów, pokombinowałem z opóźnieniami i ... Znalazłem, może nie złoty i elegancki środek, ale działa. :D
    Code:
    void nastawy (unsigned char poziom)      //menu ustawienia
    
    {
       register unsigned char help = 0;
       poziom = klawisz();
       switch (poziom)
       {
       case 1:                        // ustaw program
       break;
       case 2:                        // karmienie ręczne
       break;
       case 3:                        //czasy
         for (help = 0; help < 200; help ++)
          {
         wyswietl(140, 150);
          }
          poziom += klawisz();
          switch (poziom)
          {
          case 4:                     //zegar
          break;
          case 5:                     //czas karmienia
          break;   
          }   
       break;
       }
    }

    Wyżej pokazane rozwiązanie polega na sprawdzeniu po raz drugi stanu klawiszy po wejściu do "nastawy" (tego wcześniej nie robiłem, myślałem, że wystarczy raz i podać jako argument - błąd) i zajęciu procka wyświetleniem do jakiego menu się włazi (to co jest w case 3 umieściłem w każdym. Sprawa się wyprostowała na tyle, że menu daje obsłużyć się bezstresowo. Tak, że w sprawie menu dziękuję za pomoc, ale cdn...