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.

Impulsator, Atmega328p na jednym przerwaniu INT0

dasej 26 Gru 2014 16:32 5334 13
  • Witam,

    Przedstawiam a tym artykule jak można na jednym przerwaniu obsłużyć pokazany poniżej impulsator.
    Może komuś się przyda.


    Impulsator, Atmega328p na jednym przerwaniu INT0



    Impulsator, Atmega328p na jednym przerwaniu INT0



    Wyjście B enkodera może by na innym dowolnym pinie, wymaga jedynie zmian w algorytmie.

    /* wyjście impulsatora A do INT0 PORTD pin PD2
    wyjście impulsatora B do PORTD pin PD1
    Kompilowane i testowane na Atmega328P.
    Avr Studio 4.18
    Programator AVR Prog MKII */

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Algorytm specjalnie tak napisałem bym mógł łatwo i obrazowo wytłumaczyć jak
    to działa. W necie można znaleść sporo przykładów na obsługę impulsatora,
    wszystkie przykłady które znalazłem korzystają z dwóch przerwań
    INT0 i INT1. Postanowiłem zaoszczędzić jedno przerwanie i tak powstał ten algorytm.


    Impulsator, Atmega328p na jednym przerwaniu INT0


    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Po wejściu w przerwanie sprawdzamy piny PD2=1 ( wejście INT0 ) i PD1=0 oraz
    czy przerwanie EICRA=1 jest ustawione na 1 (reaguj na zbocze narastające)
    jeżeli tak to, zmień reakcję przerwania na zbocze opadające oraz zwiększamy
    zmienną licznik o jeden.




    Impulsator, Atmega328p na jednym przerwaniu INT0

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Po wejściu w przerwanie sprawdzamy piny PD2=0 ( wejście INT0 ) i PD1=1 oraz
    czy przerwanie EICRA=0 jest ustawione na 0 ( reaguj na zbocze opadające )
    jeżeli tak to, zmień reakcję przerwania na zbocze narastające oraz zwiększamy
    zmienną licznik o jeden.



    Impulsator, Atmega328p na jednym przerwaniu INT0

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Po wejściu w przerwanie sprawdzamy piny PD2=1 ( wejście INT0 ) i PD1=1 oraz
    czy przerwanie EICRA=1 jest ustawione na 1 ( reaguj na zbocze narastające )
    jeżeli tak to, zmień reakcję przerwania na zbocze opadające oraz zmniejszamy
    zmienną licznik o jeden.







    Impulsator, Atmega328p na jednym przerwaniu INT0

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Po wejściu w przerwanie sprawdzamy piny PD2=0 ( wejście INT0 ) i PD1=0 oraz
    czy przerwanie EICRA=0 jest ustawione na 0 ( reaguj na zbocze opadające )
    jeżeli tak to, zmień reakcję przerwania na zbocze narastające oraz zmniejszamy
    zmienną licznik o jeden.

    Proszę zwrócić uwagę na stałą zmianę sposobu reagowania przerwania INT0,
    z reakcji na zbocze narastające i opadające.


    Końcowa wersja czterech najważniejszych lini.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Przy tej formie zapisu program jest mniejszy o 156 bajtów.
    Tak wykazuje w moim przypadku AvrStudio.


    Powyższy algorytm działa popranie i nie gubi impulsów oraz poprawnie je zlicza. Ewentualnie błędy mogły powstać jedynie w trakcie pisania artykułu, które nie są zamierzone.

    Fajne! Ranking DIY
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
    O autorze
    dasej
    Poziom 31  
    Offline 
    dasej napisał 1730 postów o ocenie 172, pomógł 150 razy. Mieszka w mieście Słupsk. Jest z nami od 2008 roku.
  • #2
    daroslav15
    Poziom 15  
    Wydaje mi się że logicznym jest użycie tylko jednego przerwania, bo wykorzystanie dwóch jest po prostu bez sensu.
    Pytanie ze strony bardziej sprzętowej: co z drganiami styków? Tanie impulsatory są wyjątkowo upierdliwe pod tym względem.
  • #3
    kr0nos
    Poziom 9  
    Czy zmienna uint16_t licznik nie powinna być typu volatile jeżeli operujemy nią w przerwaniu?
  • #4
    dondu
    Moderator Mikrokontrolery Projektowanie
    1. W funkcji main brakuje pętli głównej, a to oznacza, że doda ją kompilator w dodatku wyłączając przerwania - efektem będzie ... brak reakcji mikrokontrolera na jakiekolwiek sygnały z enkodera.

    2.
    dasej napisał:
    W necie można znaleść sporo przykładów na obsługę impulsatora,
    wszystkie przykłady które znalazłem korzystają z dwóch przerwań
    INT0 i INT1. Postanowiłem zaoszczędzić jedno przerwanie i tak powstał ten algorytm.

    Oj, to słabo szukałeś :)
    Poza tym, czasami istotne może być, by opóźnienie było możliwie najmniejsze - wtedy dwa przerwania mogą być niezbędne.

    3. Jeżeli już stosujesz język C to stosuj zdefiniowane nazwy pinów np.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    bo pewną niekonsekwencję stosujesz w swoim kodzie patrz bit ISC00.

    Poza tym przyrównywanie do konkretnych wartości jest zbędne i wydłuża kod wynikowy, o czym piszesz w dalszej części, choć nie wskazałeś dlaczego.

    Dodatkowo pojedynczy znak & w tym przypadku nie może być zastosowany, bo oznacza operację bitową, a nie logiczną. Wprawdzie uwzględniłeś to w ostatecznym kodzie, ale nie pokazuj tego typu operacji jako kod początkowy, bo początkujący zasugerują się i kłopoty gotowe :)


    4. W jakim celu stosujesz zewnętrzne rezystory pull-up? Wystarczy włączyć programowo wewnętrzne.

    5. licznik (jeżeli wykorzystujesz poza przerwaniami, a sądzę że tak jest) powinien być volatile.

    6. No i pytanie o drgania styków zadane przez kolegę daroslav15 wyżej jest najistotniejsze. Nic w tym względzie nie pokazałeś i nie napisałeś a chodzi o to (patrz 56-ta sekunda):


    Link
  • #5
    mkpl
    Poziom 37  
    Tak się zastanawiam... Dlaczego nikt nie stosuje przerwania zbiorczego do obsługi klawiatury i impulstatora?

    Podpinamy po Bożemu klawiaturę + impulsator na jeden port następnie z każdej nogi diodą sygnałową na przerwanie INT.

    Po wykryciu przerwania wartość portu jest zatrzaskiwana. Odpada problem drgania styków ponieważ czas okresu drgania styków jest wielokrotnie większy niż szybkość zatrzaskiwania danych na porcie.
  • #6
    dondu
    Moderator Mikrokontrolery Projektowanie
    mkpl napisał:
    Tak się zastanawiam... Dlaczego nikt nie stosuje przerwania zbiorczego do obsługi klawiatury i impulstatora?

    A na jakiej podstawie tak uważasz? :)
    Wszystko zależy od danego projektu i jego ograniczeń.

    mkpl napisał:
    Podpinamy po Bożemu klawiaturę + impulsator na jeden port następnie z każdej nogi diodą sygnałową na przerwanie INT.

    No i dodatkowe elementy się pojawiają ... coś za coś.

    mkpl napisał:
    Po wykryciu przerwania wartość portu jest zatrzaskiwana. Odpada problem drgania styków ponieważ czas okresu drgania styków jest wielokrotnie większy niż szybkość zatrzaskiwania danych na porcie.

    Skoro tak jest, to tym bardziej przerwanie wykona się wielokrotnie.
    Należy więc wyłączyć przerwanie na pewien czas (opóźnienie), czyli ... de facto wprowadzić eliminację drgań styków. :)
    Opóźnienie to może być jawne lub nie, ale zawsze musi być uwzględnione.
  • #7
    dasej
    Poziom 31  
    @dondu

    Świetnie, dziękuje za uwagi. Zacznie się dyskusja. Znam temat drgania styków. Proszę to wytłumaczyć. Jeden pełny obrót w te i z powrotem, a licznik wraca do pozycji wyjściowej mimo niedoskonałości algorytmu i błędów w myśleniu.


    Link


    Chętnie poczytam wyjaśnienia dlaczego działa poprawnie mimo drgań styków.

    a to fragment kodu, co nie istotne usunełem.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • #8
    dondu
    Moderator Mikrokontrolery Projektowanie
    dasej napisał:
    Chętnie poczytam wyjaśnienia dlaczego działa poprawnie mimo drgań styków.

    Bez analizy całego programu nie można jednoznacznie odpowiedzieć na Twoje pytanie.
    Na filmie, który pokazałem wyżej wykorzystany jest timer do zliczania impulsów w tym drgań. To bardzo dobry sposób, by pokazać to zjawisko, którego Ty w swoim algorytmie nie uwzględniasz.

    Opóźnienia niejawne być może są tutaj:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Istotne może także jest fakt, że niepoprawnie używasz definicji zmiennej licznik bez użycia volatile przez co łącznie masz wrażenie, że algorytm działa poprawnie.

    Zjawiska drgań styków nie da się przeskoczyć czarami ... opóźnienie oczekujące na ustabilizowanie się styków musi być, ale jego realizacja może być zrobiona na różne sposoby (jawne i niejawne, o czym wspomniałem w poprzednim poście).

    Wyjątek to impulsator optyczny, a nie stykowy - jesteś pewien, że Twój jest stykowym?

    Poza tym nie wiemy, czy czasem nie masz tam kondensatorów, które tworzą filtr RC ...

    Przeanalizuj więc swój projekt pod tym kątem i znajdź przyczynę wrażenia, iż algorytm jest poprawny. To Twój artykuł nie mój, więc udowodnij, że nie mamy racji :)

    https://hifiduino.wordpress.com/2010/10/20/rotaryencoder-hw-sw-no-debounce/
    http://www.eevblog.com/forum/projects/hardware-debouncing-a-rotary-encoder/
  • #9
    dasej
    Poziom 31  
    Nie jest jeszcze na tyle dobry by to wytłumaczyć
    ale podejrzewam że załatwia to sam procesor.

    Przy wejściu w przerwanie nie reaguje na kolejne zbocza narastające lub
    opadające musi zakończyć obsługę przerwania i dopiero jak z niego wychodzie
    podejmie reakcję na kolejne zbocze.

    Przypuszczalnie w tym czasie zanikają drgania styków.
    Procesor ma w tym czasie sporo warunków do sprawdzenia.
  • #10
    dondu
    Moderator Mikrokontrolery Projektowanie
    dasej napisał:
    Przy wejściu w przerwanie nie reaguje na kolejne zbocza narastające lub
    opadające musi zakończyć obsługę przerwania i dopiero jak z niego wychodzie
    podejmie reakcję na kolejne zbocze.

    Przypuszczalnie w tym czasie zanikają drgania styków.
    Procesor ma w tym czasie sporo warunków do sprawdzenia.

    No właśnie (dobrze kombinujesz :) ) - jeśli tak jest (dużo instrukcji w przerwaniu przy małej częstotliwości zegara taktującego) to jest to niejawne opóźnienie. Dlatego jak już wspomniałem, tylko analiza całego projektu pozwoli Ci na zrozumienie, dlaczego przez przypadek ten algorytm daje taki, a nie inny rezultat.

    Istotne jest natomiast, by nie zostawiać niczego przypadkowi. Jeżeli jesteś świadomy, że stosujesz niejawne opóźnienie, to jest jak najbardziej prawidłowe rozwiązanie problemu drgań styków. Ale jeśli nie jesteś tego świadomy, to prędzej czy później problem się ujawni.

    Naszą rolą natomiast jest pokazywać istotne problemy w takich artykułach jak Twój, by inny początkujący po przeczytaniu artykułu był świadomy dlaczego działa lub nie dany przypadek.

    Ale niech to Ciebie nie zniechęca do publikacji tego typu artykułów.
    Bardzo fajnie, że dzielisz się swoimi osiągnięciami :)

    Na koniec nieco teorii i praktyki:
    http://mikrokontrolery.blogspot.com/2011/04/przycisk-drgania-stykow-debouncing.html
    http://mikrokontrolery.blogspot.com/2011/02/o-drganiach-stykow-bez-bajek-przykad.html
    http://mikrokontrolery.blogspot.com/2011/03/epp-drgania-stykow.html
  • #11
    dasej
    Poziom 31  
    Całość działa na arduino ( klon chiński ) mini pro Atmega 328p zegar 16Mhz.
    Żadnych kondensatorów, ani filtrów RC. Są tylko długie kable. Taśmy.
  • #12
    dasej
    Poziom 31  
    Wykonałem pewien test na moim algorytmie.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Wynik jest taki jak przypuszczałeś @dondu, zmienna intliczba znacznie odbiega od wartości przechowywanej w licznik. W niektórych przypadkach zwiększa się nawet od 5 do 10 razy przy jednym skoku impulsatora. Z testu wynika że procesor reaguje na każde drgnięcie, uruchamiając kolejne przerwania, ale z powodu nieustabilizowania się stanów na wejściach nie spełnia żadnego warunku. Dopiero przy którymś z kolejnych przerwań na tyle się ustabilizują stany na wejściach że nastąpi spełnienie jednego z czterech warunków co wymusza zmianę zmiennej licznik.

    Myślę że dobrze wyjaśniłem kwestię drgań styków.
  • #13
    dondu
    Moderator Mikrokontrolery Projektowanie
    dasej napisał:
    Wynik jest taki jak przypuszczałeś @dondu, zmienna intliczba znacznie odbiega od wartości przechowywanej w licznik. W niektórych przypadkach zwiększa się nawet od 5 do 10 razy przy jednym skoku impulsatora. Z testu wynika że procesor reaguje na każde drgnięcie, uruchamiając kolejne przerwania, ale z powodu nieustabilizowania się stanów na wejściach nie spełnia żadnego warunku. Dopiero przy którymś z kolejnych przerwań na tyle się ustabilizują stany na wejściach że nastąpi spełnienie jednego z czterech warunków co wymusza zmianę zmiennej licznik.

    ... i to jest właśnie niejawne opóźnienie (o którym pisałem), a które w tym przypadku czasami zadziała, a czasami nie. My jednak nie możemy sobie pozwolić na przypadki, stąd obsługę drgań styków należy uwzględniać w programie.

    Dobrze, że jesteś dociekliwy :)
  • #14
    Janusz_kk
    Poziom 27  
    Może wtrącę swoje 3 grosze
    dasej napisał:
    Wynik jest taki jak przypuszczałeś @dondu, zmienna intliczba znacznie odbiega od wartości przechowywanej w licznik. W niektórych przypadkach zwiększa się nawet od 5 do 10 razy przy jednym skoku impulsatora. Z testu wynika że procesor reaguje na każde drgnięcie, uruchamiając kolejne przerwania, ale z powodu nieustabilizowania się stanów na wejściach nie spełnia żadnego warunku. Dopiero przy którymś z kolejnych przerwań na tyle się ustabilizują stany na wejściach że nastąpi spełnienie jednego z czterech warunków co wymusza zmianę zmiennej licznik.


    W tym prostym przykładzie nie ma to specjalnie znaczenia że procesor zasuwa zbędnie w przerwaniu, ale jak będziesz miał dłuższy program albo wyżyłowany czasowo to wtedy tego czasu ci braknie i nie będziesz wiedział dlaczego, dlatego ważne jest aby procek nie odbierał przypadkowych przerwań, z tego względu lepiej jest cyklicznie odpytywać enkoder czy klawiaturę poza przerwaniami, wywołując to timerem co np 10ms.