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?
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
1) Robisz "Goto Rozjasnij" i "Goto Sciemnij", a potem próbujesz wrócić Returnem. Wywalasz program.
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
3) Już ci poradzili że problem jest z GOTO, a powinieneś wstawić GOSUB, ty jednak znów wklejasz program z GOTO.
4) Z programu kolegi nowynom wyrzuć instrukcje PRINT, pewnie na tym ci się sypie bo do reszty nie można się przyczepić.
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?
No dobrze BIGJack, napisz swój programik jak najlepiej potrafisz i pytaj dalej o dręczące Cię wyrywki programiku, pomogę
Aha co do wejścia czujki, to lepiej napisz to na przerwaniu zewnętrznym INT0 (PIND.2), lub INT1 (PIND.3)
Nieee nie musisz robić opóźnień na Timerze, lecz jest to wskazane ze względu na późniejsze przyzwyczajenie, a przede wszystkim zaznajomienie się z tym tematem.
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.
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.
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
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".
Zamień miejscami zawartość subów Zmniejsz i Zwieksz bo są na odwrót.
Waitms 50 daj dopiero po End IF. Różnica niby niewielka ale w obecnej postaci może to sprawiać wrażenie że led reaguje później niż naciśnięcie przycisku.
Jest też taka wpadka, niby żadna ale to kiedyś może być problem:
Config Portd = &B1111100
Rejestry są zawsze 8 bitowe, ty wpisujesz tylko 7 bitów, no bo tyle masz nóżek. Kompilator sam dopisze zero na początku żeby wyrównać do długości 8 bit. A co jeśli kiedyś wyjdzie jego nowa wersja i tego nie dopisze? Też nic się nie stanie ale zawsze definiuj 8 bitów, nawet jak masz tylko 5 nóżek. Brakujące bity wpisuj jako 0 na początku.
Start Timer jest teoretycznie zbędny, timer startuje natychmiast po jego configu. Ale nie wyrzucaj tego, kiedyś coś zmienia w Bascomie i może być problem.
W PWM można też zrobić "dobijanie" do skrajnych wartości, np pwm=0 zrobić jako przełączenie nóżki timera na zwykłe wyjście np w stanie niskim, natomiast pwm=255 jako przełączenie nóżki na wyjście w stanie wysokim. Potem zmieniając na wartość 1-254 trzeba RAZ znów przywrócić nóżkę jako sterowaną z timera.
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
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
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;
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.
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.
Przestań kombinować, poczytaj sobie w innym czasie.
Zwiększaj częstotliwość PWM do momentu aż migotanie nie będzie widoczne. Nie możesz jej zwiększyć na max bo wtedy zabraknie czasu na wykonanie programu z głównej pętli (poza przerwaniem).
Tą prymitywną metodą w ciągu kilku minut uzyskasz bardzo dobrze działające wyświetlanie. Niektórzy za bardzo zagłębiają się w wzory, obliczenia, równania itp. Urządzenie ma działać i tyle, nie ważne jak to zrobisz.
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
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.
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.
Masz tez prosty kalkulator:
Link
Był też AVR Calc czy jakoś tak, programik, bardzo użyteczny.
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.