Redakcja: Dondu
Lampka RGB LED |
Pomysł stworzenia tego projektu powstał przez nadmiar puszek po Coca-Coli który robił bałagan w moim pokoju, więc postanowiłem że zrobię z nich użytek. Poprzez wycinanie różnych motywów na puszce i zamontowanie trójkolorowej diody led uzyskałem prostą i tanią w wykonaniu oraz efektowną w ciemności lampkę. Dodatkowy malunek niebieskim sprayem sprawił że wygląda jeszcze lepiej.
Różne motywy |
Dioda led RGB sterowana jest programową modulacją szerokości impulsów z mikrokontrolera Attiny13. Dlaczego ten scalak? Poszukiwałem czegoś w małej obudowie, a wysterowanie tego za pomocą np. Atmega8 jest w moim odczuciu strzelaniem z armaty do wróbla.
Schemat układu
Schemat układu |
Układ zasilany jest bateryjnie, za pomocą małej pastylki CR2025, dodany kondensator filtrujący. Rezystory dla każdej diody dobierałem doświadczalnie, warto zwrócić uwagę że różne kolory ledów mają różne napięcia przewodzenia.
Vf nieb > Vf ziel > Vf czerw
Jako że układ jest minimalistyczny, wyłącza się go za sprawą wyjęcia baterii, ewentualnie można się pokusić o zamontowanie zworki na zasilaniu.
Program
Zdecydowałem się na prostą sekwencję rozjaśnianych i ściemnianych kolejno kolorów. Zrealizowałem to za pomocą programowego PWM, metoda dość prosta i skuteczna. Dla czytelności rozbiłem program na main.c oraz piny.h, gdzie znajdują się deklaracje zmiennych oraz makra pinów. Myślę że komentarze powiedzą wszystko.piny.h
/* * piny.h * * Created on: 05-12-2013 * Author: Marcin "Mesho" Popko * Strona www: atmegan.blogspot.com */ #ifndef PINY_H_ #define PINY_H_ //marka uproszczające dostęp do portów #define NIEB (1<<PB0) #define ZIEL (1<<PB1) #define CZER (1<<PB2) #define LED_PORT PORTB #define LED_DIR DDRB volatile uint8_t pwm_ziel, pwm_nieb, pwm_czer; //definicje zmiennych przechowujących wartośc pwm uint8_t i; //zmienna na potrzeby pętli for #endif /* PINY_H_ */
main.c
/* * main.c * * Created on: 05-12-2013 * Author: Marcin "Mesho" Popko * Strona www: atmegan.blogspot.com * * Prosta lampka RGB LED sterowana programowym PWM * F_CPU = 1,2MHz */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdlib.h> #include <string.h> #include "piny.h" int main(void) { DDRB |= ZIEL | NIEB | CZER; //ustawiamy piny jako wyjścia PORTB &= ~(ZIEL | NIEB | CZER); //wyłączamy na początek wyjścia diody RGB PORTB |= (1<<PB3) | (1<<PB4); //załączamy pull-upy przy nieużywanych pinach DDRB &= ~((1<<PB3) | (1<<PB4)); //ustawiamy nieużywane piny jako wejścia TCCR0A |= (1 << WGM01); //timer w trybie CTC TCCR0B |= (1 << CS01) | (1 << CS00); //preskaler 64 TIMSK0 |= (1 << OCIE0A); //odblokowujemy przerwanie timera 0 ACSR |= (1<<ACD); //wyłączamy komparator analogowy - oszczędzamy energie sei(); //włączamy globalne zezwolenie na przerwania while (1) { for (i = 0; i < 255; i++) { //rozjaśniamy diodę zieloną pwm_ziel++; //inkrementacja zmiennej pwm diody zielonej _delay_ms(2); //odstep czasowy } // for (i = 0; i < 255; i++) { //ściemniamy diodę zieloną pwm_ziel--; //dekrementacja zmiennej pwm diody zielonej _delay_ms(2); //odstep czasowy } for (i = 0; i < 255; i++) { //rozjaśniamy diodę niebieską pwm_nieb++; //inkrementacja zmiennej pwm diody niebieskiej _delay_ms(2); //odstep czasowy } for (i = 0; i < 255; i++) { //ściemniamy diodę niebieską pwm_nieb--; //dekrementacja zmiennej pwm diody niebieskiej _delay_ms(2); //odstep czasowy } // for (i = 0; i < 255; i++) { //rozjaśniamy diodę czerwoną pwm_czer++; //inkrementacja zmiennej pwm diody czerwonej _delay_ms(2); //odstep czasowy } for (i = 0; i < 255; i++) { //ściemniamy diodę czerwoną pwm_czer--; //dekrementacja zmiennej pwm diody czerwonej _delay_ms(2); //odstep czasowy } } } ISR(TIM0_COMPA_vect) { //przerwanie z f= ~18750Hz static uint8_t cnt = 0; //definicja zmiennej licznika przerywań cnt++; if (pwm_ziel > cnt) //jeśli wartośc zmiennej pwm jest wieksza od wartosci licznika PORTB |= ZIEL; //przełącz stan wyjścia na wysoki else PORTB &= ~ZIEL; //jeśli nie, przełącz stan wyjścia na niski if (pwm_czer > cnt) //jeśli wartośc zmiennej pwm jest wieksza od wartosci licznika PORTB |= CZER; //przełącz stan wyjścia na wysoki else PORTB &= ~CZER; //jeśli nie, przełącz stan wyjścia na niski if (pwm_nieb > cnt) //jeśli wartośc zmiennej pwm jest wieksza od wartosci licznika PORTB |= NIEB; //przełącz stan wyjścia na wysoki else PORTB &= ~NIEB; //jeśli nie, przełącz stan wyjścia na niski if (cnt > 255) cnt = 0; //reset licznika }
Zasilanie
Jako że zastosowałem zasilanie bateryjne, warto było zadbać o to, aby mikrokontroler pobierał jak najmniej prądu. Zdecydowałem się ustawić taktowanie na fabryczne 1,2MHz. Porównałem pobór prądu pobieranego przez sam mikrokontroler przy różnych dostępnych takowaniach, (mierzyłem go od strony masy mikrokontrolera, więc prąd który pobierała dioda nie był uwzględniany).Różne taktowania, to różny pobór prądu |
Okazało się, że można zmniejszyć apetyt mikrokontrolera na prąd czterokrotnie bez większej utraty funkcjonalności. Z 2,8mA udało się zejść aż do 0,6mA!. Dzięki poprawkom w programie prąd ten spadł do 0,55mA.
Łącznie cały układ pobiera do ok. 3mA, bateria CR2025 podczas moich testów starczyła na ok. 2-3h świecenia.
Jedyny problem który napotkałem ze strony programu to spowolnione działanie komendy _delay_ms(x), jednak dla takich banalnych zastosowań dopasowałem doświadczalnie szybkość rozjaśniania/ściemniania.
Prosta konstrukcja |
Ładnie pasuje :) |
Ze względu na to że układ jest prosty, zdecydowałem się zmontować go na płytce uniwersalnej. Poprzez ładne wycięcie i zeszlifowanie uzyskałem konstrukcję pasującą do góry puszki. Dioda LED zamocowana od spodu kieruje światło bezpośrednio do puszki.
Efekt końcowy (film na youtube):
Pozdrawiam
Mesho
Uwagi redakcji
Minimalistyczny projekt przez to technicznych uwag niezbyt wiele.
Najistotniejsza, to bateria. W takim projekcie zastosowanie tak małej baterii kładzie projekt na łopatki. Bardzo fajnie, że autor rozumie ten problem i postanowił dołożyć starań w zakresie minimalizacji prądu pobieranego przez mikrokontroler.
Jednakże na tym polu są jeszcze dwa istotne kierunki modyfikacji:
1. zastosowanie diod LED o wysokim strumieniu świetlnym, przez co ograniczamy prąd pobierany z baterii - najważniejsza zmiana jaką należy rozpatrzyć,
2. zmiana programu w taki sposób, by część znajdująca się w pętli głównej także realizowana była przez przerwanie (to samo lub inne), po to by wyeliminować wszystkie instrukcje delay_ms(), podczas których mikrokontroler niepotrzebnie działa. Po tej modyfikacji pętla główna zawierać powinna wyłącznie rozkaz usypiania mikrokontrolera, do możliwie najgłębszego snu.
Więcej w temacie akumulatorów i zużycia energii możecie poczytać:Bateria zasila mikrokontroler
a o oszczędzaniu energii: SmartPIP - Elektroniczny dręczyciel
Nie wiem jak to jest w przypadku tego układu, ale myślę że jak by zastosować timer i usypiać mikrokontroler choćby do stanu CPU idle zamiast tych delay to pochodziło by to troszkę dłużej na baterii.
OdpowiedzUsuńCo masz na myśli pisząc cyt. "Jedyny problem który napotkałem ze strony programu to spowolnione działanie komendy _delay_ms(x)"?
OdpowiedzUsuńOgraniczona częstotliwość taktowania proca spowodowała że opóźnienie 2ms trwało de facto około, nie pamiętam dokładnie ale gdzieś 20. Sytuacja taka jak w naszych komputerach PC, jak powłączamy za dużo programów, będą się one po prostu ciąć :P
UsuńBTW. Długość pracy baterii z braku dokładnych testów w opisie na wyrost zaniżyłem, ale świecą u mnie po 10h i wciąż nie mają dość. Tak mocno zająłem się stroną artystyczną, że na program nie starczyło zbyt wiele czasu i głowy. Lekcja z usypianiem mikrokontrolera pozostanie mi jeszcze do odrobienia ;)
Usuń