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

Jak poprawnie skonfigurować Timer0 i Timer2 w wyświetlaczu widmowym?

xamrex 05 Sie 2015 09:53 1659 24
REKLAMA
  • #1 14899444
    xamrex
    Poziom 28  
    Witam,
    Przymierzam się do zrobienia wyświetlacza widmowego.
    Póki co mam prototyp, który działa, ale nie bardzo dobrze.
    Wydaje mi się, że wiem w czym tkwi problem, ale nie wiem do końca jak go rozwiązać..

    Założyłem sobie, że wyświetlacz będzie podzielony na 20 części, czyli mogę wyświetlić obraz co 18stopni(360/20).

    Czytając informacje znalezione w Internecie zasada takiego wyświetlacza powinna być następująca.

    1.Odpalamy Timer0(jako licznik), który zlicza czas potrzeby do zrobienia jednego okrążenia wiatraka
    2.Konfigurujemy Timer2 tak, aby przerwanie było 20 razy(bo taką założyłem rozdzielczość) częściej niż obrót pełnego obrotu wentylatora.

    W przerwaniu Timera2 wystawiamy na port, do którego podpięte są diody nasz obraz.

    Czy taka zasada jest poprawna?
    #############################################
    Bo w rzeczywistości nie działa to najlepiej..
    Tzn.
    Mój wentylator potrzebuje ok 25ms na wykonanie obrotu (2400 obr/min)
    Mam uC napędzany kwarcem 8Mhz.
    Konfiguruję prescaler licznika(timera0) na podział przez 1024, co daje mi jeden 'impuls' co 128us.
    Więc maksymalną wartość do jakiej może doliczyć licznik (aby się nie przekręcić to ) 128us*255= 32640us=32,6ms.
    Czyli wszystko OK.

    Teraz ustawiam timer2 jako CTC i wpisuję do niego wartość 20 razy mniejszą niż tą do której doliczył Timer0.

    I wszystko niby działa, ale na końcu obrotu widać, że obraz się przesuwa/drga/jest niewyraźny.
    Dzieje się to z pewnością dlatego, że te przerwania nie są DOKŁADNIE wykonywane 20 razy w ciągu pełnego obrotu wentylatora.

    No bo załóżmy, że licznik(timer0) doliczył do 176 (czyli wentylator obraca się co 176*128us=22,5ms)
    i teraz dzielimy 176/20=8.8 niestety nie można wpisać wartości ułamkowej do TIMERA2, aby wyzwolić przerwania więc zostanie ta wpisana wartość 8, i tym samym przerwania nie będą wykonywane 20 razy w ciągu obrotu wentylatora a OKOŁO 20 razy (pewnie coś koło 19 albo)...

    Chciałbym się dowiedzieć, czy coś źle robię, czy ta koncepcja jest zła...
    Albo jak to rozwiązać?? Mogę użyć timera 16bit, ale mało prockow ma 2 timery 16 bit..
    Jak inne osoby to rozwiązaly?
  • REKLAMA
  • #2 14899497
    Wirnick
    Poziom 30  
    A jakby w przerwaniu timera0 wstawić flagę zliczającą do 20. Wtedy, wystarczyłaby korekcja czasu jednego timera do czasu obrotu wentylatora.
  • #3 14899518
    xamrex
    Poziom 28  
    Nie rozumem o co dokładnie chodzi.
    U mnie nie występuje przerwanie Timera0, używam go tylko jako licznik. (aby dostać informacje jak długo trwa jeden płeny obrót wentylatora)
    Wartość nigdy nie przekroczy 255(timer nigdy się nie 'przekręci')..
  • #4 14899564
    zumek
    Poziom 39  
    A napisz nam, jak obliczasz położenie wałka silnika/wyświetlacza i/lub czas pełnego obrotu:?:
  • #5 14899572
    piotrva
    VIP Zasłużony dla elektroda
    Musisz na pewno wykrywać przejście ramienia z diodami nad "punktem zero".
    Dzięki temu będziesz miał 2 pieczenie na 1 ogniu - zmierzysz okres obrotu i zawsze będziesz zaczynać wyświetlanie od tego samego punktu (kąta).

    Możesz to zrobić za pomocą hallotronu i małego magnesu lub metodą optyczną.
  • #6 14899615
    xamrex
    Poziom 28  
    Mam to za pomocą fototranzysotra.
    Po wykryciu przerwania od fototranzysotra (na INT1)
    odczytuję wartość z rejestru TCNT0 i mnoże razy 128us, co daje mi czas pełnego borotu
    następnie kasuję wartość TCNT0 ,aby znów mierzył od początku,,,

    Ale tak jak pisałem, ja to już mam zrobione, tylko jeśli licznik doliczy do np 176, to jeśli podzielę te wartość przez 20(aby wpisać ją do drugiego licznika, który działa w trybie CTC, ) to ta wartość wynosi 8.8!!! co jest zaokrąglane do 8 więc stąd biorą się te niedokładności!.
    Myślę nad odpaleniem zamiast timera8bit timera 16 bit, wtedy będzie to dokładniej i nie powinno być problemów..

    Spójrzcie.
    Jeśli licznik policzy do 176us, to pełnu obrót trwa 176*128us=22528us

    Teraz jesli do timera pracującego w trybie CTC wpiszę 176/20=~8
    to przerwanie wykonuje się co 1250us,
    a 1250*20=25000us
    a 25000us != 22528us

    Dodano po 36 [minuty]:

    Widzę, problem jest w tym, że licznik2, który miał działac 20 razy cześciej niż licznik0, miał ten sa prescaler, i po prostu do ORC2 wpisywałem wartość TCNT0/20..
    To powodowało błędy w dokładności na poziomie nawet 10%

    A muszę zmienić prescaler, i wpisać odpowiednią wyliczoną warotść (wtey błędy zmaleją do 0.5%)
  • REKLAMA
  • #7 14900403
    xamrex
    Poziom 28  
    COś mi to nie działa tak jak ma ;/
    Mam taki kod:
    Pełny obrót trwa ok 26ms..
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    A to test jak to wygląda..
    Widać, że skacze...






    Dlaczego ten obraz tak skacze?
    Kod jest strasznie prosty.. W czym może tkwić problem?
  • #8 14900519
    zumek
    Poziom 39  
    xamrex napisał:

    Dlaczego ten obraz tak skacze?
    Kod jest strasznie prosty.. W czym może tkwić problem?

    Ja bym jeszcze resetował preskaler T0/T2 .
  • #9 14900545
    xamrex
    Poziom 28  
    zumek napisał:
    a bym jeszcze resetował preskaler T0/T2 .

    Resetował? Tzn ustalał na nowo??
    Przecież on się nie zmienia.

    Naprawdę liczę na pomoc ;-)
  • REKLAMA
  • #10 14900588
    Wirnick
    Poziom 30  
    "Mam uC napędzany kwarcem 8Mhz.
    uint16_t freq=((50000UL/((TCNT0*128)/20))*10);" Tu jest jakiś błąd w kodzie?
  • #11 14900659
    xamrex
    Poziom 28  
    Wirnick napisał:
    "Mam uC napędzany kwarcem 8Mhz.
    uint16_t freq=((50000UL/((TCNT0*128)/20))*10);" Tu jest jakiś błąd w kodzie?

    Nie, po prostu trochę zminimalizowałem obliczenia.
    Wynik powinien wyjść poprawnie ;-)
  • #12 14900691
    dondu
    Moderator na urlopie...
    xamrex napisał:
    zumek napisał:
    a bym jeszcze resetował preskaler T0/T2 .

    Resetował? Tzn ustalał na nowo??
    Przecież on się nie zmienia.

    Zumek miał na myśli resetowanie licznika preskalera, a nie ustawień preskalera.
    Zobacz w ATmega8 bit PSR10 i rysunek Prescaler for Timer/Counter0 and Timer/Counter1

    Patrz: http://mikrokontrolery.blogspot.com/2011/03/prescaler-postscaler-co-to.html
  • #13 14900749
    xamrex
    Poziom 28  
    dondu, czyli powinienem ustawiać za każdym razem ten bit (PSR10) w rejestrze SFIOR na jednen, w obsłudze przerwania ISR(INT1_vect)?
  • Pomocny post
    #14 14900765
    Andrzej__S
    Poziom 28  
    A spróbuj może takiego sposobu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #16 14900809
    xamrex
    Poziom 28  
    Andrzej__S napisał:
    A spróbuj może takiego sposobu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Nie jest nic lepiej ;-(
    Dalej obraz 'skacze'

    Dondu ->
    1. Dla lepszej dokładności..
    Jeśli miałbym oba ustawione na 1024.
    i jeśli pierwszy licznik wskazywałby np. 123 to w drugim, aby przerwanie było wykonywane musiałbym wpisać 123/20 a to jest 6.15 i byłoby zaokrąglenie co nie jest dokładne.
    Dlatego postanowiłem na zwiększenie precyzji ustawiając mniejszy prescaler.
    2.Atmega8A-PU
    Dodano po 2 [minuty]:

    Ustalenie tego bitu PSR10 również nie pomogło..
    Zaczynam się zastanawiać czy to nie jest przypadkiem od konstrukcji mecvhanicznej..
    Tzn. mam to zrobione na wentylatorze z zasilacza PC..
    Może po prostu zbyt mocno zmieniają się obroty w czasie i z tego wynika te przesuwanie się obrazu?
  • #18 14900963
    xamrex
    Poziom 28  
    Znalazłem pewną zależność.
    Jeśli podzielę obraz na większą ilość kawałków
    Kod: C#
    Zaloguj się, aby zobaczyć kod

    Chodzi mi o tą wartość w tym wypadku 20..
    to jeśli zwiększe np. na 30, to obraz tak nie skacze
    Natomiast jeśli zmniejsze na 10. to obraz jeszce bardziej skacze

    Tutaj filmy to prezentujące:
    a)30 kawałków




    b)10 kawałków




    Tylko w czym jest problem?

    Dodano po 1 [minuty]:

    dondu napisał:
    Nadal w przerwaniu INT1 nie zatrzymujesz i nie zerujesz preskalera Timer2. Musisz być pewien, że timer0 i timer2 zawsze rozpoczynają dokładnie od początku.

    dondu-> w kodzie Andrzej__S rzeczywiście tego nie robiłem. ale u siebie to robię
  • #20 14901028
    xamrex
    Poziom 28  
    Kod: C#
    Zaloguj się, aby zobaczyć kod


    Przepraszam nie zamieściłem aktualnego kodu ;-(
    Ale te zerowanie nic nie daje..
    Zastanawia mnie dlaczego przy mniejszej rozdzielczości obraz bardziej skacze, a przy mniejszej mniej..
    Coś chyba musi być nie tak z tym kodem ;-(
    A trudno zauważyć co to ;-(

    Teraz zauwżyłem minimalną poprawkę jaką mozna zrobić..
    tzn dodać tę linijkę w obsłudze przerwania:
    Kod: C#
    Zaloguj się, aby zobaczyć kod

    Czyli cała poprawna obsługa wyglądałaby tak:
    Kod: C#
    Zaloguj się, aby zobaczyć kod


    Bo teraz po osiągnięciu pełnego obrotu nie był wyświetlany pierwszy element z tablicy, a dopiero po odczekaniu pewnego czasu (aż licznik 2 się przepełni i przejdzie do osługi przerwania)..
    teraz jest to chyba bardziej poprawnie,
    ale mimo to dalej obraz skacze ;/
    ##################################
    ##################################
    CAŁY AKTUALNY KOD:
    Kod: C#
    Zaloguj się, aby zobaczyć kod

    Ale dalej problem dalej nie rozwiązany, bo dalej skacze;(
  • Pomocny post
    #21 14901139
    dondu
    Moderator na urlopie...
    Jeszcze raz muszę napisać:

    dondu napisał:
    Nadal w przerwaniu INT1 nie zatrzymujesz i nie zerujesz preskalera Timer2. Musisz być pewien, że timer0 i timer2 zawsze rozpoczynają dokładnie od początku.

    czyli by być pewnym poprawnego działania powinieneś w przerwaniu INT1:
    - zatrzymać oba timery,
    - wyzerować ich preskalery,
    - obliczyć co ma być obliczone,
    - wyzerować liczniki (oba),
    - ustawić OCR2,
    - włączyć oba timery.

    Tylko taka procedura zapewniać będzie zawsze prawidłowe i powtarzalne odliczanie czasów.
  • #22 14901154
    xamrex
    Poziom 28  
    Okej ;-) JUtro zrobię dokładnie tak jak piszesz ;-)
    Teraz lecę spać ;-)
    Póki co serdecznie dziękuję za pomoc!
  • REKLAMA
  • #23 14901599
    Andrzej__S
    Poziom 28  
    Kolega dondu ma rajcję, przedstawiłem prostszy sposob obliczania OCR2, a zapomniałem o synchronizacji timera2.

    Spróbuj może jeszcze raz z moim kodem, ustawiając preskaler timera 2 na 64:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #24 14901640
    Wirnick
    Poziom 30  
    Mam pytanie. czy nota ATMEL obejmuje wszystkie rejestry konfiguracyjne AVR - " SFIOR |= 1<<PSR2;" jest błędem ? A powinno być bez or -" SFIOR = 1<<PSR2;
  • #25 14901834
    xamrex
    Poziom 28  
    Andrzej__S -> tak jak pisał Dondu, brakuje jeszcze (i tobie i mi) resetowanie(ustawianie na 0) timera TCNT0/TCNT2
    Ja zapomniałem w kodzie o resetowaniu TCNT2, a widzę ty o TCNT0 ;-)
    Chyba to będzie powodowało problem ze skakaniem wyświetlacza..

    Jak wrócę z pracy do domu to przetestuję i dam znac.
    Jeszcze raz chciałbym gorąco podziękować koledze dodnu za pomoc jak i za jego nieocenionego bloga;-)
    Mam nadzieję, że wszystko będzie działało ;-)

    Dodano po 5 [godziny] 49 [minuty]:

    Tak jak myślałem,
    Nie kasowałem obu timerów, tylko jeden i dlatego to nie działało;-(
    cały kod (już działa wszystko wygląda tak):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
REKLAMA