Wednesday, January 9, 2013

Arduino - HSV to RGB

I got an Arduino for Christmas, along with a cool starter pack that contains all kinds of cool switches, LEDs, wires, etc. My favorite component to play with so far is the RGB LED. It has red, green, and blue LEDs inside of one unit, so you can use it to fake any color.

I started with making it just show random colors, but then thought I could do better. The code below chooses a random Saturation and Hue, then turns the brightness all the way up, all the way down, and then starts over again.

//these have to be attached to PWM pins
int REDPin = 6;
int GREENPin = 5;
int BLUEPin = 3;


int vIncrement = 5;

unsigned int h = 0, s = 0, v = 0; //hsv
unsigned int r, g, b, hh, c, x, m;


void setup()
{
  pinMode(REDPin, OUTPUT);
  pinMode(GREENPin, OUTPUT);
  pinMode(BLUEPin, OUTPUT);
  randomSeed(analogRead(0));
  Serial.begin(9600);
}

void loop()
{
  v = v + vIncrement;

  if (v <= 0){
    h = random(0, 360);
    hh = h / 60;
    s = random(0, 255);
  }
  
  if (v <= 0 || v >= 255)    // reverse the direction of the fading
  {
    if (v > 0x10000) //handle overflow - unsigned int
      v = 0;
    vIncrement = -vIncrement;
    v = constrain(v, 0, 255);
  }
  
  c = (v * s) / 256;
  x = (c * (60 - abs(h % 120 - 60))) / 60;
  m = v - c; // 44
  
  switch(hh){
    case 0:
      r = c + m;
      g = x + m;
      b = m;
      break;
    case 1:
      r = x + m;
      g = c + m;
      b = m;
      break;
    case 2:
      r = m;
      g = c + m;
      b = x + m;
      break;
    case 3:
      r = m;
      g = x + m;
      b = c + m;
      break;
    case 4:
      r = x + m;
      g = m;
      b = c + m;
      break;
    case 5:
      r = c + m;
      g = m;
      b = x + m;
      break;
    default:
      r=g=b=m;
  }
  
  
  r = constrain(r, 0, 255);
  g = constrain(g, 0, 255);
  b = constrain(b, 0, 255);
  analogWrite(REDPin, r);
  analogWrite(GREENPin, g);
  analogWrite(BLUEPin, b);

  delay(20);  // wait for 20 milliseconds to see the dimming effect
}

There are lots of algorithms out there for converting HSV to RGB, but I didn't like all the converting between float and int. This one does it only using unsigned ints (my Arduino uses 16-bit numbers, so I needed them unsigned to prevent overflow). It was based on the Wikipedia HSV page.

(For this algorithm, S, V, R, G, B are in [0, 255] and H is in [0, 360])

No comments: