Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[at2313][Bascom] Programowe rozwiązanie PWM

08 Mar 2010 22:03 3610 16
  • Poziom 10  
    Witam!
    Piszę sterownik rgb na 2313.
    Jak wiadomo tinny ma 4 wyjścia PWM.
    W projekcie chciałbym sterować niezależnie 3 diodami.
    Na czym dokładnie polega programowe rozwiązanie PWM?
    Rozumiem, że w PWM chodzi o to, że (załóżmy 8 bitową rozdzielczość) na każde 256 cyklów zegara w x cyklach zegara będzie ustawiona 1 a później nie?
    Czyli musiałbym napisać analogiczne instrukcje opóźnień, tak?
    Z góry dziękuję za odpowiedź.
    Pozdrawiam!
  • Poziom 19  
    To czemu nie użyjesz sprzętowego PWM?

    Programowe to chyba najposciej np w taki sposób:

    Code:
     
    
    do
     PORTx.y = 1
     waitus A
     PORTx.y = 0
     waitus &hFF - A 
    loop


    Gdzie zmienna A jest typu byte (dla 128 masz wypełnienie ok 50%)
  • Poziom 10  
    To jest jakaś koncepcja.
    Czytałem, że w assemblerze można odmierzyć dokładnie czas trwania jednego cylku zegara i wstawić kod do Bascoma, powinno być dokłądniej.

    grysek napisał:
    To czemu nie użyjesz sprzętowego PWM?


    bo nie mógłbym wysterować 3 diód niezależnie.
  • Poziom 19  
    Tylko pytanie po co robić dokładniej skoro i tak jak to ma być tylko do diody to nawet nie zauważysz różnicy.

    A mi sie wydaje że jednak można każdy sprzętowy kanał PWM sterować osobno :P

    Zwłaszcza że kanały masz 4 a diody 3. A wyobraź sobie że jak bedziesz chciał sobie dorobić dodatkową funkcję do programu to gdzie wtedy znajdziesz dla niej czas skoro procesor cały czas będzie zajęty programowym PWM?
  • Poziom 10  
    Przepraszam, zapomniałem dodać, że mają to być diody RGB, dlatego chcę zastosować pwm programowe.

    Dodano po 3 [minuty]:

    szaryjelen napisał:
    Witam!
    Piszę sterownik rgb na 2313.
    Jak wiadomo tinny ma 4 wyjścia PWM.
    W projekcie chciałbym sterować niezależnie 3 diodami.
    Pozdrawiam!

    Dla ścisłości, 3 diody RGB, nie każdy kolor osobno.
    Potrzebuję 9 kanałów.
  • Poziom 21  
    Dla programowego PWM funkcja będzie skomplikowana, ponieważ musisz sterować wszystkimi potrzebnymi wyjściami jednocześnie, rozbicie na poszczególne funkcje dla pinów i przetwarzanie cykliczne raczej nie wchodzi w grę, ponieważ nieobsługiwane w danym momencie wyjścia zepsują swój współczynnik wypełnienia. Więc chyba o jakimkolwiek wolnym czasie procesora można rzeczywiście zapomnieć. Może włączyć timer a w przerwaniu rozbudowana funkcja warunkowa, zmieniająca stany na potrzebnych pinach. Wtedy 9 przepełnień licznika będzie okresem przebiegu na pinach. Współczynnik wypełnienia możesz regulować wtedy od 0 do 1 skokowo co 1/9 (0,1/9,2/9,...,8/9,1). A jak weźmiesz sobie więcej przepełnień za okres to możesz współczynnik regulować w większym zakresie.

    edit:

    W pierwszym przerwaniu wszystkie piny pwm, które flagami globalnymi mają współczynnik wypełnienia >0 ustawiane na 1.

    W przerwaniach 2-9 zerowane będą odpowiednie piny zgodnie z zadeklarowanym licznikiem przepełnień i twoimi warunkami wpisanymi do flag.

    I tak w koło. Współczynnik wypełnienia sterowany byłby danymi wpisywanymi do flag. Jedna flaga mogła by objąć dwa piny bo 9 mieści się w 4-ech bitach.

    PS. Nie znam bascoma

    [at2313][Bascom] Programowe rozwiązanie PWM

    Tak wyglądają przebiegi z takiego PWM-a. Od góry 0,8 0,5 0,3 0,2 0 Jak jesteś zainteresowany to mogę wrzucić jutro kod, ale w C. Całkiem to niezłe, nawet symulator mi nie krzyczał że "expensive CPU load" :D Okres jednego cyklu jest stały i w tym przypadku wynosi ok 20ms czyli częstotliwość to 50Hz. Zaprzęgnięty timer0 po prescalerze /64, procesor jedzie na 8MHz czyli timer taktowany 125kHz, przerwania generowane są z częstotliwością 488Hz, co przy podziale na 9 przerwań na cykl daje ok 55Hz.
    Oczywiście można rozkręcić procka na 16MHz, lub zmniejszyć preskaler, jeśli widoczne byłoby migotanie(to drugie kosztem mocy obliczeniowej oczwiście).

    Nie wiem dokładnie jak działa takie sprzętowe pwm i czy można w nim płynnie zmieniać współczynnik wypełnienia, tak tutaj nie masz takiej możliwości. Ale myślę że taki prymitywny pwm wystarczy do sterowania diodami RGB.
  • Pomocny post
    Poziom 29  
    Code:

    Incr Reference                                             

    If Reference < R Then : Set Portb.2 : Else : Reset Portb.2 : End If       'red

    If Reference < G Then : Set Portb.3 : Else : Reset Portb.3 : End If       'green

    If Reference < B Then : Set Portb.4 : Else : Reset Portb.4 : End If       'blue


    Całość wywoływana przez przerwanie - przepełnienie licznika. R G i B to zmienne do których w dowolnym czasie wpisujesz własne wartości. W tym przypadku PWM będzie miało 256 kroków od 0 do 100% (Reference się po prostu "przekręci" po 255), możesz oczywiście to zmniejszyć dodając na początku przykładowo If Reference = 121 Then Reference = 0 wtedy uzyskasz rozdzielczość 120 i tak dalej. Kanałów też możesz sobie dodać ile chcesz, ale dopilnuj żeby kod zdążył się wykonać zanim przyjdzie kolejne przerwanie :)
  • Poziom 10  
    Tylko jest mały problem...
    Primo, niedawno dopiero zacząłem się uczyć Bascoma a o C nie mam zielonego pojęcia.
    Secundo, nie chcę gotowych kodów. Byłem na stonie mirley.firley.org, kod widziałem, nie zrozumiałem dlatego kombinuje inaczej.
    Nie wiem jak "ugryźć" te przerwania, o co tam chodzi?
  • Poziom 26  
    Może spróbuj multipleksować te diody, tak jak wyświetlacze LED.
  • Poziom 21  
    Przerwanie od timerów to zbiór instrukcji, które zostają wykonane w przypadku przepełnienia licznika, asynchronicznie, czyli niezależnie od wykonywanego w danym momencie kodu (chyba ze jest to inne przerwanie). Nie wiem jak wygląda obsługa przerwań w bascomie, ale mogę wytłumaczyć o co "biega". A więc 8-bitowy licznik ulega przepełnieniu co 256 cykli zegara go taktującego. Licznik zazwyczaj nie taktuje się bezpośrednio zegarem CPU lecz poddaje się go podziałowi. W moim przypadku użyłem podziału przez 64 czyli 1 takt zegara licznika to 64 takty zegara CPU. Czyli 64 takty zegara CPU to zwiększenie wartości licznika o 1. Przepełnienie nastąpi po 256-ciu cyklach zegara taktującego licznik czyli po 64*256=16384 taktach CPU. Dla zegara 8Mhz jedno przerwanie będzie występować co ok 2ms. Przy zwiększeniu taktowania do 16 MHz przerwania będą występować co 1ms. Teoretycznie mało bo częstotliwość przebiegu o takim okresie to aż 1kHz czyli do pwm wystarczająco. Ale to jest tylko jedna składowa okresu całego pwm, ponieważ potrzeba więcej momentów możliwości zmiany stanów pinów pwm, na okres przebiegu modulowanego składa się więcej przerwań. W moim przypadku jest to 10 przerwań co daje 10 możliwych współczynników wypełnienia i częstotliwość ok 50Hz (2ms*10=20ms >>50Hz).

    W każdym przerwaniu jest inkrementowana zmienna licznik przerwań, a po osiągnięciu odpowiedniej wartości zerowana. Wartość przy której zostanie wyzerowana będzie określał okres PWM-a i będzie on iloczynem czasu od jednego do drugiego przerwania, i ilością tych przerwań (wartość dla której licznik przerwań się zeruje). Ilość przerwań również składa się na "rozdzielczość" takiego rozwiązania, ponieważ okres jest podzielony na tyle właśnie części i tylko w przerwaniach można zmieniać stany tych portów. W każdym przerwaniu jest również sprawdzany warunek dla każdego wybranego pinu pwm, tzn czy flaga ustawień współczynnika wypełnienia jest równa licznikowi przerwań, i w przypadku prawdy pin jest zerowany. Dodatkowo występuje warunek, który ustawia wszystkie piny o niezerowym współczynniku na 1 w przerwaniu 0(licznik przerwań==0).

    W efekcie otrzymujesz przebieg, w którym w chwili t=0 wszystkie linie o niezerowym współczynniku wypełnienia wchodzą na logiczne 1 i zerowane są w odpowiednim przerwaniu składowym (którymś z kolei), zgodnie ze swoją flagą sterującą. Procesor wykorzystany jest wtedy tylko przez niewielką ilość czasu, w jakiej wykonywane są przerwania. a pomiędzy nimi masz do wykonania ok 16384 instrukcji :D
  • Poziom 29  
    W przypadku tego fragmentu który podałem wyżej... kod pracował w Attiny13 i sterował lampką RGB. Zegar 4,8MHz, nie dzielony, napędzał ośmiobitowy timer0 który w takim przypadku potrzebował 256 taktów aby się przepełnić. Za każdym przepełnieniem, czyli przeleceniem przez 0, wywoływał ten krótki podprogram który gasił lub zapalał porty. Po za tym program miał dużo czasu na takie głupoty jak generowanie kolorów, czy wykrycie zaniku napięcia zasilania (tak była sterowana lampka).

    Tak jeszcze żeby rzucić troszkę światła na to co się wykonuje w przerwaniu... Przypuśćmy że chcemy wypełnienie na poziomie 33%, więc przy 256 krokach będzie to wartość około 85/256... zmienna Reference jest ciągle zwiększana do 255 a następnie zerowana... przez pierwsze 85 kroków reference będzie mniejsza od naszej wartości 85, a przez kolejne 171 kroków będzie większa od naszej wartości. Tak więc przez 33% trwania całego cyklu wyjście będzie włączone a przez pozostałe 67% będzie wyłączone. To samo będzie jeśli wpiszemy wartość 1 - tylko przez 1/256 czasu wyjście będzie włączone i takie też otrzymamy wypełnienie. Chyba nie potrafię tego inaczej wyjaśnić :)
    Czyli dokładnie tak jak napisałeś
    Cytat:
    Rozumiem, że w PWM chodzi o to, że (załóżmy 8 bitową rozdzielczość) na każde 256 cyklów zegara w x cyklach zegara będzie ustawiona 1 a później nie?
  • Pomocny post
    Poziom 21  
    Warto też zanegować taki przebieg albo chociaż celem osiągnięcia dużego wypełnienia sterować pwm na małe wypełnienie i wpiąć diody katodami do portów bo jak wiadomo większą wydajność prądową układy takie jak avr-ki mają przy logicznym 0.
  • Poziom 10  
    Yeah! Dzięki chłopaki ;-) Chyba już przyswoiłem : D

    Teraz kolejne pytanie się urodziło.
    Jak sterować szybkością zmian, skoro licznik przerwań się nie zmienia?
  • Poziom 29  
    omicronNs napisał:
    ... jak wiadomo większą wydajność prądową układy takie jak avr-ki mają przy logicznym 0.
    Od kiedy? Jeszcze wczoraj miały jednakową.
  • Poziom 10  
    szaryjelen napisał:

    Teraz kolejne pytanie się urodziło.
    Jak sterować szybkością zmian, skoro licznik przerwań się nie zmienia?


    Zastosować zmienną która określa czas który mikrokontroler "czeka" po zmianie zmiennych kolorów?

    np.
    Code:

    incr red
    decr blue
    incr green
    waitms S


    Czy jest może jakieś bardziej optymalne rozwiązanie?