Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega8][Język C] Jak poprzez naciśnięcie przycisku przypisać wartość zmiennej

zbysiusp 11 Jun 2011 20:20 8112 50
IGE-XAO
  • #1
    zbysiusp
    Level 13  
    Szanowni Forumowicze,
    Bardzo proszę o pomoc! Napisałem program do obsługi diody RGB na podstawie książki "Mikrokontrolery AVR Język C Podstawy programowania" (Mirosław Kardaś), ale utknąłem na problemie zmiany koloru diody za pomocą przycisku. Chciałbym aby po naciśnięciu przycisku S1-S4 wartość zmiennej x, która jest wykorzystywana w instrukcji "switch(x)" przyjmowała odpowiednio wartość 1-4. Jak wpisze ręcznie do programu wartość x=1-4 to wszystko działa. Chciałbym aby program przez cały czas sprawdzał stan klawiszy i po naciśnięciu któregokolwiek z nich w dowolnym momencie przeszedł od razu do wykonania instrukcji określonej w switch(x).

    Oto kluczowe fragmenty kodu:
    Code: c
    Log in, to see the code

    Proszę we wszystkich postach dodać znaczniki code.
    robak
  • IGE-XAO
  • #2
    janbernat
    Level 38  
    Należy doczytać do str.395 i dalej- wstep do systemów czasu rzeczywistego.
    I zastosować funkcję superdebouncing.
  • #3
    zbysiusp
    Level 13  
    Bardzo dziękuję za odpowiedź i pouczenie. Wygląda na to, że jest to funkcja specjalizowana "sporządzona" przez autora w/w książki. Ciekaw jestem czy istnieją inne rozwiązania gdyż zadanie logicznie wydaje się proste, a stopień komplikacji funkcji SuperDebounce jest znaczny (dla mnie). Tak prosto mogłoby być: wciskam klawisz S1 -> zmienna x: x=1 -> switch(1) itd. Pytanie tylko w którym miejscu umieścić zmienną x i jak oczekiwać na naciśnięcie klawisza. Proszę o jeszcze inne sugestie.
  • Helpful post
    #4
    Fredy
    Level 27  
    Najłatwiej to zrób tak:

    Wszystkie przyciski podłacz do pinów procka, daj podciągnięcie za pomocą rezystorów wewnętrznych ,oprócz tego za pomocą diod zsumuj te sygnały ,a nastęnie zsumowane sygnały daj na wejście przerwania np INT0. Musisz to zrobić tak że przyciśnięcie któregokolwiek przycisku spowoduje zmiane (spadek napięcia ) na wejściu przerwania INT0.
    I dalej robisz w programie procedurę obsługi przerwania INT0 w którym tylko czytasz który przycisk został naciśnięty.
  • #5
    zbysiusp
    Level 13  
    Bardzo dziękuję Fredy. Zapaliłem się do Twojego pomysłu, ale mam braki w wiedzy (dopiero zaczynam mękę/przyjemność z avr i C). Bardzo proszę o zebranie moich ustaleń w działający kod c. Oto one:
    Code: c
    Log in, to see the code

    A także pomysły na wywołanie i obsługę tego przerwania:
    wciśnięcie klawisza 1 skutkuje efektem x=1 i wchodzi do switch(x) jako switch(1)
    Nie wiem także w którym miejscu programu takie sprawdzanie przerwania wstawić. Jak po zsumowaniu sygnałów za pomocą diod (jeszcze nic o tym nie wiem) INT0 zorientuje się, który klawisz został naciśnięty?
    Pozdrawiam, dziękuję i proszę o dalszą pomoc.
  • #6
    Fredy
    Level 27  
    Tylko musisz jeszcze włączyć globalnie przerwania, czyli daj "sei". No i jedna ważna sprawa x musisz zrobić jako Volatile.
    Zrób Main jako petle niekończącą się w której tylko np drukujesz zawartość zmiennej.
    W prcedurze przerwania daj albo switcha albo serię ifów - coś w tym stylu:
    if (PINB & KEY1) x=1;
    itd

    Zasada jest banalna, program kręci się w kółko robiąc cokolwiek, następnie po naciśnięciu jakiegoś switcha zgłoszone jest przerwanie, więc natychmiast wchodzi ci do procedury obsługi przerwania i tam musisz zrobić analizę co zostało naciśnięte i odpowiednio ustalić wartość zmiennej X.
    .
  • IGE-XAO
  • #7
    zbysiusp
    Level 13  
    Dzięki, ale jeszcze zapytam.
    Code: c
    Log in, to see the code

    Czy jest to poprawne. Gdzie wstawić sprawdzanie wywołania przerwania i jak ono wygląda. Popraw proszę mój kod tak aby działał.
  • #8
    janbernat
    Level 38  
    Pewnie że superdebounce jest mocno rozbudowana.
    Ale jej zaletą jest to że dobrze działa.
    Zwróć uwagę że wogóle nie bierzesz pod uwagę w tym rozwiązaniu drgań styków.
    Po naciśnieciu przycisku nastąpi seria przerwań- kilka- kilkadziesiąt.
    Można to rozwiązać sprzętowo- filtr RC i bramka schmitt-a.
    Ale to jest rozbudowa układu.
    Albo programowo- tak jak zrobił to Mirek.
    Oczywiście przykładów jak rozwiązać to programowo jest mnóstwo.
    Zaproponowałem funkcję z książki bo ją masz i to dobrze opisaną.
    Na początek można ją potraktować jako "czarną skrzynkę"- parametry wejściowe i wyjściowe są ważne a całą funkcję wstawiasz metodą "kopiuj/wklej"
    A potem na spokojnie wczytujesz się w to jak to działa.
    Sporo gotowych funkcji i makr dostarczonych wraz z GCC tak się używa.
  • #9
    Fredy
    Level 27  
    zbysiusp wrote:
    Gdzie wstawić sprawdzanie wywołania przerwania i jak ono wygląda.


    Nie ma czegoś takiego. Przerwanie się samo wykona - oczywiście jeśli je odblokujesz no i odblokujesz wszystkie przerwania globalnie.
    Wtedy już nie musisz sobie tym problemem głowy zawracać - program sam wejdzie w przerwanie i poprawi ci wartość zmiennej x a następnie grzecznie wróci do głównego programu.
    Tylko sprawdż czy układ masz prawidłowy. Powinno być tak że wciśnięcie któregokolwiek przycisku ma zmienić stan na zero na wejściu INT0 oraz na jednym wejściu procka.
    Sprawę drgań styku można zrobić także w procedurze obsługi przerwania , wystarczy tylko zrobić coś w tym stylu:

    if(PINB & KEY1)
    { delay_ms 20;
    if(PINB & KEY1) X=1;
    }
  • #10
    zbysiusp
    Level 13  
    Bardzo dziękuję JANBERNAT. Drgania styków uwzględniłem w definicji funkcji w poście pierwszym:
    Code: c
    Log in, to see the code

    Problem z tym, że nie potrafię z tej funkcji korzystać.
    Próbowałem wstawiać polecenie w pętli głównej programu np:
    Code: c
    Log in, to see the code

    ale to nie działa... bo program nie oczekuje na wciśnięcie klawisza.

    Dodano po 4 [minuty]:

    Dziękuję Fredy. Czyli mój kod i definicja ISR są poprawne? Skąd wiadomo, który klawisz został naciśnięty?[/syntax]
  • #11
    Fredy
    Level 27  
    Przecież w przerwaniu dajesz serię ifów i tam kontrolujesz co zostało naciśnięte.
  • #12
    zbysiusp
    Level 13  
    Proszę Fredy napisz jeszcze jak dokładnie mechanicznie podpiąć przyciski.
    Dobrze myślę? KEY1 i KEY2 z jednej strony do PB1 i PB2 (PB1 i PB2 podciągnięte do VCC - stan wysoki). KEY1 i KEY2 z drugiej strony do INT0 (zwykle zwiera się je do masy). Wciśnięcie klawisza wymusi stan wysoki na INT0! Gdzie miejsce na diody i sumowanie?
  • #13
    Fredy
    Level 27  
    KEY1 i KEY2 podpinasz pod PB1 i PB2. Potem dajesz diody od PB1 do INT0, oraz od PB2 do INT0. Kierunek diód ma być taki że katody do PB1 i PB2.
    Efekt ma być taki że po naciśnięciu np KEY1 ma spać napięcie na PB1 i na INT0, ale na PB2 ma być wysoki stan.
  • #14
    janbernat
    Level 38  
    Nie należy wprowadzać _delay() do przerwania!
    To jest jak z papierosami- łatwo zacząć a potem bardzo trudno się odzwyczaić.
    Proponuję przerobić program na taki bez przerwań na początek.
    Wprowadź polling- czyli po polsku- odpytywanie stanu klawiatury.
    To się robi tak- pętla główna kręci się w kółko i trwa to jakieś mikrosekundy.
    W tej pętli sprawdzasz czy jakikolwiek klawisz został naciśnięty.
    Jeśli nie- to pętla kręci się dalej i nic innego nie robi.
    Jeśli tak- to odczekujemy 20ms i wchodzimy w sprawdzanie który klawisz został naciśnięty
    za pomocą if albo switch- i wykonujemy to co ma być zrobione po naciśnięciu lkawisza.
  • #15
    zbysiusp
    Level 13  
    A z drugiej strony zwieramy przyciski oczywiście do masy. jak zrozumiałem diody zabezbieczają przed "przeniesieniem" się stanu niskiego z INT0 (otrzymanego np. z PB1-KEY1) na pozostałe piny PB2, PB3 itd. Stan 0 ma tylko PB1, z którego INT otrzymał 0. Czy dobrze?

    Dodano po 4 [minuty]:

    Dziękuję JANBERNAT, czy mógłbyś napisać mi "szkielet" takiej realizacji?

    Dodano po 47 [minuty]:

    Czy takie podłączenie klawiszy a'la Fredy jest poprawne?

    [Atmega8][Język C] Jak poprzez naciśnięcie przycisku przypisać wartość zmiennej
  • #16
    dondu
    Moderator on vacation ...
    zbysiusp wrote:
    Czy takie podłączenie klawiszy a'la Fredy jest poprawne?

    Tak.
    Można można to zrobić także korzystając z Timera, który w przerwaniu będzie skanował przyciski np. 20 razy na sekundę. Wtedy diody są niepotrzebne a wejście INT będzie wolne.
  • #18
    zbysiusp
    Level 13  
    Dziękuję MIREKK36. Oczywiście, że rezystory są: R-100R, B-180R, G-180R. Taki skrót myślowy dla znawców tematu.
    Panowie proszę podajcie przykładowy kod realizacji problemu z klawiszami. Wszyscy doradzają (dzięki!), a ja siedzę nad płytką testową i patrzę w diodę RGB mieniącą się prawie wszystkimi kolorami tęczy. Naciskam nieszczęsne przyciski podłączone wg Fredy'ego, podaję 0 na pin przełącznika i wejście INT0 i nic, zupełnie nic!
    Proszę o pomoc, a najlepiej kod "edukacyjny" lu poprawienie mojego.

    MÓJ NIEDZIAŁAJĄCY KOD:
    Code: c
    Log in, to see the code
  • #20
    zbysiusp
    Level 13  
    Podpowiedz proszę jak to zrobić technicznie. Wybieram w edytorze: listing kodu "SYNTAX wybierz" i wkleja się jak wklejało. Naprawdę się staram.

    Dodano po 1 [minuty]:

    Sorki doczytałem! Zaraz wkleję kod ponownie!

    Dodano po 3 [minuty]:

    Dziękuję i poprawiam się.
    MÓJ NIEDZIAŁAJĄCY KOD:

    Code: c
    Log in, to see the code
  • #22
    zbysiusp
    Level 13  
    Napisz proszę czy należy także deklarować PIND2 (INT0) i nadać mu wartość wejściową?

    POPRAWIONY KOD:

    Code: c
    Log in, to see the code
  • #23
    janbernat
    Level 38  
    Program nie pasuje do obrazka- gdzie czwarty klawisz?
  • #25
    dondu
    Moderator on vacation ...
    1. INT0
    zbysiusp wrote:
    Napisz proszę czy należy także deklarować PIND2 (INT0) i nadać mu wartość wejściową?

    Tak, przy takim schemacie należy włączyć pull up na pinie INT0.


    2. Komentarz jest niewłaściwy do funkcji pinów PD7, PD6, PD2

    Code: c
    Log in, to see the code

    PD2 ma być wejściem z włączonym pull-up.
    PD6 i PD7 w ogóle nie używasz.


    3. Podobnie tutaj
    Code: c
    Log in, to see the code


    4. Na schemacie dodaj rezystory przy LED
    Bo Ci co w przyszłości będą szukać informacji nie czytając wątku podłączą i poniosą straty :)


    Na razie tu się zatrzymałem - wprowadź zmiany, sprawdź kod, wrzuć tutaj i opisz zachowanie.
  • #26
    zbysiusp
    Level 13  
    Poprawiłem kod - wstawiam fragment. Pewna reakcja na wciśniecie klawisza jest bo po ok 10 sekundach tęcza się przerywa i świeci się tylko kolor niebieski (x=3?). Nadal właściwie nie działa.

    Code: c
    Log in, to see the code
  • #28
    Fredy
    Level 27  
    To masz źle:

    Code: c
    Log in, to see the code


    tu sprawdzasz czy jest jedynka a masz sprawdzać czy jest zero.
    Zaneguj te warunki.
  • #29
    zbysiusp
    Level 13  
    Próbowałem, ale PD2 "nie wchodzi" - dziwne; już kiedyś się to zdarzało. Dopiero PIND2 kompilator uznał za właściwy. Zegar - wewnętrzny oscylator 8MHz.