Edoardo Vignali
Lampada RBG
Progetti -
Venerdì 30 Luglio 2010 16:13
Scritto da Edoardo Vignali

Questo articolo parlerà di come costruirsi una lampada RBG con un ATMEGA168 in modalità standalone. Per capire meglio questo articolo è consigliato leggere questi altri due articoli:

Arduino in modalità standalone, per capire come usare un ATMEGA con bootloader arduino precaricato senza aver bisogno della schedina.

Scrivere bootloader Arduino senza utilizzare un programmatore AVR, per poter comprare un semplice ATMEGA8/168/328 e programmarvelo con il Bootloader senza particolari circuiti che molto spesso non funzionano, oppure che vi fanno perdere ore intere se non giornate a cercare i driver giusti per la vostra configurazione di sistema.

Il progetto di una lampada RBG è molto semplice, non richiede particolari skill di programmazione ne di particolari conoscenze in ambito elettronico. Per fare questa lampada io ho seguito un iter che possiamo racchiudere nei seguenti passi.

1. Progettazione del Circuito

Se avrete letto il primo articolo sopracitato capirete che tornerà utilissimo avere solo un microcontrollore senza la schedina, perchè in questo modo risparmiamo spazio all'interno della lampada e soldi. Infatti non avremo bisogno di ricomprarci un'altra board per successivi progetti ma semplicemente vi basterà un altro ATMEGA.

Il dimensionamento dei driver dei led è molto semplice. Ho usato un semplice BJT PNP, perchè la corrente che esce direttamente dalla porta dell microcontrollore è di 40mA mentre quella di picco del mio led RBG è di 350mA.

Led Driver RBG

Dato che pilotiamo il led in PWM, non starà sempre acceso e quindi utilizzaeremo la corrente di picco e tenendo conto che mediamente la Vd per ogni colore è 2.2V

Il nostro BJT lavorerà essenzialmente in due zone, Saturazione e Interdizione. Dato che la Ie =Ib+Ic allora dimensionerò la R1 a seconda dei valori commerciali di resistenza, andando per tentativi con un valore commerciale di R1 di 180ohm mi viene una Ib = (5-0.7-2.2)/180 =11.67mA e con una R2 di 6.8ohm la Ic = (5-0.5-2.2)/6.8= 338.23mA quindi la Ie = 11.67+338.23=~ 350mA. Le resistenze andranno prese da 1W per sicurezza e 1% di tolleranza.

Una volta progettato il driver e stabilito che al pin 11 ci connetteremo il ricevitore IR, non rimane altro che creare il circuito per l'arduino standalone e stabilire a quali pin PWM vogliamo collegare ai vari leds. Io ho scelto il pin 5 per il rosso il 9 per il blu e il 10 per il verde.

Schema lampada rbg fritzing

Per chi non si trovasse bene con fritzing (tipo me :D) questo è lo schema Eagle:

Schema lampada rbg eagle

2.Bill Of Material

  • 1x Atmega168 con bootlader precaricato
  • 2 Condensatori da 22pF
  • 2 Condensatori da  10uF
  • 2 Condensatori da 100uF
  • 1 Condensatore da 1uF
  • 1 Power Jack
  • 1 Interruttore
  • 1 Oscillatore al quarzo da 20MHz
  • 3 BJT BC337
  • 3 Resistenze da 6.8ohm
  • 3 Resistenze da 180ohm
  • 1 Resistenza da 10K
  • 1 Ricevitore IR tipo TSOP o altro
  • 1 Millefori per prototipazione
  • 1 LED RBG 1W Prolight o simile
  • 1 LM7805
  • Saldatore a Stagno
  • Stagno
  • Treccia dissaldante per correggere eventuali errori o pompetta ciucciastagno
  • Cavetteria varia
  • 1 Arduino di tipo Diecimila, Duemilanove o NG

3. Prototipazione

Per la prototipazione ho usato una millefori ibrida tipo questa.

Basetta per prototipare

Che poi è diventata una cosa tipo:

Rbg prototipo

L'oggetto verde sotto al led è un dissipatore, perchè ho pensato che sarebbe stato utile nel caso il led non riuscisse da solo a dissipare tutto il calore generato.

Il filo rosso,blu e verde non sono stati messi a caso infatti è molto utile usare dei riferimenti di questo tipo in fase di prototipazione.

4.Modifica del bulbo da lampioncino per esterni

Il bulbo che troverete nei negozi di bricolage avrà un portalampade interno, io l'ho tolto utilizzando un trincetto e un seghetto. Lo spazio per un alimentatore interno ci sarebbe, ma non è molto comodo realizzarlo direttamente sulla nostra board perchè richiederebbe un lavoro troppo certosino non adatto ad un hobbista medio.

RBG Lamp Bottom

Successivamente ho creato dei buchi sul tappo nero per  l'interruttore e la femmina del plug di alimentazione per rendere il lavoro più professionale. I

Retro lampada rbg

Per poter chiudere la lampada ho dovuto asportare una parte dell'incastro. Dovete scegliere una parte che non contenga i "finecorsa"  che servono a bloccare la lampada al tappo quando la avvitate.

Bulbo lampada rbg

Inoltre ho tagliato un rettangolo delle dimensioni del TSOP1736 per poter avere il ricevitore a infrarossi direttamente sulla superficie esterna.

Rbg lamp frontale

5.Codice

Il codice è stato scritto interamente da me quindi probabilmente conterrà degli errori e non sarà perfettamente ottimizzato. Spero che chiunque si imbatta in questo articolo abbia la voglia di darci un'occhiata e magari migliorarlo. Includete la libreria IRremote.h

int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
int pins[]={5,9,10};
int scala_c[]={255,0,0,255,115,15,255,0,70,255,0,95,255,0,215,
255,0,255,0,100,255,10,140,215,0,150,115,0,225,50,0,255,0,0,255,
0,0,255,0,255,255,0,255,255,0,255,255,255};
word col[] ={0x906F,0x10EF,0x50AF,0xB04F,0x30CF,0x708F,
0xA857,0x28D7,0x6897,0x9867,0x18E7,0x58A7,
0x8877,0x8F7,0x48B7,0xD02F};
word funzione[] = {0xA05F,0x20DF,0x609F,0xE01F,
0xF00F,0xE817,0xD827,0xC837};
int rbg =0;
 int rbg_matrix[6][3] =
{
  {255, 0,  0 },
  { 0, 255, 0 },
  { 0,  0, 255},
  { 0, 255,255},
  {255, 0, 255},
  {255,255, 0 },
};
 int stat_prec=0;
 int stat_succ=0;
 int fading[] = {0,0,0};
boolean set = LOW;
long int tempo_delay = 0; 
int debounce = 30;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

word decodifica(){
  word var = 0x0000;
 if (irrecv.decode(&results)) {
  var = (results.value);
 // Serial.println(var,HEX);
 //delay(50);
  return var;
  irrecv.resume();
 }
}

void loop() {
if (irrecv.decode(&results)) {
    colors();
    irrecv.resume();
 }
}

void colors(){
if (irrecv.decode(&results)) {
  switch(funz()){
case 0:
  //if(decodifica() == funzione[0]){
    Serial.println("funzione 0");
    if(rbg<255) rbg+=17;
    else rbg =0;
 // }
  break;
  case 1:
//  if(decodifica() == funzione[1]){
   Serial.println("funzione 1");
    if(rbg>-255) rbg-=17;
    else rbg = 0;
    
  //}
  break;
  case 2:
  rbg_clear();
  Serial.println("funzione OFF");
  break;
  case 3:
  //Bottone On premuto Funzione testing led
 Serial.println("funzione TEST");
   rbg_clear();
      for(int i =0;i<3;i++){
            for(int a = 0; a < 256; a +=5){
              analogWrite(pins[i],a);
              delay(10);
             }
            for(int a = 255; a>0; a -= 5){
              analogWrite(pins[i],a);
              delay(10);  
           } 
          rbg_clear(); 
        }   
 break;
 case 4:
   //funzione FLASH
 Serial.println("funzione FLASH");
  set = LOW;
  while(set == LOW){
  if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    } 
  for(int i =0;i<3;i++)
    analogWrite(pins[i],scala_c[rnd()]);
    delay(100);
    rbg_clear();
  }
 
 break;
  
 case 5:
  Serial.println("funzione STROBE");
 //funzione STROBE
  set = LOW;
  while(set == LOW){
  if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    } 
  for(int i =0;i<3;i++)
    analogWrite(pins[i],255);
    delay(25);
    rbg_clear();
    delay(25);
  }
 
 break;
 case 6:
    Serial.println("funzione FADE");
  //funzione FADE
  set = LOW;
  while(set == LOW){
  if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    }
stat_succ = random(0,5);
  if(stat_succ != stat_prec){
 for(int i =0;i<3;i++){
 analogWrite(pins[i],rbg_matrix[stat_prec][i]);
  if(rbg_matrix[stat_succ][i] < rbg_matrix[stat_prec][i]) fading[i]= -5;
  if(rbg_matrix[stat_succ][i] == rbg_matrix[stat_prec][i]) fading[i]= 0;
  if(rbg_matrix[stat_succ][i] >rbg_matrix[stat_prec][i]) fading[i]= 5;
      }
int o =0;      
 while(o<256){
   if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    }
   for(int i = 0; i<3; i++){
     analogWrite(pins[i],(rbg_matrix[stat_prec][i]+fading[i]*o));
       }
     delay(25);
    o+=5;
     }
     stat_prec = stat_succ;
   } 
  }
  break;
  case 7:
    Serial.println("funzione SMOOTH");
  //funzione SMOOTH
  set = LOW;
  while(set == LOW){
  if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    }
stat_succ = random(0,5);
  if(stat_succ != stat_prec){
 for(int i =0;i<3;i++){
 analogWrite(pins[i],rbg_matrix[stat_prec][i]);
  if(rbg_matrix[stat_succ][i] < rbg_matrix[stat_prec][i]) fading[i]= -1;
  if(rbg_matrix[stat_succ][i] == rbg_matrix[stat_prec][i]) fading[i]= 0;
  if(rbg_matrix[stat_succ][i] >rbg_matrix[stat_prec][i]) fading[i]= 1;
 }

    int o=0;
 while(set == LOW && o<256){
 if (irrecv.decode(&results)) {
  if(funz() == 2) {
    set = HIGH;
  }
  else{
    set == LOW;
  }
   irrecv.resume();
    }
    for(int i = 0; i<3; i++){
     analogWrite(pins[i],(rbg_matrix[stat_prec][i]+fading[i]*o));
       }
     delay(50);
     o++;
     }
     stat_prec = stat_succ;
   } 
  }
  break;
 default:
   Serial.println("funzione COLOUR PURO");
    for(int a=0;a<16;a++){
       if(decodifica() == col[a]){
       for(int i =0;i<3;i++){
         int colore = scala_c[i*16+a];
          analogWrite(pins[i],colore);
        }
       }
      }
      irrecv.resume();
    }
  }
}
//Funzione generatrice di un numero casuale da 0 a 47
int rnd(){
 int rand = random(0,47);
 return rand;
}
//Funzione che spenge tutti i colori
void rbg_clear(){
  for(int i = 0; i<3;i++){
    analogWrite(pins[i],0);
  }
}
// Funzione che assegna ad ogni tasto funzione un numero da 0 a 7
// per entrare nei vari case ed 8 per entrare nel default
int funz(){
   if (irrecv.decode(&results)) {
   word tmp = 0x0000;
   tmp = decodifica();
   int w =0;
   while(funzione[w] != tmp) {
     if(millis() - tempo_delay > debounce){ // da un piccolo delay per evitare segnali indesiderati
      tempo_delay = millis();
       if(w<8) w++;
       else return 8;
     }
   }return w;
    irrecv.resume();
       }
       
      }

Le varie funzioni sono spiegate nel codice, ma mi vorrei soffermare su FADE e SMOOTH.

La differenza tra le due è che FADE è più veloce mentre SMOOTH è molto più lenta, ma entrambe hanno lo stesso principio di funzionamento. Praticamente io ho creato una matrice di 6 possibili stati del led ovvero: Rosso acceso, verde e blu spento; verde accesso e rosso e blu spento; ecc ecc; rosso e verde acceso e blu spento; ecc ecc. Queste due funzioni scelgono uno di questi stati a caso, ne scelgono uno successivo e ci passano sfumando più o meno velocemente.

Questo è un esempio:

Funzione passaggio di stato

In pratica con questa funzione ho voluto creare un modo casuale di fading che possa generare qualsiasi tipo di colore possibile con un led RBG in modo da non annoiarsi mai della lampada.

Ecco a voi il risultato, cosa ne pensate?

Al solito scusate la pessima qualità del video ma non ho una fotocamera digitale e purtroppo sono costretto ad utilizzare il mio buon vecchio cellulare.

Ringrazio AndreaV del forum di Arduino per avermi corretto i calcoli del dimensionamento del BJT.

CC

 

Gioblu Robotics © 2010 - 2012 · Sitemap · privacy

gioscarab@gmail.com

Gioblu BOTServer è online dal 10 Aprile 2010 - 319.232 Visite - 1.027.175 Pagine visualizzate - 182.309 Visitatori unici - 536 utenti attivi