Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

bascom - sterowanie led pwm

BIGJack 06 Nov 2012 10:35 4827 18
Optex
  • #1
    BIGJack
    Level 16  
    Mam problem ze sterowaniem PWM w moim projekcie.
    Załączam fragment kodu który ma powoli rozjaśniać i ściemniac żarówkę
    led jednak rozjasnienie działa zgodnie z założeniem czyli powoli i płynnie a gaszenie w mgnieniu oka tzn. bardzo szybko.
    Jeżeli te procedurki połącze w jedna to prawidłowo rozjasnia i gasi?
    Jaka jest przyczyna?

    Code: vbnet
    Log in, to see the code
    [/code]
  • Optex
  • #2
    Mundi1970
    Level 24  
    Podprogramy wywołuje się instrukcją Gosub, a nie Goto.
  • Optex
  • #3
    BIGJack
    Level 16  
    Kolego nowynom Twój poprawiony kod również nie zawiera etykiet :) aczkolwiek wygląda można powiedzieć wzorowo :)

    Quote:
    A tak nawiasem, czy nie łaska sprawdzić na symulatorze ?

    Napisałem tego posta w akcie desperacji po lekturze helpa, innych postów i
    wygooglowaniu wszystkiego co możliwe. Mam podpięty układ pod kompa i przelewam moje wypociny na bieżąco do procka.

    Quote:
    O toto Kolega nie wie, co to są ETYKIETY

    Oczywiście że wiem aczkolwiek nie jestem biegły w bascomie i robiąc mój mały bałagan w prostym kodzie etykiety mi tylko przeszkadzają. Oczywiście jak wstawiam fragment kodu na elektrodę to byłyby wskazane aczkolwiek przy tych kilku linijkach chyba się obędziemy bez nich :)

    Jest to fragment kodu celowo zawężony do minimum niezbędnego do analizy moich błędów w pisaniu programu. Celowo zrobiłem nieskończoną pętlę.

    Całość ma sterować iluminacją dekoracyjną i oświetleniem miejsca roboczego w kuchni. Czujnik podczerwieni rozjaśnia w miarę szybko i odlicza czas do wyłączenia jednak jeżeli podczas odliczania wykryje ruch to zeruje czas i odlicza od początku po czym płynnie powoli wygasza światło. Oto kod który napisałem do tej pory.
    Code: vbnet
    Log in, to see the code


    ps pomijając fakt że zastosowałem goto zamiast gosub dlaczego jedna procedura jest wykonywana według oczekiwań a druga nie?
    kolego nowynom Twój kod działa ładnie w symulatorze ale w moim układzie brak reakcji. hmmm
  • #4
    Anonymous
    Anonymous  
  • #5
    BIGJack
    Level 16  
    Saabotaz ;
    Quote:
    1) Robisz "Goto Rozjasnij" i "Goto Sciemnij", a potem próbujesz wrócić Returnem. Wywalasz program.

    Wcześniej przed pętlą do-loop dla sprawdzenia ustawiłem aby dioda migała i faktycznie co rozjaśnienie migała - wniosek, masz rację program się wywalał.

    Quote:
    2) Czemu ci działa Rozjaśnienie, a Ściemnianie nie? No bo skok do rozjasnienia przez Goto, program rozjaśni jak należy, powrót returnem i wywala się program. Cud że po tym ściemnianie jeszcze ci działa

    Racja.

    Quote:
    3) Już ci poradzili że problem jest z GOTO, a powinieneś wstawić GOSUB, ty jednak znów wklejasz program z GOTO.

    Nie jestem uparty i zrozumiałem mój błąd, wstawiłem po prostu cały kod a nie tylko jego zmodyfikowany fragment. Oczywiście zmienię goto na gosub.

    nowynom, zwłoka to zadeklarowana pozostałość po wcześniejszym podejściu do tego projektu :-) zastąpiona została zmienną czas. Natomiast co do 15 to miał być czas świecenia w tymczasowy czas świecenia led-a. Pętla zaś miała być spowolniona poleceniem wait 1 . Czy jeżeli nie zależy mi na precyzyjnym odmierzaniu czasu muszę opóźnienie robić na timerze?
  • Helpful post
    #6
    Anonymous
    Anonymous  
  • #7
    gustawm2
    Level 11  
    Witam,

    ostatnimi czasy potrzebowałem wykonać projekcik do sterowania jasnością diody.
    Przeczesałem elektrodę, kawałek polskiego internetu i książkę do Bascoma.

    Układ, który wykonałem działa poprawnie, ale gorzej jest z softem.
    Niestety nie bardzo wiem gdzie szukać rozwiązania problemu.

    Attiny2113 działa na wewnętrznym oscylatorze.
    Oto mój kod.

    Code: vbnet
    Log in, to see the code


    Jeżeli w ciało ifa if Pind.0/1 = 0 wpiszę kod
    
    For A = 0 To 250 Step 10
        Pwm1a = A
        Waitms 5
    Next I
    


    to ten fragment działa poprawnie.
    W zasadzie zależy mi na zmienianiu Pwm1a w granicach 0 - 250 po naciśnięciu jednego lub drugiego przycisku.

    Wiem, że kod można znacznie uprościć, ale na razie to jestem zamotany najważniejszą na tę chwilę funkcją - zmianą pwm.

    Nie wiem czemu po odpaleniu programu działa tylko jedno naciśnięcie guzika w danym kierunku, drugie naciśnięcie nie powoduje wejścia w ifa - zmianę stanu pb0 i pwm.

    Czy problemem jest typ zadeklarowanej zmiennej A?
  • #8
    Anonymous
    Anonymous  
  • #9
    gustawm2
    Level 11  
    Saabotaz wrote:
    Wszystko działa dobrze, dokładnie tak jak napisałeś :-)

    Syfy w programie:

    1) A jako integer, powinno być jako byte (pwm 8 bit) lub word (16 bit). Tutaj to nie powoduje błędu ale dobrze by było nie używać zmiennych mogących być ujemnymi, ponieważ PWM może mieć wartości tylko 0 lub dodatnie.

    2) Enable Timer 1 - nie jest potrzebne bo nie używasz przerwań, raczej przydałoby się Start Timer 1 ale Bascom automatycznie startuje Timer podczas configu

    3) If A < 250, potem robisz A+10 co daje wartość 260 i przekręcenie się wartości. No bo przecież 8 bit nie może mieć więcej niż 255, a zobacz że ty wpisujesz tam max 260. Popraw na If A < 241 (czemu 241, a nie 240? Bo dając 240 uzyskasz max pwm 240, dając 241 max będzie 250, pomyśl czemu)

    4) If A > 0, potem robisz A-10 co ci daje -10 czyli przekręcenie się wartości w pwm (bo on może być tylko 0 lub dodatni). Zmień na If A > 9 (pomyśl czemu >10 nie zadziała zbyt dobrze)

    5) Pamiętaj że program działa błyskawicznie, w ułamku sekundy od przyciśnięcia przycisku, jego if wykona się z pewnością kilka tysięcy razy na sekundę. Dlatego przed każdym end if wstaw np. waitms 200


    Dzięki za podpowiedź.
    Okazało się, że największym problemem jest pkt 5 - niestety zawodowym programistą uC nie zostanę, wolę skrypczenie w mniej wysublimowanych językach.

    Ad. 3 i 4) Jeżeli chodzi o warunki z A to było to pisane na kolanie i rzeczywiście przekręcały się liczniki, ale w pewnym zakresie nie miało to znaczenia - dzięki za wytknięcie

    Ad. 1 - Rzeczywiście Integer tu lekko nie pasuje, ale w tym przypadku nie ma to większego znaczenia gdyż w programie nie ma innych funkcji, które mogłyby operować na tej zmiennej.

    Przerobiłem fragment książki o Bascomie, a wraz z tym program ciut się zmienił,
    w zasadzie robi prawie to samo co wcześniej.

    Generalnie kod zrobił się czytelniejszy i przy testach z diodą i buzzerem wypadł pomyślnie.
    Teraz pozostaje mi zgłębić (czyt. zrozumieć) do końca temat pwm i poprawić program tak, aby zadziałał w "środowisku produkcyjnym".

    Oto obecny kod:

    Code: vbnet
    Log in, to see the code
  • #10
    Anonymous
    Anonymous  
  • #11
    emarcus
    Level 38  
    Saabotaz wrote:
    Wszystko działa dobrze, dokładnie tak jak napisałeś :-)

    Syfy w programie:

    3) If A < 250, potem robisz A+10 co daje wartość 260 i przekręcenie się wartości. No bo przecież 8 bit nie może mieć więcej niż 255, a zobacz że ty wpisujesz tam max 260. Popraw na If A < 241 (czemu 241, a nie 240? Bo dając 240 uzyskasz max pwm 240, dając 241 max będzie 250, pomyśl czemu)


    Tu akurat w wyjaśnieniu wkradła sie pewna nieścisłośc.
    Po przekroczeniu wartości A>255 lub 260 nie nastąpi "przekręcenie się wartości" [?]
    Zarówno zmienna A przyjmie taką wartośc (integer przyjmie max 32767) jak też rejestr Pwm1a bez problemu taką wartośc zaakceptuje bo jest to rejestr 16 bitowy (OCR1A). Problemem w tym wypadku jest wyjście poza zakres kontroli 'pola' 8-bitowych wartości.
    Co nie zmienia faktu że żródłem problemu jest autor wymiarując pośrednią zmienną A jako integer, co prowadzi do wyraźniejszego konfliktu na drugim końcu regulacji (przy decrementacji wartości Pwm1a).
    Jeżeli pozostawimy zmienną "A as word" wtedy należloby przed wpisem do Pwm1a wstawic ograniczenia;
    od góry(przy incrementacji):
    ............
    if A >= 255 then
    A = 255

    oraz od dołu (przy decremantacji):
    ............
    if A >255 then
    A=0

    e marcus
  • #12
    gustawm2
    Level 11  
    Dzięki wielkie za sugestie.
    Program poprawiłem, wszystko działa tak jak chcę.

    Zabrałem się za kolejną rzecz i utknąłem na timerach i książce do bascoma.

    Generalnie to mam problem z PWM - potrzebuję wygenerować impulsy o zadanej długości w taktowaniu pomiędzy x Hz

    Na razie siedzę i próbuję wymyślić jak to zrobić.

    Dodano po 3 [godziny] 4 [minuty]:

    Poczytałem o PWM i nie wiem czy do końca dobrze rozumiem.

    Zakładając, że poterzbuję wygenerować impuls o długości od 1000us do 2000us z częstotliwością dowolną pomiędzy 50Hz a 400Hz to... tak sobie policzyłem
    Przyjąłem częstotliwość 245Hz
    1000000/8/510 =~ 245Hz
    Dalej:
    1sek = 1000000us
    1000000us/245Hz =~ 4018us na okres, w którym będziemy wypełniać PWM

    Jeżeli okres wynosi 4018us, do wygenerowania są impulsy o długości od 1000us do 2000us:
    DC1 = (1000us/4018us)* 100% = 24,88%
    DC2 = (2000us/4018us)* 100% = 49,77%

    zakładając, że nasz rejestr pwm jest 8 bitowy to 25% z 256 = 64 , a 50% = 128
    więc powinienem tak sterować układem, aby zapisując do rejestru pwm1a poruszać się pomiędzy tymi wartościami.

    Proszę o sprostowanie jeżeli coś pominąłem lub coś pokiełbasiłem :-)
  • #13
    emarcus
    Level 38  
    gustawm2 wrote:


    Zabrałem się za kolejną rzecz i utknąłem na timerach i książce do bascoma.

    Generalnie to mam problem z PWM - potrzebuję wygenerować impulsy o zadanej długości w taktowaniu pomiędzy x Hz


    Zakładając, że poterzbuję wygenerować impuls o długości od 1000us do 2000us z częstotliwością dowolną pomiędzy 50Hz a 400Hz to... tak sobie policzyłem
    Przyjąłem częstotliwość 245Hz
    1000000/8/510 =~ 245Hz
    Dalej:
    1sek = 1000000us
    1000000us/245Hz =~ 4018us na okres, w którym będziemy wypełniać PWM

    Jeżeli okres wynosi 4018us, do wygenerowania są impulsy o długości od 1000us do 2000us:
    DC1 = (1000us/4018us)* 100% = 24,88%
    DC2 = (2000us/4018us)* 100% = 49,77%

    zakładając, że nasz rejestr pwm jest 8 bitowy to 25% z 256 = 64 , a 50% = 128
    więc powinienem tak sterować układem, aby zapisując do rejestru pwm1a poruszać się pomiędzy tymi wartościami.

    Proszę o sprostowanie jeżeli coś pominąłem lub coś pokiełbasiłem :-)


    Nie najlepiej to kombinujesz.
    Jeżeli pracujesz nad Att2313 to temat Timera1i jego trybów pracy a w szczególności PWM najłatwiej poznasz studiując Datasheet rozdział:

    16-bit Timer/Counter1>Modes of Operation
    Po zapopznaniu się (z grubsza) z treścią wszystkich trybów pracy timera, zatrzymaj się na dłużej na tabeli 46 str. 110, w której znajdziesz wszystkie możliwe tryby (Mode) pracy timera1 (od 0 do 15).
    Zauważ, że za każdy tryb pracy odpowiedzialne są ustawienia tylko czterech bitów (wymienione w kolejnych czterech kolummach)_WGM1 3:0 - niefortunnie są one rozrzucone w różnych rejestrach Timera1- do tego dojdziesz później jezeli jeszcze nie połapałeś.
    Popatrz na kolumnę z nagłówkiem "TOP"; jeżeli w tej kolumnie występuje konkretna wartośc (w HEX-notation), - to ten tryb pracy ma już określoną częstotliwośc pracy i wpisy do rejestru pwm1a mogą kontrolowac tylko wypełnienie.
    Jeżeli zakładasz 8-bit PWM to jak doszedłeś do ustalenia częstotliwości pracy 245Hz ?
    Popatrz na tabelę poniżęj;

    bascom - sterowanie led pwm

    Owszem, możesz użyc pwm1a do kontrolo częstotliwości w innych trybach ale wtedy nie masz kontroli nad regulacją wpełnienia, które pozostanie na poziomie 50%.
    Nie znaczy to że nie ma możlowości kontroli obydwóch parametrów; oczywiście jest taka możliwośc ale to wymaga nieco innego rozważenia niż przjąłeś w swoich obliczeniach powyżej.
    Timer1 ma dwa kanały PWM; A i B na których możesz generowac dwa rózne sygnały PWM o tejsamej częstotliwosci określonej przez prescaler a wypełnienie kontrolwane przez pwm1a oraz pwm1b dla odpowiednich kanałów.
    Aby kontrolowac oba parametry musisz zrezygnowac z jednego kanału PWM wtedy masz możliwośc jedną wartością np: pwm1a kontrololwac częstotliwośc a pwm1b kontrollwałby wypełnienie dla jednego tylko sygnału PWM.
    Zatem najpierw musisz zacząc od wybrania trybu pracy timera i pod ten tryb prowadzic dalsze obliczenia dla przyjętej częstotliwości.


    e marcus
  • #14
    gustawm2
    Level 11  
    Hej.

    Dzięki za odpowiedź.
    Będę musiał jeszcze nad tym przysiedzieć bo coś mi się to wszystko rozjeżdża.

    Ustaliłem częstotliwość PWM z następującego wzoru - częstotliwość rezonatora/preskaler/510(w przypadku pwm 8bit)

    Pogubiłem się totalnie w tych timerach i ustawieniach.
    Jutro po pracy wezmę się jeszcze raz za książkę i poczytam - może się coś rozjaśni; później przeczytam datasheeta i mam nadzieję, że się wszystko wyklaruje.
  • #15
    Anonymous
    Anonymous  
  • #16
    gustawm2
    Level 11  
    Witam,

    ale kiedy właśnie zależy mi na tym, żeby to skumać... wynik na oko uzyskałem taki jak oczekiwałęm, teraz chcę iść dalej.
    Potrzebuję wygenerować impulsy o długości od 1000 do 2000us z zadanym taktowaniem - w zasadzie dowolnym pomiędzy 50-400Hz
  • #17
    emarcus
    Level 38  
    gustawm2 wrote:
    Witam,

    ale kiedy właśnie zależy mi na tym, żeby to skumać... wynik na oko uzyskałem taki jak oczekiwałęm, teraz chcę iść dalej.
    Potrzebuję wygenerować impulsy o długości od 1000 do 2000us z zadanym taktowaniem - w zasadzie dowolnym pomiędzy 50-400Hz


    No to wybierz swoją częstotliwośc z tabeli, ktorą ci podałem i pod ten odpowiedni tryb skonfiguruj timer, a w programie głównym pozostanie ci manipulacja wypełnienia poprzez zmiany wartości pwm1a. Process tej zmiany może byc dokonany na wiele różnych sposobów. Cały program nie powinien zając więcej niż kika linii kodu.

    e marcus
  • #18
    Anonymous
    Anonymous  
  • #19
    emarcus
    Level 38  
    Saabotaz wrote:
    Jeśli chcesz mieć kontrolę nad długością impulsu PWM i długością całego okresu (np generowanie prostokąta o określonej częstotliwości) to zazwyczaj używa się timera w trybie CTC.
    .


    Eh... Sabot,
    Mącisz mu w głowie okropnie......
    Przecież w CTC nie ma możliwości nad kontrolą obydwóch parametrów; częstotliwości i wypełnienia niezależnie.
    Praktycznie reguluje się tylko wypełnienie (dokładniej czas trwania impulsu), co w konsekwencj staje się wypełnieniem w przypadku generowania fali poprzez 'toggle OCF1A - stanu logicznego wyjścia.
    Oczywiście wypełnienie w tej sytuacj będzie zawsze 50% (konskwencja procesu toggle). Częstotliwośc (okres) takiej 'pseudo PWM' fali będzie funkcją wypełnienia.

    Autor potrzebuje zmieniac wypełnienie przy wybranej i ustalonej częstotliwości czego tryb CTC mu nie daje, więc musi 'sięgnąc' do innych trybów configuracji timera gdzie taka niezależna kontrola jest możliwa.

    e marcus