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

AVR attiny2313A - Programowy PWM, brak automatycznego zerowania TCNT0.

w1941s 25 Lip 2015 13:26 1056 9
  • #1 14873956
    w1941s
    Poziom 14  
    Witam. Piszę ponieważ mam problem z programowym PWM na attiny2313A. Ustawiam Timer w tryb CTC. Po zrównaniu TCNT0 z OCR0A powinno samo wyzerować rejestr TCNT0. Niestety tak się nie dzieje, jeśli sam się tym nie zajmę to serwa szaleją.

    Z obliczeń wynika, że przerwanie TIMER0_COMPA_vect powinno wykonywać się co 0,01ms.

    PWM ma działać tak: Uruchamiamy TIMER1(16bit), kiedy nadejdzie przerwanie od TIMERA1 po około 19ms, zatrzymujemy TIMER1 i uruchamiamy TIMER0, który zajmuje się generowaniem impulsów o szerokości od 0,01ms do 2,5ms.

    Zamieszczam kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 14874063
    dondu
    Moderator na urlopie...
    1. Nie definiuj F_CPU w kodzie programu z tych powodów: http://mikrokontrolery.blogspot.com/2011/03/fcpu-gcc-gdzie-definiowac.html

    2. Niepotrzebnie się trudzisz:

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

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


    3. Pobieżnie patrząc program jest ok, ale cudów nie ma - w trybie CTC timer na pewno zeruje się w momencie, gdy dojdzie do OCR0A. Przyczyna musi leżeć w innym miejscu. Timery te mają wspólny układ preskalera i może pod tym kątem należałoby się zastanowić?
  • Pomocny post
    #3 14874161
    Andrzej__S
    Poziom 28  
    Wygląda na to, że procedura obsługi przerwania TIMER0_COMPA_vect się nie wyrabia (ma do dyspozycji 80 taktów). Innymi słowy czas pomiędzy przerwaniami jest krótszy od czasu wykonania kodu procedury obsługi przerwania.
    Wpisanie na początku procedury instrukcji TCNT0=0; powoduje po prostu wydłużenie czasu zliczania timera 0 o czas trwania prologu procedury i wtedy jest OK.
  • #4 14874163
    w1941s
    Poziom 14  
    Przystosowałem program do takich samych dzielników i dalej ten sam problem. Może gdzieś w obliczeniach się wysypałem :(. Nie daje mi to spokoju.

    Dodano po 23 [minuty]:

    Andrzej___S miałeś racje, najwidoczniej nie wyrabiał dałem mu do OCR0A=120; i teraz dobrze działa. Bardzo ciekawe, nie spodziewałem się tego. Trzeba będzie dać kwarc 16Mhz. Uwzględnię to w pcb.

    Dodano po 1 [minuty]:

    Tak na marginesie, jest jakiś lepszy sposób na programowy PWM?
  • #5 14874252
    Andrzej__S
    Poziom 28  
    Możesz spróbować tak:
    Zmień typ zmiennej timer na volatile uint8_t i procedurę obsługi przerwania:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Powinno działać nawet przy OCR0A=80.

    EDIT:
    ...pod warunkiem, że nie odkomentujesz linijki z servo5 :)
    Teraz dopiero zauważyłem, że ta zmienna timer w ogóle nie musi być volatile. Można nawet zastosować zmienną statyczną timer wewnątrz procedury obsługi przerwania, przy czym to już niewiele zmieni, jeśli chodzi o szybkość wykonywania procedury.

    No i zakladam, że te funkcje _delay_ms() wewnątrz funkcji main() to tylko dla testów. Dokładność odmierzanego przez nie czasu przy włączonych przerwaniach jest raczej znikoma.
  • #6 14874475
    w1941s
    Poziom 14  
    Tak _delay_ms jest tylko do testów :). Myślę, że już nie będę kombinował, dodam ten kwarc 16Mhz i będzie cacy :D. Jak wszystko zrobię to opublikuje na elektrodzie.
  • #7 14874606
    Andrzej__S
    Poziom 28  
    w1941s napisał:
    Myślę, że już nie będę kombinował, dodam ten kwarc 16Mhz i będzie cacy :D

    Niezależnie od tego, jakie taktowanie zastosujesz, dobrze jest zadbać o to, żeby procedura obsługi przerwania była jak najkrótsza. Daje to więcej czasu na wykonanie normalnego kodu, jak i procedur innych przerwań - zwiększa wydajność kodu.
  • #8 14876117
    w1941s
    Poziom 14  
    Ok, zastosuję się do wskazówek. Ale dlaczego właściwie zrobienie zmiennej tymczasowej i późniejsze jej używanie zamiast volatile jest szybsze? Chodzi o to, że zmienna volatile cały czas odczytywana jest z pamięci i ładowana do rejestru a zmienna bez volatile, ładowana jest tylko raz? Czy dobrze myślę?
  • Pomocny post
    #9 14876638
    Andrzej__S
    Poziom 28  
    w1941s napisał:
    Chodzi o to, że zmienna volatile cały czas odczytywana jest z pamięci i ładowana do rejestru a zmienna bez volatile, ładowana jest tylko raz? Czy dobrze myślę?

    Dobrze myślisz.
    Ogólnie zmienna globalna volatile ma sens w sytuacji, gdy ze zmiennej korzystasz jednocześnie w programie głównym i w procedurze obsługi przerwania. W Twoim przypadku, gdy korzystasz ze zmiennej tylko wewnątrz procedury obsługi przerwania, volatile jest niepotrzebne. Mało tego, w takim przypadku zawsze lepiej (bezpieczniej) jest zastosować zmienną statyczną (czyli taką, która nie zmienia wartości pomiędzy wywołaniami funkcji) wewnątrz procedury.

    Jeśli nawet musisz zastosować volatile, to jest ono istotne bardziej z punktu widzenia programu głównego, ponieważ w nieprzewidywalnym momencie może wystąpić przerwanie i zmienić wartość zmiennej (w przypadku zmiennych wielobajtowych należy dodatkowo zapewnić atomowy dostęp do zmiennej).
    Z punktu widzenia procedury obsługi przerwania natomiast, volatile zwykle nie jest już takie istotne, ponieważ przeważnie zezwolenie na przerwania w czasie wykonywania procedury jest wyłączone, więc nieoczekiwana zmiana wartości zmiennej jest niemożliwa. Jeśli wewnątrz procedury kilkakrotnie trzeba korzystać ze zmiennej volatile, korzystniej jest załadować ją raz i korzystać z jej kopii. Pozwala to zaoszczędzić kilka taktów na każde odwołanie do zmiennej (razy ilość odwołań) i czasami znacząco skrócić czas wykonywania procedury. Jest to szczególnie istotne w sytuacjach, kiedy stosunek czasu pomiędzy wywołaniami przerwania a czasem wykonania procedury jest duży.

    Z grubsza licząc procedura obsługi przerwania trwająca 120 taktów wywoływana co 160 taktów konsumuje ok. 75% czasu procesora. Zaoszczędzenie nawet 20-30 taktów w tej sytuacji może okazać się kluczowe dla poprawnego działania programu, szczególnie jeśli chcemy korzystać także z innych przerwań.
  • #10 14878800
    w1941s
    Poziom 14  
    Dziękuję za wyjaśnienie, zastosuję się do wskazówek :). Temat uważam za zakończony. Jeszcze raz dzięki :).
REKLAMA