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

[C][ATmega8] - Switch i przerwanie zewnętrzne

04 Wrz 2013 12:16 3087 17
  • Poziom 7  
    Witam,
    jestem w trakcie pisania programu dla line follow'era i chciałbym za pomocą switcha włączać i wyłączać robota (konkretnie serwa), coś na zasadzie przycisku on/off.

    Do tego celu chcę użyć przerwań zewnętrznych w ATmedze8 i switcha, za pomocą którego będę zmieniał stan na pinie PD2 (INT0).

    Program niestety nie działa jak należy. Raz na kilka przypadków zdarzy się oczekiwany efekt. Często jednak serwa obracają się nie reagując na wciśnięcie switcha, innym razem stoją w bezruchu. Często też zatrzymują się, albo włączają w zupełnie dowolnym momencie. Totalny chaos :|

    Dlatego też bardzo proszę o pomoc i wytknięcie błędów w kodzie:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Gdy program odpalam bez switcha wszystko działa jak należy, tzn. koła obracają się zgodnie z założonymi warunkami. Problemy pojawiają się gdy chcę dodać przerwanie zewnętrzne.

    Proszę o pomoc, jeśli ktoś zauważy jakikolwiek błąd
  • Poziom 23  
    1. Po co opóźnienie na ustanie drgań styków jeżeli przerwanie już się wykonuje? Nic Ci to opóźnienie nie daje a tylko strasznie wydłuża wykonanie procedury przerwania.
    2. Jeżeli już masz to opóźnienie to po nim powinno być ponowne sprawdzenie pinu PD2 które określi czy na pewno nastąpiła zmiana stanu na pinie.
    Na Twoim miejscu w obsłudze przerwania ustawiałbym tylko jakąś flagę zaś w programie głównym zrobiłbym procedurę taką, że jeżeli flaga ta jest ustawiona sprawdzam po pewnym opóźnieniu czy na pewno nastąpiło przerwanie (zmienił się stan pinu PD2) jeżeli tak ... to coś się tam robi. Jeżeli nie to flaga się zeruje i ... procek dalej czeka na przerwanie.
  • Poziom 14  
    Kod: text
    Zaloguj się, aby zobaczyć kod



    Nie ma potrzeby zmieniania GICR w obsłudze przerwania.
  • Poziom 7  
    Wprowadziłem zmiany jak radziliście, tj.

    W obsłudze przerwania zmieniam jedynie stan flagi:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    zaś w głównej pętli sprawdzam flagę oraz stan pinu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Reszta kodu bez zmian.
    Po tych modyfikacjach program działa już lepiej, tj. serwa częściej wyłączają się w momentach w których powinny to robić, jednak czasami nie włączą się w odpowiedniej chwili :?
    Prócz tego dużo gorzej reagują na zmianę powierzchni pod czujnikami (czarna/biała linia). W programie bez switcha wszystko chodzi płynnie, natomiast tutaj serwa są bardziej toporne :|
  • Poziom 23  
    Trochę inaczej
    Kod: c
    Zaloguj się, aby zobaczyć kod
    [/code]
    Bo w twoim przypadku tylko wprowadziłeś opóźnienie 10 ms do if(jazda). to opóźnienie ma za zadanie wyeliminować drgania styków. Czyli int wykrywa że zmienił się stan. Powoduje to wskoczenie do if(jazda) w którym jest opóźnienie i dopiero wtedy ponownie sprawdzasz czy ta zmiana jest dalej. Jeżeli tak ... wykonujesz program... jeżeli nie ... wyskakujesz z całego if(jazda). Zasada programowej eliminacji drgań styków jest taka:
    1. Zmiana pinu którą wykrywa uC
    2. Robisz opóźnienie
    3. Jeżeli po opóźnieniu dalej jest ta zmiana
    4. Wykonujesz procedurę do niej przypisaną
    5. Jeżeli nie .. nic nie robisz.
    Powodzenia
  • Poziom 14  
    Proponuje użyć przerwania od timera np co 10ms i sprawdzania w nim stanu pinu, np 10 razy:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Takie coś wykonuje się w przerwaniu, trwa chwile i nie tracisz procesora na jakieś delay'e... Bo tak naprawdę Twój procesor ogromną większość czasu tkwi w delayach i nic nie robi. Zakładam tu że używasz tact-switcha, a nie takiego on-off.
  • Poziom 34  
    Tu masz artykuł kolegi mirekk36 na temat drgania styków (3 części), warto przeczytać.
  • Poziom 24  
    Ależ szanowni koledzy, programując procesory pozbywajmy się zakłóceń (drgań styków) metodami programowymi (stosując filtrację cyfrową). A więc:
    PDT napisał:
    Proponuję zastosować timer do generowania przerwań co około 2.5ms. W przerwaniu testujemy wejścia portów nie zawracając sobie głowy jakimiś 'drganiami styków'. Sprawdzone, pewne, proste. Czas 2.5ms dobrany jest tak aby zwykły enkoder 20-32imp./obrót obracany energicznie ręką nie zgubił impulsu (gdy czas pomiędzy przerwaniami za długi), oraz wszystkie odczyty mają być w tą samą stronę prawo/lewo (jeśli wskakują fałszywki to daliśmy za krótki czas, i łapiemy drgania styków).

    Aha, byłbym zapomniał: te układy RC mające usuwać efekt drgań styków - obowiązkowo usunąć. Dopiero ich obecność znakomicie wydłuża czas trwania stanów nieustalonych.


    Powyższe podejście ma mocne podstawy teoretyczne:
    Cytat:
    The Whittaker–Shannon interpolation formula is a method to reconstruct a continuous-time bandlimited signal from a set of equally spaced samples.
    This is equivalent to filtering the impulse train with an ideal (brick-wall) low-pass filter.


    Taka metoda filtracji drgań styków jest oczywista przy programowej obsłudze. Sprowadza się do próbkowania stanu styków z okresem znacznie (przynajmniej dwukrotnie) dłuższym niż czas ustalania się drgań.

    Na koniec szkielet algorytmu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Program jest pod '51 ale to dla ilustracji zagadnienia jest bez znaczenia.

    Pzdr
  • Poziom 7  
    dejmos, po wgraniu Twojego kodu program działa lepiej, drgania styków jednak dalej występują i raz na jakiś czas serwa nie zawsze zareagują tak jak powinny, szczególnie przy dłuższym przytrzymaniu switcha.

    pbuhne, o ile Cię dobrze zrozumiałem, kod po przerobieniu z przerwaniami od Timera wygląda następująco:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Drgania styków tutaj dalej występują i serwa włączają się i wyłączają w sposób losowy :|

    shadow0013, BlueDraco, dzięki za linki, poczytam o tych sposobach i spróbuję jakoś je wykorzystać
  • Użytkownik usunął konto  
  • Poziom 24  
    Spróbuj poprawić swoją obsługę klawisza ON/OFF w przerwaniu. Np tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    To już powinno lepiej działać.

    Pzdr
  • Poziom 7  
    W takim przypadku serwa wyłączają się w odpowiednim momencie, ale problem jest gdy maja zostać uruchomione. Często udaje się to dopiero przy trzeciej, czy czwartej próbie
  • Pomocny post
    Specjalista - Mikrokontrolery
    Jaką masz częstotliwość przerwań timera? Testowanie stanu przycisków powinno następować z częstotliwością rzędu 30..50 Hz jeśli pamiętasz tylko jeden stan wstecz. Jeśli masz większą częstotliwość, to albo testuj je w co którymś przerwaniu, albo wsuwaj stan do zmiennej i wykrywaj sekwencję stanów (bitów) np. 1110.
  • Pomocny post
    Poziom 24  
    Cargo1906 napisał:
    W takim przypadku serwa wyłączają się w odpowiednim momencie, ale problem jest gdy maja zostać uruchomione. Często udaje się to dopiero przy trzeciej, czy czwartej próbie


    Zatem kolega ma jeszcze jakieś błędy w pozostałej części programu. Zmiana stanu zmiennej jazda dokonuje się w jednym miejscu:
    jazda ^= 1;
    Brak przesłanek by zmiana 1->0 była dokonywana poprawnie, zaś 0->1 już nie.

    PS Może serwa nie zawsze uruchamiają się przy jazda==1? Nie da się w pętli głównej wyprowadzić zmiennej jazda na jakiś LED?
  • Poziom 7  
    Ha! Rzeczywiście częstotliwość generowania przerwań timera wynosiła 100Hz. Po jej obniżeniu program działa dużo lepiej, ale jeszcze nie wzorowo. Rzadko, ale raz na kilka przypadków serwa nie załączają się w odpowiedniej chwili, ruszają by po ułamku sekundy się zatrzymać, tak jakby na moment pojawił się odpowiedni stan i nagle się zmienił. Dzieje się to jednak bardzo rzadko i tylko przy próbie uruchamiania serw. Wyłączanie ich działa już bez zarzutu.

    PDT napisał:

    PS Może serwa nie zawsze uruchamiają się przy jazda==1? Nie da się w pętli głównej wyprowadzić zmiennej jazda na jakiś LED?


    Hmm, popróbuję coś wieczorem, bo w tej chwili brakuje mi już czasu.

    Dziękuję wszystkim za dotychczasową pomoc ;)
  • Pomocny post
    Poziom 14  
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Podaj mi JEDNĄ wartość adc4 dla której ten warunek NIE jest spełniony.
    Tak samo tu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    tu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    lub tu:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Już łapiesz? Te warunki zawsze będą spełnione:

    0: mniejsze od 190, warunek ok
    159: mniejsze od 190, warunek ok
    170: mniejsze od 190 i większe od 160, warunek ok
    191: większe od 160, warunek ok...

    Wiesz dlaczego? Bo masz tam OR czyli LUB : ||

    Myślę że, powinieneś jeszcze raz sobie przemyśleć te warunki if else.

    Pozdrawiam ;)
  • Poziom 7  
    Racja, operatory logiczne miałem w niewłaściwych miejscach, prędzej tak to powinno wyglądać:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dzięki za zwrócenie uwagi :cunning: