logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

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

zbysiusp 11 Cze 2011 20:20 8661 50
  • #1 9601019
    zbysiusp
    Poziom 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:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Proszę we wszystkich postach dodać znaczniki code.
    robak
  • #2 9601364
    janbernat
    Poziom 38  
    Należy doczytać do str.395 i dalej- wstep do systemów czasu rzeczywistego.
    I zastosować funkcję superdebouncing.
  • #3 9601880
    zbysiusp
    Poziom 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.
  • Pomocny post
    #4 9601939
    Fredy
    Poziom 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 9602305
    zbysiusp
    Poziom 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:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    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 9602315
    Fredy
    Poziom 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.
    .
  • #7 9602381
    zbysiusp
    Poziom 13  
    Dzięki, ale jeszcze zapytam.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    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 9602383
    janbernat
    Poziom 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 9602422
    Fredy
    Poziom 27  
    zbysiusp napisał:
    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 9602426
    zbysiusp
    Poziom 13  
    Bardzo dziękuję JANBERNAT. Drgania styków uwzględniłem w definicji funkcji w poście pierwszym:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Problem z tym, że nie potrafię z tej funkcji korzystać.
    Próbowałem wstawiać polecenie w pętli głównej programu np:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    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 9602492
    Fredy
    Poziom 27  
    Przecież w przerwaniu dajesz serię ifów i tam kontrolujesz co zostało naciśnięte.
  • #12 9602537
    zbysiusp
    Poziom 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 9602567
    Fredy
    Poziom 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 9602573
    janbernat
    Poziom 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 9602596
    zbysiusp
    Poziom 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 9603041
    dondu
    Moderator na urlopie...
    zbysiusp napisał:
    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 9603114
    zbysiusp
    Poziom 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:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #20 9603184
    zbysiusp
    Poziom 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:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #22 9603299
    zbysiusp
    Poziom 13  
    Napisz proszę czy należy także deklarować PIND2 (INT0) i nadać mu wartość wejściową?

    POPRAWIONY KOD:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #23 9603330
    janbernat
    Poziom 38  
    Program nie pasuje do obrazka- gdzie czwarty klawisz?
  • #24 9603364
    zbysiusp
    Poziom 13  
    Już jest!
    [Atmega8][Język C] Jak poprzez naciśnięcie przycisku przypisać wartość zmiennej
  • #25 9603406
    dondu
    Moderator na urlopie...
    1. INT0
    zbysiusp napisał:
    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

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

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


    3. Podobnie tutaj
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    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 9603518
    zbysiusp
    Poziom 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.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #28 9603535
    Fredy
    Poziom 27  
    To masz źle:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    tu sprawdzasz czy jest jedynka a masz sprawdzać czy jest zero.
    Zaneguj te warunki.
  • #29 9603556
    zbysiusp
    Poziom 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.
REKLAMA