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

[C] [C][ATmega8] - Problemy z przerwaniem zewnętrznym i sterowaniem serwami

Cargo1906 04 Wrz 2013 12:16 3420 17
REKLAMA
  • #1 12700823
    Cargo1906
    Poziom 9  
    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 / 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
  • REKLAMA
  • #2 12700981
    dejmos
    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.
  • #3 12701016
    pbuhne
    Poziom 15  
    Kod: Text
    Zaloguj się, aby zobaczyć kod



    Nie ma potrzeby zmieniania GICR w obsłudze przerwania.
  • REKLAMA
  • #4 12701176
    Cargo1906
    Poziom 9  
    Wprowadziłem zmiany jak radziliście, tj.

    W obsłudze przerwania zmieniam jedynie stan flagi:

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


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

    Kod: C / 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 :|
  • REKLAMA
  • #5 12701274
    dejmos
    Poziom 23  
    Trochę inaczej
    Kod: C / 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
  • #6 12702535
    pbuhne
    Poziom 15  
    Proponuje użyć przerwania od timera np co 10ms i sprawdzania w nim stanu pinu, np 10 razy:

    Kod: C / 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.
  • REKLAMA
  • #7 12702925
    shadow0013
    Poziom 34  
    Tu masz artykuł kolegi mirekk36 na temat drgania styków (3 części), warto przeczytać.
  • #9 12703779
    PDT
    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 / C++
    Zaloguj się, aby zobaczyć kod

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

    Pzdr
  • #10 12704232
    Cargo1906
    Poziom 9  
    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 / 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ć
  • #11 12704330
    Konto nie istnieje
    Konto nie istnieje  
  • #12 12704344
    PDT
    Poziom 24  
    Spróbuj poprawić swoją obsługę klawisza ON/OFF w przerwaniu. Np tak:

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

    To już powinno lepiej działać.

    Pzdr
  • #13 12704361
    Cargo1906
    Poziom 9  
    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
    #14 12704401
    BlueDraco
    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
    #15 12704450
    PDT
    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?
  • #16 12704537
    Cargo1906
    Poziom 9  
    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
    #17 12704753
    pbuhne
    Poziom 15  
    Kod: C / 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 / C++
    Zaloguj się, aby zobaczyć kod


    tu:

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


    lub tu:

    Kod: C / 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 ;)
  • #18 12705663
    Cargo1906
    Poziom 9  
    Racja, operatory logiczne miałem w niewłaściwych miejscach, prędzej tak to powinno wyglądać:

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


    Dzięki za zwrócenie uwagi :cunning:
REKLAMA