Witajcie! Postanowiłem zrobić siostrze na święta lampkę RGB. Wykonałem ją na ATTiny2313. Żeby jednak była troszkę inna dodałem jej więcej opcji. Mianowicie posiada 3 tryby: 1: Ustawiamy kolor, lampka losowo miga jaśniej/ciemniej z regulowaną prędkością (coś a la ognisko). 2: Lampka losowo mruga różnymi kolorami, ustawiana prędkość. 3: Lampka płynnie przechodzi między losowymi kolorami z zadaną prędkością. Fotki/filmiki robione kalkulatorem, wybaczcie. http://obrazki.elektroda.pl/4551836800_1294782513_thumb.jpg http://obrazki.elektroda.pl/1166706300_1294782525_thumb.jpg http://obrazki.elektroda.pl/8475819400_1294782529_thumb.jpg https://filmy.elektroda.pl/19_1294782676.mp4 https://filmy.elektroda.pl/73_1294785657.mp4 Ustawianie wygląda tak: mamy 4 przyciski, do zmiany trybu (między wymienionymi trzema), do wybrania zmienianego parametru, i 2 do zwiększania i zmniejszania wartości parametrów. Parametrami są składowe R, G, B i czas opóźnienia, mający wpływ na częstotliwość pracy. Wiemy który parametr zmieniamy, gdyż po naciśnięciu przycisku 'par' lampka nas informuje zapalając się na chwile na odpowiedni kolor, bądź mrugając 3 razy na biało przy zmianie opóźnienia. Za to jest odpowiedzialny ten rozbudowany switch w ISR(INT1_vect). Co do działania. Pierwsze 2 tryby banalne, natomiast 3-ci działa tak: losuje liczbę od 0 do 7, bo mam 8 różnych kombinacji kolorów (R on/off, G on off, B on/off = 2*2*2=8). W praktyce- losuje liczbę, i o tym czy dany kolor ma być zapalony decyduje 1 z 3 najmłodszych bitów. Następnie, w odpowiednio opóźnianej, 255-obiegowej pętli for, gdy aktualna składowa jest powiedzmy wyłączona, a wylosowaliśmy że ma być włączona, co obieg pętli dodajemy 1 do natężenia. Gdy jest włączona i wylosowaliśmy że ma być włączona, po prostu nie robimy nic. W ten sposób przechodzimy płynnie między kolorami. Otrzymujemy myślę zatem dobry sposób wyświetlania. Myślę, że gdyby próbować przesuwać zmianę różnych kolorów w fazie to nie dałoby nam to wiele, zwiększyło jedynie średnią jasność wyświetlanych kolorów (tzn. wolimy wyświetlać kolor w postaci 0 150 150 niż 100 250 250, bo jest bardziej nasycony, choć trochę ciemniejszy). Są to jedynie moje luźne, nie do końca analizowane w praktyce ni teorii domysły ;). Kod zamieszczam, jeśli jakiś pros by się tu przypadkiem zbłąkał i cierpiał na nadmiar czasu ^ chęci, proszę o zerknięcie i komentarz. W sensie, czy ten kod jest jako tako w miarę napisany, jakieś może rady/ krytyka. Wiem, delay w ISR brzydko, zależało mi na prostocie. Jakiś inny sposób na niwelacje drgań styków? Do początkujących: kod mam do ATTiny2313, by uzyskać na inne mikro kontrolery AVR najprawdopodobniej trzeba będzie zmodyfikować funkcje INIT. Co do hardware'u, to nawet go tu nie zamieszczam, jest prościutki. Dioda podpięta do pinów timerów przez oporniki R=200 G=100 B=100 ohm. Diódkę sobie oszlifowałem i wywierciłem wgłębienie na środku, równolegle do nóżek, coby ładniej światło rozpraszała. Obudowa z balsy i bibułki z plastycznego. Mam nadzieje że wyjaśniłem +/- mój pomysł sterowania z tą tęczą (chociaż na pewno ktoś już na taki też wpadł, nie szukałem :D). Pozdrawiam, Marcin.
#include & lt; avr/io.h & gt;
#include & lt; avr/interrupt.h & gt;
#include & lt; util/delay.h & gt;
#define _R OCR0A
#define _G OCR1AL
#define _B OCR1BL
enum{R, G, B, czas};
volatile unsigned char par=0, tryb=0, params[4], random, temp[2], rgb[3];
void init(void);
unsigned long rnd(){
static unsigned long y=2463534242;
y^=(y & lt; & lt; 13); y=(y & gt; & gt; 17); return(y^=(y & lt; & lt; 5)); };
void delay(int us){ for(int i=0; i & lt; us; i++) _delay_us(100); }
int main(void){
init();
while(1){
switch(tryb){
case 0:
random=rnd();
_R=((int)params[R]*(int)random)/256;
_G=((int)params[G]*(int)random)/256;
_B=((int)params[B]*(int)random)/256;
delay(2*params[czas]);
break;
case 1:
temp[0]=rnd()%3;
temp[1]=rnd()%100 + 150;
rgb[temp[0]]=temp[1];
rgb[(temp[0]+1)%3]=temp[1] & 0b00111111;
rgb[(temp[0]+2)%3]=temp[1] & 0b00011111;
_R=rgb[0];
_G=rgb[1];
_B=rgb[2];
delay(2*params[czas]);
break;
case 2:
random=rnd();
for(unsigned char i=0; i & lt; 255; i++){
if( (random & 1) & & (rgb[0]!=255)) ++rgb[0];
if(!(random & 1) & & (rgb[0]!=0)) --rgb[0];
if( (random & 2) & & (rgb[1]!=255)) ++rgb[1];
if(!(random & 2) & & (rgb[1]!=0)) --rgb[1];
if( (random & 4) & & (rgb[2]!=255)) ++rgb[2];
if(!(random & 4) & & (rgb[2]!=0)) --rgb[2];
if(tryb!=2) break;
_R=rgb[0];
_G=rgb[1];
_B=rgb[2];
delay(params[czas]/10);
}
if(rgb[0] & gt; 128) rgb[0]=255; else rgb[0]=0;
if(rgb[1] & gt; 128) rgb[1]=255; else rgb[1]=0;
if(rgb[2] & gt; 128) rgb[2]=255; else rgb[2]=0;
break;
}
}
}
/////////////////////////////////////////
ISR(PCINT_vect){
if(!(PINB & 2)) params[par]+=25;
if(!(PINB & 1)) params[par]-=25;
delay(50);
}
/////////////////////////////////////////
ISR(INT0_vect){ // TRYB
if(++tryb==3) tryb=0;
delay(100);
}
/////////////////////////////////////////
ISR(INT1_vect){ // PARAMETRY
switch(par){
case 0:
par++;
_R=0;
_G=255;
_B=0;
delay(500);
break;
case 1:
par++;
_R=0;
_G=0;
_B=255;
delay(500);
break;
case 2:
par++;
for(unsigned char i=0; i & lt; 3; i++){ _R=150; _G=255; _B=255; delay(100); _R=0; _G=0; _B=0; delay(100);}
break;
case 3:
par=0;
_R=255;
_G=0;
_B=0;
delay(500);
break;
}
}
/////////////////////////////////////////
void init(void){
DDRB=28;
PORTB=3;
DDRD=0;
PORTD=12;
GIMSK = 0b11100000;
PCMSK = 0b00000011;
MCUCR |= 0b00000000;
TCCR0A = 0b11000011;
TCCR0B = 0b00000010;
TCCR1A = 0b11110001;
TCCR1B = 0b00001010;
OCR1AH = 255;
OCR1BH = 255;
OCR1AL = 150;
OCR1BL = 150;
OCR0A = 150;
sei();
}