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

[Atmega8][winavr] problem z konfigiracją Timera1 PWM

pawelvod 13 Lut 2011 15:10 2637 10
  • #1 9145792
    pawelvod
    Poziom 18  
    Witam chciałem skonfigurować timer1 w ten sposób że:
    1.chodzi on cały czas odliczając 0-255
    2.Przerwanie wywoływane jest po pierwsze po każdym przepełnieniu (czyli SIG_OVERFLOW1)
    3.Przerwanie wywoływane jest w określonym czasie odliczania zapisanym w ICR1 (czyli TIMER1_CAPT_vect)
    Mój kod inicjujący przerwanie wygląda tak:
    TCCR1A = (1<<WGM10);
    		TCCR1B = (1<<WGM12)|(1<<CS10)|(1<<CS12);//256 bit fas PWM z preskalerem na najwolniejszy
    		ICR1 = 128;
    		TIMSK |= _BV(TOIE1);
    		TIMSK |= _BV(TICIE1);
    sei();

    Obsługa przerwań:
    ISR(TIMER1_CAPT_vect){
      LED_PORT ^= LED_2;
    }
    ISR(SIG_OVERFLOW1){
    	LED_PORT ^= LED_1;
    }

    Dioda 1 mruga jak szalona a dioda 2 milczy.
    Założenie jest takie, żeby dioda 2 zapalała się i gasła w połowie czasu gdy dioda 1 jest zapalona. Stąd ICR1 = 128.
    Nie bardzo wiem gdzie błąd i czy da się tak w ogóle skonfigurować timer.
    Oczywiście 128 nie jest wartością docelową tylko ma być zmienna, a czasami ma się zmieniać 2-3 razy w ciągu jednego zliczania timera, czyli wywołać przerwanie na 10, 40 i 90 cyklu powiedzmy. Update ICR1 wew. przerwania . Na razie nie wchodzi mi w ogóle w ISR(TIMER1_CAPT_vect)
  • #2 9145820
    Andrzej__S
    Poziom 28  
    Zamiast ICR1 powinieneś użyć np. OCR1A i przerwania TIMER1_COMPA_vect.

    Rejestr ICR1 służy do czegoś innego. Zapamiętuje wartość timera 1 na przykład w momencie zmiany stanu logicznego na pinie ICP1. Wykorzystuje się go np. do pomiaru czasu między zdarzeniami zewnętrznymi.
  • #3 9145839
    tmf
    VIP Zasłużony dla elektroda
    SIG_OVERFLOW1 ni ejest symbolem, którego możesz użyć w powiązaniu z ISR. Zamiast tego użyj TIM1_OVF_vect .
    Poza tym dlaczego chcesz użyć trybu fast PWM? Użyj normal mode.
  • #4 9145938
    pawelvod
    Poziom 18  
    zmieniłem kod na:
    //przerwanie 1 PWM
    		TCCR1A = (1<<WGM10);
    		TCCR1B = (1<<CS10)|(1<<CS12)|(1<<ICES1);//PWM z preskalerem na najwolniejszy
    		OCR1A = 128;
    		TIMSK |= _BV(TOIE1);
    		TIMSK |= _BV(TICIE1);
    ISR(TIMER1_COMPA_vect){
      LED_PORT ^= LED_2;
    }
    ISR(TIMER1_OVF_vect){
    	LED_PORT ^= LED_1;
    }

    Zmieniłem na
    Efekt jest taki, że dioda 1 miga jak migała(czyli wektor TIMER1_OVF_vect poprawiony na ten co powinien).
    Natomiast po uruchomnieniu TIMSK |= _BV(TICIE1); program idzie w las. Czyli nie ustawiony wektor przerwania. Co do trybu PWM to chyba tylko w takim trybie mogę uzyskać porównanie licznika z którymś z rejestrów (OCR1A) w trakcie inkrementacji.

    Dodano po 8 [sekundy]:
  • #5 9146144
    Andrzej__S
    Poziom 28  
    W celu zezwolenia na przerwanie TIMER1_COMPA należy ustawić flagę OCIE1A, a nie TICIE1.

    pawelvod napisał:

    Co do trybu PWM to chyba tylko w takim trybie mogę uzyskać porównanie licznika z którymś z rejestrów (OCR1A) w trakcie inkrementacji.

    Nie tylko w takim trybie. W trybie Normal też uzyskasz przerwania w momencie zrównania wartości timera z rejestrem OCR1A, dodatkowo będziesz mógł używać większej rozdzielczości (16-bitowej). Wprawdzie Atmel nie zaleca używania tych przerwań do generowania przebiegów, ale jak używasz dużego preskalera i nie wydłużysz znacząco kodu obsługi przerwań, to myślę, że powinno działać prawidłowo.

    P.S.
    Pamiętaj jeszcze o tym, że gdybyś zmienił tryb pracy z obecnego 8-bitowego na tryb Normal 16-bitowy, czasy generowanego przebiegu wydłużą się 256 razy, więc w celu uzyskania tych samych lub przynajmniej podobnych czasów będziesz prawdopodobnie musiał zmniejszyć preskaler (256-krotnie). Problemem może być to, że obecnie masz ustawiony preskaler 1024, a ATmega8 nie oferuje preskalera 256-krotnie mniejszego, czyli preskalera 4. Poza tym, jak ustawisz niski preskaler, to obsługa przerwań może się nie wyrabiać, jeśli do rejestru OCR1A będziesz wpisywał zbyt niskie wartości (odstępy między poszczególnymi przerwaniami będą zbyt krótkie).
  • #6 9147041
    pawelvod
    Poziom 18  
    Wszystko już chodzi tak jak trzeba. Jeszcze ostatnia rzecz której nie do końca mogę pojąć z dokumentacji. Widzę, że można w trybie normal ustawić OCR1A tak żeby po osiągnięciu tej wartości timer się resetował i liczył od nowa. Jest jeszcze coś o rejestrze ICR1. Czy można zrobić tak, żeby jeden z tych rejestrów resetował timer po doliczeniu do jego wartości, a drugi jedynie wywoływał przerwanie gdy timer osiągnie jego wartość?
  • #7 9147451
    Andrzej__S
    Poziom 28  
    Cytat:

    Widzę, że można w trybie normal ustawić OCR1A tak żeby po osiągnięciu tej wartości timer się resetował i liczył od nowa. Jest jeszcze coś o rejestrze ICR1. Czy można zrobić tak, żeby jeden z tych rejestrów resetował timer po doliczeniu do jego wartości, a drugi jedynie wywoływał przerwanie gdy timer osiągnie jego wartość?

    Tak. Ten tryb pracy nazywa się Clear Timer on Compare Match (CTC). Można go skonfigurować tak jak piszesz za pomocą bitów WGM13:0 w rejestrach TCCR1A i TCCR1B. Do Twoich potrzeb najlepszy byłby tryb CTC z wartością TOP (przy której zeruje się licznik) w rejestrze ICR1 (WGM13:0=1100 binarnie) lub jeden z trybów Fast PWM (WGM13:0=1110 binarnie). Wtedy rejestr OCR1A możesz wykorzystać do generowania przerwań gdzieś między wartością timera równą zero a wartością TOP zawartą w ICR1.
    Cytat:

    Oczywiście 128 nie jest wartością docelową tylko ma być zmienna, a czasami ma się zmieniać 2-3 razy w ciągu jednego zliczania timera, czyli wywołać przerwanie na 10, 40 i 90 cyklu powiedzmy.

    Pamiętaj jednak o tym, co napisałem w poprzednim poście odnośnie preskalera i rozmiaru kodu w procedurach obsługi przerwania, tym bardziej, że planujesz chyba wewnątrz obsługi przerwania TIMER1_COMPA modyfikować wartość OCR1A (jeśli dobrze zrozumiałem). Generalnie chodzi o to, żeby nowa wartość zapisywana do OCR1A wewnątrz obsługi przerwania TIMER1_COMPA była na tyle wysoka, żeby przed zakończeniem obsługi tego przerwania timer nie zdążył przekroczyć nowej wartości.
  • #8 9153422
    pawelvod
    Poziom 18  
    Podsumowując. Dziękuję za pomoc. Poprogramowałem i trochę słabo to wychodzi. Potrzebowałem 8 kanałów pwm do regulacji jasności świecenia 8 sekcji LED. Pierwszy program jaki zrobiłem o tradycyjne 256 pętli na jeden cały cykl PWM ze sprawdzeniem w każdym przebiegu czy któraś z sekcji ma zgasnąć. Działało to około 100Hz/ Natomiast wadą tego rozwiązania było to, że przerwanie angażowało procesor w 80-90% i program główny wlekł się strasznie. Sposób drugi czyli sprawdzenie ciut dłuższego warunku, ale tylko 8 razy w trakcie całego cyklu PWM (a przy kilku sekcjach świecących z tą samą jasnością nawet mniej) spowodowało że procesor wystartował i program główny śmiga. Niemniej następujące po sobie jasności gdzie OCR1A różni się tylko o 1 spowodowały ograniczenie prędkości do 80-100Hz (może przy procedurze ASM udało by się zejść do 150Hz). Jeśli komuś taka częstotliwość wystarcza to jest chyba słuszniejsza droga niż tradycyjne 256 sprawdzań (rząd wielkości mniejsze obciążenie procesora). Jako że całość ma oświetlać dość jasne akwarium(150W w LED) obawiam się że 80Hz może nadmiernie męczyć oczy i wolę dać co najmniej 1000Hz. Więc chyba zostaje tylko mój dawny pomysł z logiką:
    Cytat:
    Generator kwarcowy 10MHz, co da po podzieleniu przez 256 wartość 39kHz.
    - 1 licznik modulo 256 (8-bitowy), np. HC4520, aby uzyskać okres 256 razy większy od zegara,
    - Licznik programowany HC40103 (8-bitowy) na każdy "kanał", jest to licznik zliczający w dół z wejściami równoległymi i tylko jednym wyjściem, na którym pojawia się stan niski gdy licznik osiągnie "0".
    - Przerzutnik R-S lub D (1/2 HC74), który będzie ustawiany przez licznik HC40103 gdy ten zliczy ustaloną na jego wejsciach ilość impulsów i przy okazji zatrzyma cykl zliczania tego licznika, oraz będzie zerowany w momencie przepełnienia licznika modulo 256 (tego na HC4520). Na każdy "kanał" osobny przerzutnik.
    - Po przepełnieniu licznika modulo 256 należy przeładować licznik programowany i zezwolić na odliczanie przez niego impulsów z generatora, potrzebna jest 8-wejściowa bramka OR (może być na diodach) która na czas trwania stanu "0" licznika modulo 256 poda stan niski na wejście /SPE licznika 40103, a narastające zbocze zegara dokona przeładowania tego licznika.

    chyba że macie jakiś lepszy pomysł. Patrzyłem na dedykowane atmele PWM, ale ciężko to dostać, a tu co prawda parę elementów dojdzie na płytce, ale obciążenie procesora takim PWM jest żadne, częstotliwość jest w zasadzie dowolna, a cena rozwiązania niska.
  • #9 9154449
    LordBlick
    VIP Zasłużony dla elektroda
    Toż to wystarczy w jednym przerwaniu CTC zrobić wszystkie 8 kanałów... Ustawiamy częstotliwość podstawową CTC na 256*<częstotliwość odświeżania>. Inna sprawa, to czy na prawdę potrzebne jest aż 256 stopni jasności...
  • #10 9154461
    tmf
    VIP Zasłużony dla elektroda
    A najprościej stworzyć w RAMie tablice zawierające stan poszczególnych bitów IO w kolejnych cyklach. Zajmie to trochę miejsca, ale bez przesady. Dtedy 8 kanałów to tylko 2 instrukcje - odczyt z tablizy i zapis do portu IO. W tym trybie to wyrobi się nawet AVR taktowany z kwarca zegarkowego :)
  • #11 9168770
    pawelvod
    Poziom 18  
    co do light-i to właśnie taki sposób jest wolniejszyt gdyż w każdym cyklu z 256 sprawdzam 8 warunków. Czyli procesor sprawdza 265*8 warunków na jeden PWM. Przy drugim sposobie jest to poprostu 8 warunków na 256 cykli sumarycznie 256 razy mniej obciążony procesor (wychodzi 100 razy mniej bo warunki są ciut bardziej skomplikowane). Co do 256 poziomów to może i nie są potrzebne, ale oko ma ta właściwość, że zmiany oświeltlenia zauważa logarytmicznie a to w zakresie 0-20 za mało, a w zakresie 150-255 wystarczą 3 poziomy jasności więc na dobrą sprawę przydało by się 1000 kroków głównie dla zwiększenia dokładności regulacji w niskich zakresach. Co do mapy to rzeczywiście dobry pomysł tylko trochę kosztowny jeśli chodzi o RAM. Od razu można by nanosić poprawkę "ulogarytmowującą" jasności 0-100 an 256 kroków. Spróbuję choć chyba obciążenie procesora będzie podobne bo to 256 wywołań zamiast 8 ale częstotliwość max da się osiągnąć większą. Tylko ten C odkłada na stos co popadnie i sporo to zajmuje. Trzeba będzie sporo w ASM pooptymalizować. Coraz częściej myślę o jakimś sterowniku scalonym do tych diód. Słyszeliście o jakimś dostępnym układnie do tego celu który dało by się łatwo oprogramować (oczywiście poza atmega90:) )?
REKLAMA