HSV è meglio di RGB...

Come molti di voi, anche io in passato ho avuto la curiosità di "giocare" con i primi led RGB, e come credo tutti possiate aver constatato, il problema principale nell'utilizzo di questi led è la generazione di colori indipendentemente dalla luminosità che con l'assegnazione diretta dei valori RGB non è certo semplice ed intuitiva, cosa che invece risulta estremamente facile con il sistema di descrizione del colore HSB (o HSL, HSV dove V o L sta per value o level riferito alla luminosità) ovvero:
Hue (tonalità) Saturation (saturazione) Brightness (luminosità):

xlarge_564px-color_cones.png

(immagine liberamente tratta da questo link di wikipedia da vedere per approfondimenti sul metodo HSV).

In pratica definendo il valore H (nel range da 0° a 360°) si definisce il colore; quindi con S la quantità in percentuale (valore da 0 a 1) di colore presente, e con B la percentuale (valore da 0 a 1) dell'intensità luminosa.

Ed agendo ad esempio sul solo valore B sarà possibile far accendere e spegnere gradualmente il led mantenendo ad ogni livello di luminosità il colore prescelto :-)

 

//--- prototipo funzione
void HSVtoRGB( float h, float s, float v );

struct tipo_rgb{  //definisce la struttura dati RGB
  unsigned char r; //red - rosso
  unsigned char g; //green - verde
  unsigned char b; //blue - blu
}
led[2], pin[2]; //definisce i due array utilizzati: i valori RGB e le relative uscite

//variabili di uso generale
byte x;
int  h = 0;
float s, v;

void setup()
{

  pin[0].r = 3;  //assegna le uscite ai colori del primo led
  pin[0].g = 6;
  pin[0].b = 5;
  pin[1].r = 9;  //assegna le uscite ai colori del secondo led
  pin[1].g = 11;
  pin[1].b = 10;

  for( x=0; x<2; x++){  //imposta i pin come uscite
    pinMode(pin[x].r, OUTPUT);
    pinMode(pin[x].g, OUTPUT);
    pinMode(pin[x].b, OUTPUT);
  }
}

void loop()
{
  (h > 359) ? h = 0 : h++;  //ciclo della tonalita
  v = 0.5;			//luminosita
  s = 1;			  //saturazione
  HSVtoRGB( 0, (float)(h), s, v );
  HSVtoRGB( 1, (float)(360 - h), s, v );

  for( x=0; x<2; x++){  //aggiorna le uscite
    analogWrite(pin[x].r, 255 - led[x].r);
    analogWrite(pin[x].g, 255 - led[x].g);
    analogWrite(pin[x].b, 255 - led[x].b);
  }

  delay(10);
}

/* HSVtoRGB
  (cc) 2008-2010 Kokiua (alias L.M.) from Sorbolo (Parma) - Italy
  Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/
  algoritmo rielaborato partendo da da http://www.cs.rit.edu/~ncs/color/t_convert.html

  da RGB a HSB (Hue/Tonalita' - Saturation/Saturazione - Brightness/Luminosita')
  HSB diventa HSV definendo Brightness = Value per distinguere la variabile B di RGB

  i valori RGB che tornano sono nel range da 0-255
  i valori in entrata sono:
  h = [0.0-360.0] ( Tonalita' in gradi)
  s = [0.0-1.0] (Saturazione in % dove 1 = 100%)
  v = [0.0-1.0] (Luminosita' in % dove 1 = 100%)
 */
void HSVtoRGB( unsigned char x, float h, float s, float v )
{
  int i;
  float f, p, q, t, r, g, b;
  if( s == 0 ) {
    r = g = b = v;   // achromatic (grey)
    return;
  } else {
    h /= 60;			// sector 0 to 5
    i = floor( h );
    f = h - i;			// factorial part of h
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
    switch( i ) {
    case 0: r = v; g = t; b = p; break;
    case 1: r = q; g = v; b = p; break;
    case 2: r = p; g = v; b = t; break;
    case 3: r = p; g = q; b = v; break;
    case 4: r = t; g = p; b = v; break;
    default: r = v; g = p; b = q;  break; // case 5:
    }
  }
  led[x].r = 255 * r;	//converto i valori RGB dal range 0.0-1.0 a 0-255
  led[x].g = 255 * g;
  led[x].b = 255 * b;
}

N.B. i led che ho utilizzato (2 ma possono essere chiaramente di più visto l'uso dell'array) sono a catodo comune e quindi la logica è invertita (per questo emetto il valore 255 - x).

Chiaramente sarà possibile "legare" uno o più parametri di controllo del colore ad ingressi analogici (al quale avremo collegato un sensore, un potenziometro, o altro) con grande semplicità, come in questo esempio:

//loop centrale modificato
void loop()
{
  h = (float)((float)analogRead( 0 ) * (360.0L/1024.0L) ); //assegnazione del valore analogico letto nel pin 0 al parametro h (tonalità)
  v = 0.5;			//luminosita
  s = 1;			  //saturazione
  HSVtoRGB( 0, (float)(h), s, v );
  HSVtoRGB( 1, (float)(360 - h), s, v );

  for( x=0; x<2; x++){  //aggiorna le uscite
    analogWrite(pin[x].r, 255 - led[x].r);
    analogWrite(pin[x].g, 255 - led[x].g);
    analogWrite(pin[x].b, 255 - led[x].b);
  }
  delay(10);
}

Tag: