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.

Enkoder (zdarzenia, dekoder) - wyskalowanie wyniku - XMEGA

23 Wrz 2017 23:19 1152 30
  • Poziom 3  
    Witam chciałbym za pomocą enkodera regulować wartość w zmiennej: war_zad, od 0 do 3700. Wykorzystałem w tym celu zdarzenia i wbudowany dekoder do obsługi enkodera w atxmega128a3u. Lecz zastanawiam się w jaki sposób to wykonać by moja zmienna zmieniała się od 0 do 3700 bo gdy zmniejszę wartość timera CNT poniżej zera to mam odrazu wartość maksymalną. Wykonałem to w troche wydaje mi się prymitywny sposób poprzez wpisanie wartości początkowej do CNT, który przedstawiam poniżej. Można to jakoś lepiej wykonać?

    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    Jest ok. Można to ew. tak zrobić, że wykorzystujesz przerwanie przepełnienia lub porównania licznika i w jego ISR korygujesz CNT. Są jeszcze enkodery z indeksem, dzięki temu masz absolutną pozycję enkodera. Ale to już w zależności od tego do czego wykorzystujesz enkoder.
  • Poziom 3  
    Ale tutaj chodzi o przerwanie od przepełniona innego licznika niż wykorzystany w obsłudze enkodera?
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    Nie, tego z obsługi enkodera. Jak sądę przejściu 0->top i top->0 towarzyszy przerwanie nadmiaru. Ew. można wykorzystać przerwanie compare z kanałów A-D.
  • Poziom 3  
    Witam, zrealizowałem obsługę w przerwaniu od przepełnienia timera lecz nie do końca idealnie to działa. Dodałem regulacje precyzyjną i zgróbną wartości zadanej. Przy regulacji precyzyjnej generalnie działa wszystko dobrze, lecz przy regulacji zgrubnej gdy przycisk enkodera jest wciśnięty to zawrtośc zadana potrafi niekiedy skakać o duże wartości np. z 2500 do 1300. Co może być przyczyną?

    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Moderator Mikrokontrolery Projektowanie
    Sprawdzanie, czy uint16_t jest mniejszy niż zero nie ma sensu. Z definicji być nie może. Druga sprawa i myślę, że to jest przyczyną skoków to atomowość dostępu do war_pom. Pomyśl co się stanie, gdy w czasie sprawdzania warunków w main wystąpi przerwnaie OVF? Wszelkie operacje (w tym porównania) muszą być prowadzone na war_pom w sposób atomowy.
  • Poziom 3  
    Poczytałem trochę o atomowym dostępie i o ATOMIC_BLOCK. Wynikało by że: jeżeli moja zmienna war_pom jest testowana w warunku logicznym to trzeba w sposób atomowy przepisać jej zawartość do zmiennej pomocniczej. Lecz program po wgraniu zachowuje się nadal tam samo, czyli: mogę zwiększać wartość zadaną ale często gdy kręcę enkoderem to wartość jest nie zmieniana oraz niekiedy występują duże skoki.

    Zmodyfikowałem to tak, lecz nie wiem czy poprawnie.

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    Teraz zmienna tmpa jest zmieniana poprawnie, problem w tym, że na końcu wyniku tego obcięcia do 0..3700 nie zapisujesz, tylko przypisujesz do war_zad. Natomiast każde ovf z licznika zmienia war_pom w sposób ograniczony tylko typem.
  • Poziom 3  
    Czyli jak mogę zapisać to do war_zad? nie mam żadnego pomysłu.
  • Użytkownik usunął konto  
  • Poziom 3  
    Niestety nic to nie pomogło.
  • Użytkownik usunął konto  
  • Moderator Mikrokontrolery Projektowanie
    R-MIK napisał:
    Użyj ATOMIC_RESTORESTATE a nie ATOMIC_FORCEON. Dzięki temu odtwarzany jest stan znacznika I a nie bezwzględnie ustawiany.


    A po co? Jeśli w programie p[rzerwania są odblokowane to nie ma sensu używać restorestate, skoro wiemy, że przed blokiem atomowym przerwania były włączone.
  • Poziom 3  
    A w jaki sposób mogę poprawić mój program żeby enkoder działał poprawnie? Bardzo proszę o jakieś podpowiedzi gdyż nie rozumiem nadal czemu teraz nie działa i do zmiennej war_zad nie jest zapisywana wartość.
  • Pomocny post
    Użytkownik usunął konto  
  • Pomocny post
    Poziom 17  
    Problemem jest tutaj fakt ze licznik zlicza impulsy. A ty każdemu krokowi enkodera chcesz przypisać pewna wartość (regulacja zgrubna/precyzyjna) a tego licznik nie robi (bo każdy impuls jest traktowany z taka sama waga).

    Jednym z możliwych rozwiązań jest zliczanie ilości impulsów i mnożenie ich przez wagę (w zależności od wybranej dokładności).

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Przy takim rozwiązaniu przerwanie nie sa potrzebne ani żadne zmienne globalne.

    p.s. Listing z glowy nie wiem czy sie kompiluje.
  • Poziom 3  
    niestety nie, gdy wpisze zamiast zmiennej regulacja, na twardo jakąś wartość to nadal występują niekiedy skoki.

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    Użytkownik usunął konto  
  • Moderator Mikrokontrolery Projektowanie
    R-MIK napisał:
    tmf napisał:

    R-MIK napisał:
    Użyj ATOMIC_RESTORESTATE a nie ATOMIC_FORCEON. Dzięki temu odtwarzany jest stan znacznika I a nie bezwzględnie ustawiany.



    A po co? Jeśli w programie p[rzerwania są odblokowane to nie ma sensu używać restorestate, skoro wiemy, że przed blokiem atomowym przerwania były włączone.


    Tak, ale jeśli kiedyś, z jakiegoś powodu, gdzieś wcześniej zablokuje przerwania, to co się stanie po użyciu ATOMIC_FORCEON? Takiego błędu mozna później długo szukać. Owszem, ATOMIC_RESTORESTATE to jeden rozkaz więcej, ale jest to metoda bezpieczna. Ja staram się "sprzątać" po wywołaniu funkcji itp. To później ułatwia życie. Naturalnie, jak program ma 2kB to nie problem poszukać, ale jak 60?

    Jeden a programistów założył, że 1-Wire zawsze jest sprawne. Co sie stało jak zwarłem ją do masy? DS18B20 odczytywał -127 stopni. Dalsze konsekwencje? Łatwo sie domyśleć, zawsze było za zimno.


    Takie tam gadanie. Mamy konkretny program i nie ma co gdybać. Gołego cli()/sei() w programie właściwie się nie używa, więc sytuacja o której piszesz jest czysto teoretyczna. Zresztą jeśli wiem, że przerwania są zablokowane to nie używam ATOMIC_BLOCK, bo na AVR nie ma po co. Tu dodatkowo mamy XMEGA, gdzie mamy 3-poziomowy kontroler i takie zabawy z cli() zupełnie sensu nie mają.

    Dodano po 2 [minuty]:

    R-MIK napisał:
    kamil94goldman napisał:
    niestety nie, gdy wpisze zamiast zmiennej regulacja, na twardo jakąś wartość to nadal występują niekiedy skoki.

    Czy te skoki nie występują przypadkiem podczas zmniejszania?
    Nie masz programowej eliminacji drżenia styków, dodaj kondensatory na liniach enkodera.


    Znowu zapytam po co? Po pierwsze w XMEGA mamy możliwość sprzętowego filtrowania cyfrowego i z tego należy skorzystać, poza tym drgania przy enkoderze w niczym nie przeszkadzają. Nie ma możliwości, aby spowodowały nieprawidłowe liczenie, co najwyżej przez kilka milisekund stan licznika będzie się wahał +/-1.
  • Poziom 3  
    @sawitar Po poprawieniu paru małych uchybień kod się skompilował lecz nie działa poprawnie.

    Poprawki: usunięcie ";" w deklaracji enum, dodanie w nawiasie atomic_block: "ATOMIC_FORCEON", oraz zanegowanie: "if(!(PORTF.IN & PIN0_bm))"

    Program działa tak: bez wciśnięci i kręcenia czegokolwiek to około 1 s na wyświetlaczu wyświetlana jest na zmiane wartośc: "0" lub "3700" a gdy wcisnę przycisk to jest wyświetlane cały czas "0". Na kręcenie się enkodera nie ma żadnej reakcji.

    Nie rozumiem jak miałoby to działać, najpierw zapisywana jest wartosc CNT do zmiennej wartosc_licznika, potem kasowane jest CNT. Następnie obliczane jest ilosc kroków = wartosc_licznika - wartosc_referencyjna czyli wynikiem jest 0. potem cnt jest już = 0 wiec ilość kroków ciągle jest chyba 1000 lub -1000.

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Moderator Mikrokontrolery Projektowanie
    @kamil94goldman Ciągle w twoim kodzie nie widzę korekcji war_pom. Teraz to działa tak, że enkoderem zmieniasz wartość tej zmiennej. jeśli przekracza ona 3700 to wyświetlasz 3700, ale zmienna ciągle może rosnąć przy dalszym kręceniu enkodera. Podobnie w drugą stronę - jeśli jest mniejsza od zera, to wyświetlasz zero, ale zmienna może przyjmować co raz niższe wartości. Jeśli przekroczy 32767 lub -32768 to się "zawinie". Ty będziesz to widział jako np. przeskok z zera na 3700 i vice versa.

    Dodano po 2 [minuty]:

    BTW, przy dostępie do CNT nie potrzeba zamykać instrukcji w ATOMIC_BLOCK - w tym przypadku o atomowość dba sprzętowo MCU.
  • Poziom 3  
    @tmf wiec tak: dałem warunki w programie obsługi przerwania, a przy przypisywaniu war_pom do war_zad zapewniłem atomowośc. Ale po uruchomieniu programu i tak występowały spore skoki

    @tmf & @R-MIK co ciekawe po dodaniu małego kondensatora ceramicznego między pin C0 a GND wygląda na to że wszystko działa poprawnie. Może te 8 cylki filtru nie wystarcza?

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 3  
    Choć ciekawe jest to że wymieniłem teraz enkoder na inny i na tym nowym nawet bez kondensatora wszystko działa poprawnie ;)
  • Poziom 17  
    kamil94goldman napisał:

    Nie rozumiem jak miałoby to działać, najpierw zapisywana jest wartosc CNT do zmiennej wartosc_licznika, potem kasowane jest CNT. Następnie obliczane jest ilosc kroków = wartosc_licznika - wartosc_referencyjna czyli wynikiem jest 0. potem cnt jest już = 0 wiec ilość kroków ciągle jest chyba 1000 lub -1000.


    Maly blad w funkcji encoder_odczyt. Powinno byc:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Kod działa tak:
    Najpierw do licznika (TCC0.CNT) zapisuje WARTOSC_REFERENCYJNA. Co 80ms jest wołana funkcja encoder_odczyt która sprawdza o ile zmieniła się wartość licznika (o ile skoków oraz w która stronę. Robię to odejmując od aktualnego stanu licznika wartość referencyjna. W wyniku dostaniesz o ile zmienił się licznik (ta wartość może być ujemna)
    Teraz mnożę ilość skoków encodera przez wielkość skoku (zadana precyzja) i wynik dodaje w poprzednią wartością.
  • Moderator Mikrokontrolery Projektowanie
    R-MIK napisał:
    kamil94goldman napisał:
    @tmf & @R-MIK co ciekawe po dodaniu małego kondensatora ceramicznego między pin C0 a GND wygląda na to że wszystko działa poprawnie. Może te 8 cylki filtru nie wystarcza?

    Policz stałą czasowa filtra RC (ja dawałem 10nF, podciąganie jest ok 40k), czas drżenia styków (10..20ms) a czas trwania 8 cykli i wszystko stanie sie jasne.
    Drżenia styków nie zlikwiduje filtr na 8 cyki. Taki filtr rozwiąże problem przepięć i innych zakłóceń indukujących się np w przewodach ale nie drżenie styków mechanicznych. Swego czasu były scalaczki specjalnie do tego celu (rejestr przesuwający, zegar, bramki or i and oraz przerzutnik RS). Teraz robi sie to programowo.


    Owszem, zlikwiduje częściowo, natomiast nie jest to oczywiście debouncing. Zobacz jak wygląda kod Graya - przy stabilnej jednej linii zmienia się tylko druga. W efekcie drgania przekładają się na chwilowe zmiany 0<->-1 lub 0<->1 i nic poza tym. To przeszkadza tylko w wyjątkowych sytuacjach., w powyższym kodzie nie może mieć żadnego wpływu na jego działanie. Jeśli jest inaczej to znaczy, że gdzieś jeszcze jest w kodzie błąd i wypadałoby go znaleźć a nie maskować problem. Autor napisał, że po wymianie enkodera jest ok - to świadczy o tym, że pierwszy był uszkodzony - przy kręceniu musiał przerywać na obu liniach, co nie powinno mieć miejsca.
    BTW, producent zaleca aby timer ustawiać w trybie QDEC tak, aby PER było równe 4*x-1. Czyli w tym przypadku np. 3. Też warto zobaczyć ile impulsów generuje enkoder przy jednostkowej zmianie, bo są różne i warto do tego dostosować timer.
  • Poziom 3  
    Niby prosty enkoder a tyle problemów ;)

    Niby działa ale jednak nie zawsze i nie za dobrze, nadal zdarzają się jakieś skoki lub postoje.

    Chciałem użyć regulacje wartości zadanej do regulacji napięcia w mojej przetwornicy typu flyback sterowanej XMEGą

    Tranzystor przełączający flybacka jest sterowany przez driver IR2125 który posiada zabezpieczenie przeciążęniowe/zwarciowe poprzez pomiar napięcia na rezystorze bocznikowym. Transformator zaprojektowałem oraz wykonałem samemu, obliczenia przeprowadziłem za pomocą współczynnika geometrii rdzenia zgodnie z informacjami w książce "Transformers and inductor design" które zgadzają się z kalkulatorem ze strony waltera schmidta Link. Pomiar napięcia jest realizowany w trybie freeruning z częstotliwością trochę mniejszą niż częstotliwość pwm(potem zamierzam ją zwiększyć do wartości około 3 x częstotliwość pwm, a częstotliwość pwm wynosi 62 kHz. Regulacja jest zawarta w przerwaniach od timera, przerwania od timera zachodzą z częstotliwością bliską częstotliwości pwm tak aby układ miał szanse szybko zareagować.

    Jeśli chodzi o samą przetwornice i jej program to wszystko działa prawidłowo, gdy zamiast enkodera mam dwa przyciski. Zarówno z obciążeniem jak i bez obciążenia napięcie na wyjściu jest stabilne tak samo w stanach dynamicznych napięcie jest stabilne, oczywiście nie jest to jeszcze ideał i jest to na pewno jeszcze wiele do zrobienia. Na razie zrealizowałem prosty programowy regulator typu P, a zamierzam zrobić PID, więc wtedy właściwości przetwornicy na pewno się poprawią. Napięcie wejściowe przetwornicy wynosi 17 V DC a wyjściowe (max) 40 V DC

    Dodałem to programu przetwornicy program enkodera zamiast przycisków lecz nie działa ta nastawa zbyt dobrze, są dosyć częste skoki itp. timer mam ustawiony w trybie QDEC lecz jak ustawie wartośc max timera na 3 to nic się nie zmienia.

    A oto program całej przetwornicy. Może jakieś sugestie, uwagi? ;)

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Poziom 3  
    Którego? ;) tcc0 jest do enkodera, tcd0 do cyklicznej regulacji a tce0 do pwm.

    Muszę jeszcze przetestować twój program do enkodera bo jeszcze nie zdążyłem.
  • Moderator Mikrokontrolery Projektowanie
    kamil94goldman napisał:
    Którego? ;) tcc0 jest do enkodera, tcd0 do cyklicznej regulacji a tce0 do pwm.

    Muszę jeszcze przetestować twój program do enkodera bo jeszcze nie zdążyłem.


    Znalazłem jeszcze taki kwiatek:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Włączyłeś pull upa dla PIN0, ale nie dla PIN1 - czyli druga linia enkodera pracuje bez podciągania i szumi jeśli jest rozłączona.
    Dodaj konfg dla PIN1, lub ustaw maskowanie w rejestrze maskowania konfiguracji pinów.
    Jeśli to nadal nie to, to napisz przy jakich wartościach odczyt skacze, może to naprowadzi na trop.