Elektroda.pl
Elektroda.pl
X

Wyszukiwarki naszych partnerów

Kategoria: Kamery IP / Alarmy / Automatyka Bram
Montersi
Kategoria: Akumulatorki / Baterie / Ładowarki

AVR + enkoder obrotowy. Program w C

elektroziom 28 Paź 2010 21:34
  • #1 28 Paź 2010 21:34
    elektroziom
    Poziom 20  

    Witam serdecznie :)

    Mam za zadanie obsłużyć enkoder obrotowy i już drugi dzień nie mogę sobie z nim poradzić :/

    enkoder taki jak w projekcie elektrodowicza mirley:

    http://www.elektroda.pl/rtvforum/viewtopic.ph...er+audio&sid=257b88886d9ea0d1f8c64228853b95a1

    Miałby ktoś może z was gotowy programik do takiego enkodera i mógł go mi udostępnić? :/

    założenia:

    -program napisany w C/C++
    - obrót w prawo inkrementuje zmienną, obrót w lewo dekrementuje tą samą zmienną..
    - enkoder podłączony do dwóch pinów portu (zwiera do masy).
    -procesor ATmega 32 + kwarc 16MHz

    bardzo prosze o waszą pomoc.. pozdrawiam :)

  • #2 28 Paź 2010 22:08
    hotdog
    Poziom 26  

    A w czym masz problem? Rozumiesz jak on działa?

    Pozdrawiam

  • #3 28 Paź 2010 22:32
    tmf
    Moderator Mikrokontrolery Projektowanie

    Code:

     unsigned char i=0;
        
        if((PINC & _BV(PC0))==0) i++;
        if((PINE & _BV(PE7))==0) i^=3; // convert gray to binary
        
        unsigned char enc_last=EncoderState & 3;
       i-=enc_last;
        enc_last+=i;
            EncoderState&=0xFC;
        EncoderState|=enc_last;
        
        if(i & 1)
        { // bit 0 = value (1)
        if(i & 2) NoOfPulses--; // bit 1 = direction (+/-)
        else NoOfPulses++;
        }


    Debouncing to już sobie sam dodaj :)

  • #4 30 Paź 2010 15:31
    elektroziom
    Poziom 20  

    Mógłby mi ktoś wytłumaczyć działanie kodu w poście elektrodowicza tmf ? ;/ pisałem do niego na priv ale niestety nie odpowiada :/ pierwsze 3 linijki to sprawa oczywista ale reszta niestety dla mnie nie ;/

    Sprawdziłem dokładnie działanie mojego enkodera:
    Generuje on przebieg w kodzie Graya, ale stany spoczynkowe to na zmianę 11 (3) i 00 (0), a w momencie przejścia generuje na zmianę 10 (2) i 01 (1).

    Obsłużyłem go za pomocą dwóch przerwań od INT0 (PIND.2) i INT1 (PIND.3):

    Code:

    volatile int licznik = 0;

    int main(void)
    {
        //inicjalizacje

    }

    SIGNAL (INT0_vect) //obsługa przerwania INT0
    {
       if((!(PIND & 1<<2)) != (!(PIND & 1<<3)))
       ++licznik;
       else
       --licznik;
    }

    SIGNAL (INT1_vect) //obsługa przerwania INT1
    {
       if((!(PIND & 1<<2)) != (!(PIND & 1<<3)))
       --licznik;
       else
       ++licznik;
    }


    INT0 reaguje na zbocze opadające a INT1 na zbocze narastające. Wszystko śmiga łądnie tylko niestety zajmuje aż dwa przerwania zewnętrzne :( chciałbym to samo zrobić na zwykłych pinach portu bo w sumie potrzebuje podłączyć 3 takie enkodery :(

    Może programowo sprawdzać czy nastąpiło zbocze opadające i narastajśce na odpowiednich pinach tak jak robiłem to przerwaniami i w obsłudze sprawdzać czy te dwa piny od encodera są różne od siebie żeby ominąc stany spoczynkowe 11 i 00 ? :/

    Próbowałem już zrobić programowo reakcje na zbocza ale bez skutecznie :(

    Na koniec zamieszczam schemat ideowy podłączenia enkodera do ATmega32:

    AVR + enkoder obrotowy. Program w C

  • #5 30 Paź 2010 15:55
    tmf
    Moderator Mikrokontrolery Projektowanie

    Generalnie nie odpowiadam na PW, chyba, że z jakiegoś powodu mnie zainteresują :)
    Co do enkodera - mylisz się, generuje on kod Graya, zmiana następuje przy każdym przejściu. Stany 00, 01,11,10 są stabilne, nie ma czegoś takiego jak stany przejściowe. Mój kod po prostu konwertuje kod Graya na kod binarny, z zachowaniem informacji o kierunku. Zmienna NoOfPulses jest inkrementowana/dekrementowana w zależności od kierunku obrotu.
    Co do twojej obsługi - można to zrobić bez przerwań (tak jak w moim kodzie), ale trzeba zastosować wtedy pooling, czyli najlepiej w przerwaniu sprawdzać stan enkodera. W dodatku trzeba to robić na tyle często, żeby wyłapywać każdy obrót, inaczej przy szybkim przekręcaniu enkodera robi się problem z odczytem kierunku. Tobie to nie zadziałało, bo żeby określić kierunek obrotu oprócz bieżącego staniu potrzebny jest poprzedni - właśnie po to, żeby wiedzieć jaka zmiana zaszła.

  • #6 31 Paź 2010 10:49
    elektroziom
    Poziom 20  

    Może opiszesz dokładniej poszczególne linie kodu? :)

    dodam komentarze do Twojego kodu co rozumie a czego nie rozumie :)

    Code:

    unsigned char enc_last=EncoderState & 3;


    tutaj maskujesz 2 najmłodsze bity prawda? zmienną EncoderState deklarowałeś jako zmienna globalna unsigned char? czy poprostu lokalną wewnątrz ciała jakiejś petli?

    Code:

     i-=enc_last;
        enc_last+=i;


    tutaj najpierw odejmujesz wartość zmiennej i od zmiennej enc_last a potem dodajesz dlaczego?

    Code:

      EncoderState&=0xFC;
        EncoderState|=enc_last;


    tutaj maskujesz 3ci najmłodszy bit i sumujesz zawartośc stanów poprzedniego i następnego? do czego to służy ? sory za takie pytania ale chciałbym "poczuć" ten kod a nie lubie jak coś robie a tego nie rozumie :P

  • #7 31 Paź 2010 13:00
    asembler
    Poziom 32  

    Są dwa typy taki enkoderów z tego co sie praktycznie dowiedziałem.
    Pierwszy nazywany przeze mnie normalnie zwartym a drugi normalnie rozwartym.
    Różnią się one wewnętrzną budową a dokładnie szerokością zastosowanych styków. O ile program nie zostanie napisany na oba typy uwzględniając ich budowę można napisać program który bedzie działał tylko z jednym z nich.

  • #8 31 Paź 2010 16:20
    manekinen
    Poziom 29  

    elektroziom - przede wszystkim poszukaj pdf-a do swojego enkodera i upewnij się jak działa - zaoszczędzi Ci to wiele problemów. To wspólne wyprowadzenie nie koniecznie musi być po środku, a wtedy całość będzie działała - lecz niepoprawnie a Ty będziesz szukał błędu w kodzie.

    Co do samej obsługi, ja to robię tak: Jedno wyprowadzenie na przerwaniu zewnętrznym a drugie na zwykłym pinie. Obydwa podciągnięte wewnętrznie - nie trzeba żadnych dodatkowych rezystorów. Dodatkowo do masy kondensatory 10nF - drgania styków mogą wszystko zepsuć. Obojętnie w którą stronę pokręcę, wyzwolone zostaje przerwanie a w jego obsłudze czekam jakieś 10us i sprawdzam co się dzieje na drugim pinie... jeśli jest stan niski to znaczy że pokręcono np. w lewo, jeśli wysoki to np. w prawo. Jego stan można sobie przepisać do flagi i już później w wolnej chwili zwiększać/zmniejszać licznik.

    asembler - a bawiłeś się enkoderem z myszy pc? Tam co krok masz raz zwarty a raz rozwarty, i za każdym razem trzeba przekonfigurować jakim zboczem będzie wyzwalane następne przerwanie. Dodam że taki enkoder wspólne wyprowadzenie ma właśnie po boku :)

  • #9 31 Paź 2010 18:04
    asembler
    Poziom 32  

    Prosty programik na enkoder to 22 bajty kodu lecz trzeba wiedzieć z jakim sprzętem mamy do czynienia. Sprawa się komplikuje gdy chcemy zastosowac dowolny enkoder pod ten sam program wtedy program ma ponad 400 bajtów ale dodatkow enkoder moze być 'nieprawny' czyli troszkę brudny.
    Taka uwaga do autora tematu: Przed przystąpieniem dopisania softu dobrze jest taki enkoder rozebrac i przciści bo podejrzewam ze to sprzet z trzeciej ręki.
    Nie bawiłem sie myszkami ale z tegoco piszesz to taki enkoder podpada pod normalnie rozwarty wg. mojego nazewnictwa.

  • #10 23 Gru 2010 21:22
    Bobekmaster
    Poziom 24  

    tmf napisał:
    Code:

     unsigned char i=0;
        
        if((PINC & _BV(PC0))==0) i++;
        if((PINE & _BV(PE7))==0) i^=3; // convert gray to binary
        
        unsigned char enc_last=EncoderState & 3;
       i-=enc_last;
        enc_last+=i;
            EncoderState&=0xFC;
        EncoderState|=enc_last;
        
        if(i & 1)
        { // bit 0 = value (1)
        if(i & 2) NoOfPulses--; // bit 1 = direction (+/-)
        else NoOfPulses++;
        }


    Debouncing to już sobie sam dodaj :)


    Mam pytanie czy deboucing jest potrzebny do obsługi enkodera? Z tego co rozumiem ma on niwelować zakłócenia związane z drżeniem styków.
    Skorzystałem z Twojego programu i działa dobrze bez debouncingu.

    Pozdrawiam

  • #11 23 Gru 2010 21:45
    tmf
    Moderator Mikrokontrolery Projektowanie

    Nie jest konieczny, ale to zależy od okoliczności. Musisz się liczyć z tym, że bez debouncingu przy kręceniu stan może przejściowo oscylować +/-1, aż się ustabilizuje na nowej wartości. W zależności od kodu to może być problem (jeśli każda zmiana generuje zdarzenie), lub nie.
    Przy okazji, trzeba też pamiętać, że są różne enkodery - niektóre pomiędzy stabilnymi pozycjami generuja 1 impuls, ale są takie, które generują 2 lub 4. W takich sytuacjach NoOfPulses należy podzielić przez 2 lub 4.

  • #12 23 Gru 2010 21:50
    Bobekmaster
    Poziom 24  

    Mój enkoder wysyła 4 impulsy i wynik dziele przez 4.
    Impulsy nie skaczą i zliczają się poprawnie.
    Funkcja jest wyzwalana przerwaniem zegarowym a nie zewnętrznym.

    Tak więc nie będę robił deboucingu.

    Pozdrawiam i dziękuję za odpowiedź.

  • #13 24 Gru 2010 15:20
    Fredy
    Poziom 27  

    tmf napisał:
    Nie jest konieczny, ale to zależy od okoliczności. Musisz się liczyć z tym, że bez debouncingu przy kręceniu stan może przejściowo oscylować +/-1, aż się ustabilizuje na nowej wartości. W zależności od kodu to może być problem (jeśli każda zmiana generuje zdarzenie), lub nie.
    Przy okazji, trzeba też pamiętać, że są różne enkodery - niektóre pomiędzy stabilnymi pozycjami generuja 1 impuls, ale są takie, które generują 2 lub 4. W takich sytuacjach NoOfPulses należy podzielić przez 2 lub 4.


    Zauważ że na wejściu schematu wyżej są kondensatory 100n więc drgań tu nie będzie napewno - tym bardziej że enkodery są zwykle oparte o układy optyczne a nie mechaniczne.

  • #14 24 Gru 2010 16:10
    tmf
    Moderator Mikrokontrolery Projektowanie

    Zauważ, że nie rozmawiamy o powyższym schemacie, to czy 100nF wystarczy zależy od pullupa i stałej RC, a enkodery o których tu mowa to zwykłe enkodery obrotowe, mechaniczne, a nie optyczne. Raczej nikt przy zdrowych zmysłach nie wrzuciłby do sterowania menu enkodera optycznego za kilkaset zł :)
    Wesołych Świąt.

  • #15 27 Gru 2010 09:15
    Fredy
    Poziom 27  

    Ja obsługę takich enkoderów wykonuje zawsze na jednym przerwaniu. Jeden z impulsów wywołuje przerwanie, w obsłudze przerwania sprawdzam tylko stan drugiego kanału. Jeśli jest wysoki to ++licznik, jeśli jest niski to --licznik.

  • #16 27 Gru 2010 10:57
    tmf
    Moderator Mikrokontrolery Projektowanie

    Moim zdaniem jest to kepski pomysł. Ew. drgania styków wywołują serię przerwań, dzięki czemu procesor niepotrzebnie jest zajęty. IMHO lepiej to robić na zasadzie poolingu z przerwania timera. Wtedy cały program działa w sposób bardziej deterministyczny.

  • #17 27 Gru 2010 22:50
    Fredy
    Poziom 27  

    tmf napisał:
    Moim zdaniem jest to kepski pomysł. Ew. drgania styków wywołują serię przerwań, dzięki czemu procesor niepotrzebnie jest zajęty. IMHO lepiej to robić na zasadzie poolingu z przerwania timera. Wtedy cały program działa w sposób bardziej deterministyczny.


    A tak nie będzie procesor zajęty ? To dopiero będzie masakra.
    No chyba że będziesz odpytywać raz na sekundę ......

  • #18 27 Gru 2010 23:40
    tmf
    Moderator Mikrokontrolery Projektowanie

    Będzie, ale w sposób przewidywalny. W dodatku odpowiedni dobór czasu pomiędzy kolejnymi wyzwoleniami przerwania załatwia automatycznie debouncing. Przy przerwaniach z kolei, dopóki nie kręcisz jest ok, ale jak zaczniesz to masz nagle przerwanie za przerwaniem. W efekcie program jest małodeterministyczny, a policzenie czasu reakcji staje się niemożliwe. A w wielu sytuacjach maksymalny czas reakcji programu warto znać, chociażby żeby wiedzieć z jakim opóźnieniem wchodzisz w przerwania krytyczne czasowo.

  • #19 27 Gru 2010 23:51
    Fredy
    Poziom 27  

    Nie zgadzam się z Tobą.

    Wyobraź sobie sytuację - kręcisz dość szybko. Pojawia się impuls na kanale A. Wtedy musisz natychmiast sprawdzić stan kanału B. Jeśli zrobisz to zbyt późno to możesz zinterpretować ruch jako odwrotny a to jest totalny error.
    Przy szybkim kręceniu enkodera stan przejściowe trwają bardzo krótko, a tak naprawdę miarodajne są zbocza tych sygnałów.
    Także gwarantuje ci że Twoje rozwiązanie słabo zda egzamin.
    No chyba że będziesz testować co 0,1ms. Ale wtedy to procek to mocno odczuje - dużo więcej aniżeli w przerwaniach.

  • #20 28 Gru 2010 10:53
    tmf
    Moderator Mikrokontrolery Projektowanie

    Nie masz racji. Szybsze kręcenie wcale nie skraca okresów niestabilności. Łatwo się o tym przekonać na oscyloskopie. Stąd też enkoder mechaniczny po prostu ma górną ilość impulsów jakie można wykręcić, przekroczenie tej wartości uniemożliwia wiarygodny odczyt. Zresztą tak jak piszę się po prostu robi, nawet Atmel w mikrokontrolerach mających sprzętową obsługę enkodera korzysta z czegoś w rodzaju timerów. Zbocza się nie nadają do interpretacji bo na jeden przeskok enkodera jeden z sygnałów będzie generował wiele przejść. Program więc musiałby reagować na kaźde z nich, co prowadziłoby do błędów.

  • #21 28 Gru 2010 18:39
    LordBlick
    VIP Zasłużony dla elektroda

    Osobiście używam własnej procedury na zboczach i nie odczuwam z tym żadnej niedogodności. Przerwanie na zboczu opadającym musi być potwierdzone na zboczu narastającym, ot cały debouncing. Obsługa przerwania to mikrosekundy i jest niczym w porównaniu z namiętnie stosowanym przez niektóre przypadki waitms() ;).

  • #22 28 Gru 2010 18:57
    tmf
    Moderator Mikrokontrolery Projektowanie

    To żaden debouncjing, przecież jak drgają styki to masz naprzemienne zbocza narastające/opadające, inaczej byłby to stabilny stan logiczny :)
    Oczywiście w większości przypadków to nie przeszkadza i można sobie robić na przerwaniach. Problem pojawia się w sytuacji, kiedy inne procedury wymagają niskiego, albo chociażby przewidywalnego czasu reakcji na przerwanie. Aby to zapewnić, przerwania o niskich priorytetach robi się jako ISR_NAKED, bo większość AVRów nie ma priorytetów przerwań. No i tu właśnie rodzi się problem - takiego przerwania, gdzie masz nieprzewidywalne drgania nie można zrobić naked, bo go przerwie kolejne i dojdzie do zagnieżdżenia stosu wywołań. To samo w sobie też nie jest problemem, chyba, że... jesteś krucho z pamięcią. IMHO umieszczanie enkodera na przerwaniach INT nie ma właściwie zalet, a w pewnych sytuacjach ma wady. Ponieważ obsługa enkodera to jest coś co zrobiłem raz w życiu i kopiuje istniejący kod do innych układów, więc lepiej to zrobić raz i bezproblemowo, niż tworzyć rozwiązania, które są dobe, ale czasami.

  • #23 28 Gru 2010 22:45
    LordBlick
    VIP Zasłużony dla elektroda

    Hmmm... do tej pory żyłem z przeświadczeniem, że standardowo w AVR przerwania nie da się przerwać innym przerwaniem... Ale ja rzeźbię w asm i też kopiuję istniejący kod... ;)

  • #24 28 Gru 2010 23:02
    tmf
    Moderator Mikrokontrolery Projektowanie

    Standardowo tak jest, ale nic nie stoi na przeszkodzie, żeby pierwszą instrukcją obsługi przerwania było sei. W AVR-libc załatwia to atrybut ISR_NOBLOCK. W poprzednim poście błędnie napisałem ISR_NAKED, coś mi jakieś nagości widać chodzą po głowie :)

  Szukaj w 4mln produktów
Przeglądaj produkty