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

sterowanie diody RGB przez WS2811

fasset 25 Paź 2013 12:18 7899 68
  • #1 12879002
    fasset
    Poziom 13  
    Witam.
    Chcę uzyskać regulowane wypełnienie PWM na wyjściu OC1A (PB1), a także ten sam zanegowany sygnał na PB0. Kilkakrotnie czytałem dokumentację i nadal nie wiem co robie źle. Na wyjściu PB1 otrzymuję cały czas sygnał PWM o wypełnieniu 50%, a na PB0 nie otrzymuję nic.
    Z tego co zrozumiałem (możliwe, że błędnie) rejestr OCR1A powinien regulować wypełnienie. Jedynie co się zgadza to regulacja częstotliwości poprzez rejestr OCR1C.
    Proszę o sprawdzenie i wskazanie błędów:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #2 12879030
    Tomasz Gumny
    Poziom 28  
    Ustaw PWM1A w TCCR1A.
    Po co ustawiasz PWM1X?
  • #3 12879413
    fasset
    Poziom 13  
    Dzięki - działa. Źródłem pomyłki było moje przeoczenie w dokumentacji różnicy między PWM1X, a PWM1x. A ustawiam PWM1X w celu:
    Cytat:
    When this bit is set (one), the PWM Inversion Mode is selected and the Dead Time Generator
    outputs, OC1x and OC1x are inverted.


    Kolejny problemem jest to, że wypełnienie można regulować jedynie od wartości 0 do 100 (w zależności od wartości w rejestrze OCR1C). Czy istnieje możliwość, aby w trybie PWM wartość w tym rejestrze regulowała jedynie częstotliwość, a wypełnienie w OCR1A można było zmieniać w wartościach 0-255 jak dla 8-bitowego trybu?
  • #4 12879459
    Tomasz Gumny
    Poziom 28  
    Jeśli do OCR1C wpiszesz 0 (albo 255 - nie pamiętam), to zapisując do OCR1A wartości 0..255 uzyskasz wypełnienie od prawie 0 do 255/256. OCR1C ustawia okres, a OCR1A/B/D wypełnienie. Innymi słowy, żeby PWM działało na OC1A/!OC1A, wartość OCR1A musi zawierać się między 0 a OCR1C.
  • #5 12879498
    fasset
    Poziom 13  
    Tak, tak rozumiem to. Z tym, że częstotliwość PWM w trybie Fast PWM zmienia się wraz z wartością w rejestrze OCR1C zgodnie ze wzorem:
    fPWM=fclkT1/N
    gdzie N to wartość w rejestrze OCR1C.
    Zastanawiam się nad tym czy da się regulować wypełnienie w trybie Fast PWM bez zmiany częstotliwości.
  • #6 12879688
    Tomasz Gumny
    Poziom 28  
    fasset napisał:
    Zastanawiam się nad tym czy da się regulować wypełnienie w trybie Fast PWM bez zmiany częstotliwości.
    Oczywiście - wpisując odpowiednią wartość do OCR1A. Częstotliwość PWM się nie zmieni, dopóki nie zmienisz zawartości OCR1C.
    Albo inaczej: potraktuj OCR1C jako okres PWM w taktach zegara (ustawianego CSxx), a OCR1A jako czas trwania stanu wysokiego w PWM (dla OC1A) w takich samych taktach.
  • #7 12879933
    fasset
    Poziom 13  
    Tak z tym, że regulacja wypełnienia w OCR1A będzie w zakresie <0; OCR1C>
    Chodziło o to, że regulacja miała być od <0; 255> przy stałej wartości OCR1C np = 100. Ale to już nieważne w sumie tak też może być :)
  • #8 12879985
    GSM
    Poziom 25  
    fasset napisał:
    #define F_CPU 1000000

    Popraw przy okazji tego kwiatka.
    fasset napisał:
    Chodziło o to, że regulacja miała być od <0; 255> przy stałej wartości OCR1C np = 100.

    Nie można tak zrobić. Wartość TOP timer-a (w tym wypadku OCR1C) determinuje rozdzielczość PWM-a. Wyobraź sobie, że chcesz ustawić pokrętło które ma 100 dyskretnych pozycji z dokładnością do 1/256 pełnego obrotu - nie da się. Możesz co najwyżej skalować odpowiednio wartość z zakresu 0-255 do zakresu 0-OCR1C, ale rozdzielczości tym oczywiście nie zwiększysz.

    Pozdrawiam,
    GSM
  • #9 12880567
    fasset
    Poziom 13  
    Poniższy kod powinien generować "sinusa" przy pomocy SPWM:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Niestety wypełnienie jest stałe tak jakby do rejestru OCR1A wrzucana była tylko najwyższa wartość z tablicy. W czym tkwi błąd?
  • #10 12880632
    Tomasz Gumny
    Poziom 28  
    Zmiana wypełnienia powinna odbywać się na końcu okresu PWM, gdy TCNT1 osiągnie TOP, czyli w przerwaniu OVF1.
  • #11 12880952
    fasset
    Poziom 13  
    Niestety nie pomaga
  • #12 12881082
    Tomasz Gumny
    Poziom 28  
    A co to: "|(1<<FOC1A)"?
    Nie włączaj przerwań, których obsługi nie zdefiniowałeś.
  • #13 12881179
    fasset
    Poziom 13  
    Niestety dalej nic - dziwne zwłaszcza, że podobny kod na AT90PWM działa bez szwanku.
  • #14 12881246
    Tomasz Gumny
    Poziom 28  
    To jeszcze zmień tablicę na char i pokaż program.
    Czy ustawianie PWM działa poprawnie?
    Czy program w ogóle wchodzi w przerwanie?
  • #15 12881288
    fasset
    Poziom 13  
    Ten kod działa na AT90PWM:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ten nie działa (na Attiny861):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jak "ręcznie" wpisuje wartość do rejestru OCR1A to PWM działa.
  • Pomocny post
    #16 12881325
    Tomasz Gumny
    Poziom 28  
    Sprawdź:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #17 12881375
    fasset
    Poziom 13  
    Działa, dzięki.
  • #18 12881426
    Tomasz Gumny
    Poziom 28  
    Dla 37-elementowej tablicy ten warunek:
    if(k==36) { k=0; }
    powinien chyba wyglądać tak:
    if(k==37) { k=0; }
  • #19 12881495
    cavendish
    Poziom 17  
    Najlepiej inkrementację otoczyć operatorem modulo - wtedy trudno się pomylić:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #20 12881514
    Tomasz Gumny
    Poziom 28  
    Niby tak, ale chętnie sprawdziłbym przekład na asembler obu wersji.
    Mamy tutaj 512 taktów zegara na obsługę przerwania. Jak się doliczy wszystkie operacje na stosie, zaindeksowanie tablicy (szybciej byłoby na wskaźnikach), to zapasu wielkiego nie będzie, zwłaszcza gdyby komuś przyszło do głowy skrócić okres PWM np. do 100 i ustawić preskaler timera na CK zamiast CK/2.
  • #21 12881696
    GSM
    Poziom 25  
    cavendish napisał:
    Najlepiej inkrementację otoczyć operatorem modulo - wtedy trudno się pomylić:

    Może i trudno się pomylić ale z dość istotnych przyczyn (które poruszył Tomasz Gumny) niezbyt sensowne rozwiązanie.
    Jeśli to nie zaburza jakoś wymyślonego przez autora sposobu w jaki ma działać program, to dobrze by było tą tablicę skrócić do 32 albo rozszerzyć do 64 bajtów długości. Wtedy modulo zastępujemy AND-em bitowym z 0x1F albo 0x3F.
    Jeśli czujemy się na tym polu bezpiecznie (a raczej co ważniejsze wiemy co robimy) można skorzystać z ISR_NAKED i samemu wstawkę napisać.

    Pozdrawiam,
    GSM
  • #22 12881852
    BlueDraco
    Specjalista - Mikrokontrolery
    512 cykli na tak proste przerwanie - to całkiem sporo, o ile NIE użyje się operatora modulo. Nie ma sensu nic tam optymalizować. Realnie obsługa zmieści się zapewne w kilkudziesięciu cyklach. Nie kombinujcie... ;)
  • #23 12881883
    excray
    Poziom 41  
    Dodam jeszcze aby dla takich warunków nie robić tak: if(k==37) k=0; tylko tak: if(k>36) k=0; Zwiększa idioto-odporność w połączeniu z uint.
  • #24 12881990
    BlueDraco
    Specjalista - Mikrokontrolery
    A tak, żeby nie było błędów, to:

    if (k >= sizeof(pwm1) / sizeof(pwm1[0]))
    k = 0;

    ... i jesteśmy odporni na wszelkie głupoty, bo kompilator wstawi to, co trzeba.
  • #25 12882015
    Tomasz Gumny
    Poziom 28  
    Wróćmy do tego, że szybsze są działania na wskaźnikach i najlepiej, gdyby tu w ogóle nie było indeksowania tablicy, czyli każdorazowego mnożenia indeksu (jeśli sizeof>1), dodawania go do bazy i pobierania zaadresowanego elementu. :)
  • #26 12882099
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie ma mnożenia, najwyżej przesuwanie w lewo o 1 - jedna instrukcja, jeden cykl. Oczywiście jeśli dane w tablicy mieszczą się na jednym bajcie, to powinny mieć typ bajtowy, a nie 16-bitowy.
  • #27 12911010
    fasset
    Poziom 13  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Zgodnie z obliczeniami:
    fpwm = 32MHz/(8*200)=20kHz.
    gdzie - 8 preskaler, 200 - wartość TOP - czyli rejestr OCR1C.
    Tutaj jest w porządku.
    Problem jest w częstotliwością na PA0. Zgodnie z założeniami powinna wynosić 100 Hz:
    20kHz/(2*100) = 100 [Hz]
    2*100 ponieważ tablica jest 100 elementowa, a więc k=0 raz na 200 impulsów prostokątnych.
    Dlaczego PWM na porcie PA0 ma częstotliwość 80 Hz?
  • #28 12911242
    GSM
    Poziom 25  
    PLLCSR |= (1<<PLOCK);

    Nawiasem mówiąc, ten bit jest tylko do odczytu.

    Pozdrawiam,
    GSM
  • #29 12911284
    Tomasz Gumny
    Poziom 28  
    Jakoś nie mam zaufania do konstrukcji sizeof(array) lub sizeof(string), bo gdzieś mi to zwracało rozmiar maksymalny zamiast rzeczywistego. Spróbuj wpisać tam wartość na sztywno.
  • #30 12911407
    fasset
    Poziom 13  
    Niestety nic to nie dało. Jest to o tyle dziwne, że rozmiar tablicy zmienia tą częstotliwość PWM (na PA0), ale OCR1C już nie - jakby nie miał wpływu (poza tą na OC1A).
REKLAMA