Autor: Dondu
2011.11.24
Na rozgrzewkę małe zadanie, które będzie nam potrzebne w pierwszym odcinku cyklu Efektywne Planowanie Projektu, w którym jednym z kilku zadań realizowanych przez mikrokontroler, będzie wykorzystanie PWM do regulacji świecenia diodą LED (będzie to zaledwie drobna część projektu).
Niektórzy z Was wiedzą z praktyki, inni z teorii, a jeszcze inni nie wiedzą, że regulując liniowo wypełnienie PWM, nie otrzymamy liniowego wrażenia zwiększania lub zmniejszania się światła generowanego przez LED.
Rozwiązania zadania:
Wynika to z faktu, iż każdy LED ma swoją charakterystykę strumienia światła i nie jest ona liniowa. Dodatkowo oko ludzkie także ma nieliniową charakterystykę czułości, na domiar złego zależną od barwy światła.- LED vs ludzkie oko - by miszcz310
- LED vs ludzkie oko - by ky3orr
- wersja Dondu (patrz poniżej)
Możesz to zauważyć obserwując poniższy film:
Gdzie to można wykorzystać?
- płynne regulacja LED np. w podświetlaniu wyświetlacza LCD,
- liniowe sterowanie tranzystorem itp.
- itd.
Proponuję więc na rozgrzewkę zadanie stricte programowe, polegające na opracowaniu funkcji korygującej wypełnienie PWM (korekcja gamma) w taki sposób, by oko ludzkie miało wrażenie płynnego rozjaśniania i ściemniania diody.
Tych którzy nie wiedzą, co to takiego PWM, zapraszam do lektury: PWM - Co to takiego?
To co widzicie na filmiku zrealizowałem tak:
// EPP - Rozgrzewka // Algorytm korekcji jasności LED w celu uzyskania płynnego rozjaśniania // i ściemniania widzianego przez ludzkie oko // // Dondu, 2011.11.24 // http://mikrokontrolery.blogspot.com // // Atmega8, zegar 8MHz #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> //progi PWM #define prog_0 230 #define prog_1 205 #define prog_2 180 #define prog_3 155 #define prog_4 130 #define prog_5 105 #define prog_6 80 #define prog_7 55 #define prog_8 30 #define prog_9 15 char LED_przelicz_jasnosc(char wartosc){ //funkcja korygująca jasność świecenia, wartości dobrane doświadczalnie if(wartosc > prog_0) { return 255; }else if(wartosc > prog_1) { return 128; }else if(wartosc > prog_2) { return 80; }else if(wartosc > prog_3) { return 60; }else if(wartosc > prog_4) { return 50; }else if(wartosc > prog_5) { return 35; }else if(wartosc > prog_6) { return 20; }else if(wartosc > prog_7) { return 10; }else if(wartosc > prog_8) { return 6; }else if(wartosc > prog_9) { return 3; }else{ return 0; } } int main(void) { char test = 0; //zaczynamy od PWM z duty cycle = 0 char w_gore = 1; // DDRB= (1<<PB2) | (1<<PB1); //LEDY podpięte pod: PB2-LED lewy, PB1-LED prawy //PWM Mode 5 - Fast PWM, 8-bit //piny OC1A i OC1B ustawiane na Compare Match, kasowane przy BOTTOM czyli //Set OC1A/OC1B on Compare Match, clear OC1A/OC1B at BOTTOM, (inverting mode) TCCR1A = (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM10); TCCR1B = (1<<CS12); //preskaler = 256 //pętla główna while(1) { _delay_ms(20); //opóźnienie, by efekt było widać if(w_gore) { //rozjaśnianie LED if(test<240){ test += 15; //zmiana PWM (kork co 15) }else{ //osiągnięto górną granicę test = 255; w_gore = 0; // zmień kierunek } }else{ //ściemnianie LED if(test>15){ test -= 15; //zmiana PWM (kork co 15) }else{ //osiągnięto dolną granicę test = 0; w_gore = 1; // zmień kierunek } } OCR1B = LED_przelicz_jasnosc(test); //ustaw PWM LED lewy z korekcją OCR1A = test; //ustaw PWM LED prawy bez korekcji } }Plik programu: main11.c
Jak zauważyłeś korekcja została zrealizowana z użyciem 10 progów, co wystarcza do osiągnięcia efektu jak na filmie. Ale innymi sposobami można zwiększyć płynność - spróbuj sam :-)
Podsumowanie
Wykorzystane zasoby:
- pamięć programu FLASH: 228 bajtów (0,3%)
Zadanie dla Was
Waszym zadaniem jest opracować inne wersje rozwiązania tego problemu.
Stawiam tylko jeden warunek: Nie używamy liczb zmiennoprzecinkowych!
Masz pytania?
Jeżeli coś nie jest jasne, to zadaj pytanie w komentarzu do niniejszego artykułu.
Termin
Termin nadsyłania rozwiązań w przypadku rozgrzewki będzie krótki i ustalam na niedzielę
Zmiana terminu (prośba w komentarzu). Nowy termin:
Termin już upłynął, ale możesz przesłać swoje rozwiązanie, jeżeli jest ono inne (czytaj: lepsze) niż te opublikowane.
Forma dostarczania rozwiązań
Spakowany projekt AVR Studio 4 lub plik tekstowy o rozszerzeniu *.c
Proszę o bogate komentarze!
Po otrzymaniu rozwiązań wybiorę najciekawsze i opublikuję zgodnie z zasadami określonymi tutaj: Zasady publikacji EPP
Rozwiązania zadania:
- LED vs ludzkie oko - by miszcz310
- LED vs ludzkie oko - by ky3orr
- wersja Dondu (patrz wyżej)
szkoda że taki krótki czas.
OdpowiedzUsuńnie było mnie na weekend i nie miałem pojęcia o zadaniu :)
tydzień lub dwa to byłoby ok.
Grzegorz Kaczmarek
OK, przedłużam więc czas o tydzień, do 4 grudnia 2011 (niedziela) włącznie.
OdpowiedzUsuńBy nie przegapić niczego, warto się zarejestrować na Facebooku lub subskrypcji tematu: Subskrypcja
Do tej chwili nadeszło jedno rozwiązanie, które opublikuję nie czekając na pozostałe, ponieważ jest bardzo fajnie opracowane z wykresami i filmikiem.
Ponieważ na razie nie wszyscy są artystami w C mam prośbę aby przynajmniej na początku pisać bardziej czytelny kod źródłowy. Chodzi o klamerki. Ciało poszczególnych funkcji powinno być wyraźnie widoczne. Początkującemu dosyć trudno odnajdować w listingu odpowiadające sobie pary nawiasów. Być zrozumiałym to cnota a nie ujma.
OdpowiedzUsuńTo nie jest takie proste ze względu na wąski obszar do pisania kodu zaledwie 80 znaków. Dodatkowo strasznie dużo pracy kosztuje przygotowanie tego dla HTML, na ale to nie jest wytłumaczenie :-)
OdpowiedzUsuńPostaram się zwracać bardziej uwagę na ten aspekt, w następnych kodach, by wyglądały co najmniej tak: Przykład
Dziękuję za zwrócenie uwagi.
Jestem początkujący, i w programowaniu, i w programowalnych scalaczkach.
OdpowiedzUsuńMógłby ktoś dokładniej opisać co znaczą komendy w linijkach 65-73?
Szukałem, ale nic nie znalazłem.
Szukać powinieneś w datasheet ATmega8.
OdpowiedzUsuńSą to ustawienia bitów w rejestrach TCCR1A i TCCR1B, które odpowiednio ustawiają Timer1. Opis co zostało ustawione jest w komentarzu w liniach, które podałeś.
Każdy bit jest nazwany dokładnie tak jak w datasheet, gdzie jest opis za co każdy z nich odpowiada.
Nie wiem dlaczego, ale u mnie dioda zamiast płynnie rozjaśniać się i ściemniać, miga po prostu z różną częstotliwością... Co może być powodem?
OdpowiedzUsuńNa początek sprawdź, czy masz zegar ustawiony na 8MHz -(program jest napisany na taki zegar). Drugie co na szybko przychodzi mi do głowy z tak krótkiego opisu jak Twój, to może zastosowałeś diodę samodzielnie mrugającą?
OdpowiedzUsuńMasz racje że nie powinnismy zaśmiecać tamtego wątku http://www.elektroda.pl/rtvforum/viewtopic.php?p=11224706#11224706 więc ponawiam moje zastrzeżenie tutaj - nieliniowość jest przede wszystkim efektem logarytmicznej charakterystyki oka http://pl.wikipedia.org/wiki/Prawo_Webera-Fechnera a nieidealne zachowanie diody nie będzie w praktyce zauważalne - przynajmniej w takim prostym układzie małej mocy gdzie LED zapala się i gaśnie praktycznie natychmiast.
OdpowiedzUsuńWięc popraw to co napisałeś :)
Tak, masz rację, że w tym wypadku najważniejsza jest charakterystyka ludzkiego oka, o której piszemy. Faktycznie powinien to być pierwszy argument na liście, a nie drugi - poprawię.
OdpowiedzUsuńJednakże pozostałe czynniki, jak nieliniowość strumienia światła oraz źródła zasilania także w jakimś stopniu wpływają na końcowy efekt. Czy zauważalny dla oka? Być może nie, a być może nie dla każdego. To zależy od wielu czynników, np. częstotliwości PWM vs parametr czasu zapalania i gaszenia LED.
Jednakże powinniśmy o tym pisać, by za chwilę ktoś inny, nie zarzucił nam, że nie napisaliśmy :-)
Dziękuję za uważne czytanie artykułów.
A że tak zapytam. Gdzie można zobaczyć konkursowe rozwiązania?
OdpowiedzUsuńSą na samym początku tego artykułu po prawej stronie pod pierwszą grafiką :)
Usuńfakt :D dzięki :)
Usuń