Thursday, March 17, 2011

RGB LED Part II

After some absence, I finally got some weekend time to play with my electronics.
Now that I have 100 new RGB LEDs, it’s time for some experiments.

I wanted to know how to control the colors emitted by this LEDs so here’s how I did it.

First I searched for a datasheet and found this one on Sparkfun.
According to it, the recommended current is 20mA, and the voltages are 2.0V, 3.2V and 3.2V for red, green and blue. As I wrote on my last post, each color has a different lead, and there is another for Ground (GND). These are common cathode LEDs, as it receives energy on the leads for the colors and all that energy is returned to the circuit on a single lead.

As I source all my projects with the Arduino connected to the laptop (as it already is a regulated power source), I calculated the resistors for a 5V source power.

V=R.I
Red --> (5 – 2.0) / 0.20 = 150 Ohm
Green / Blue --> (5 – 3.2) / 0.20 = 90 Ohm (The closest I have is 100 Ohm)


Connecting all wires, we can see that 3 different tiny LEDs lit up inside our 5mm RGB LED as you can see below.

Also we can see that we can’t count on a mixed color far from the LED, as the three parts point to different directions, although there might be some ways to try to improve that situation.

So the LED lights up. Big deal! Let’s play some more...

The next step is to be able to combine the three colors into making new colors.

First I tried to make a simple program on the Arduino using a (very, very poor) simulated PWM. Basically I would light up only one color at a time and tried different delay() times, to control the ‘quantity of color embedded’ in the final result. That idea came from the LED matrix project, as some kind of multiplexing.
Please, don’t waste your time on something like this.

After some online searching, I saw that the best way is to use ‘real’ PWM, as in using the PWM pins in the Arduino and analogWrite() the value (0-255) for each color. This controls the voltage at the pin, altering the luminosity of the LED. It is best to keep all color lit at the same time (not using delay()).

So now we can programmatically define the color we want to obtain, in theory. Again, with clear LEDs, it is kind of hard to observe a good mix of the light emitted by the three ‘sub-LEDs’.

But isn’t it cooler to be able to mess with those values by hand? So enter the potentiometers (pots).
My first try was to use 3 pots, to control each color. As two of them aren’t ‘breadboard friendly’, you can see below what a mess it is to connect it all.


But then I thought: “What a good opportunity to try to use push buttons.”
So I replaced the 3 potentiometers by 3 push buttons, and altered the Arduino program to cycle through the values for each color.
A simple control to avoid altering the values too much in one push was to have a small delay() after the digitalRead() of each button.




You might notice some resistors connected from each button to GND in parallel with the reader pins of the Arduino.
Those are push-down resistors.

And here is the code:
int R = 9;
int G = 10;
int B = 11;

int vR = 0;
int vG = 0;
int vB = 0;

int T = 200;
int d = 15;

void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
pinMode(7, OUTPUT);

pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);

digitalWrite(7, HIGH);
}

void loop() {
if(digitalRead(2) == HIGH)
{
vR+=d;
if(vR>l)
vR=0;

delay(T);
}

if(digitalRead(3) == HIGH)
{
vG+=d;
if(vG>l)
vG=0;

delay(T);
}

if(digitalRead(4) == HIGH)
{
vB+=d;
if(vB>l)
vB=0;

delay(T);
}

analogWrite(R, vR);
analogWrite(G, vG);
analogWrite(B, vB);
}


So to end it, I wanted to create a demo to cycle to all colors as simply as possible. I found ‘Hue-controllable RGB LED lamp‘ that shows how to cycle through the colors using only a Hue value.
I tried to use the conversion code directly from http://www.easyrgb.com/math.php?MATH=M21#text21, but all the values were quite wrong, so I lazily used the code akgraphics provided on the first post.
As the code was kind of slow because of lots of (unnecessary) math, I reduced it to:

void setup() // run once, when the sketch starts
{
//Serial.begin(9600); // set up Serial library at 9600 bps
}

void h2rgb(float H, int& R, int& G, int& B) {
int var_i;
float S=1, V=1, var_1, var_2, var_3, var_h, var_r, var_g, var_b;

var_h = H * 6;
if ( var_h == 6 ) var_h = 0; //H must be < 1
var_i = int( var_h ) ; //Or ... var_i = floor( var_h )

//var_1 = V * ( 1 - S );
var_1 = 0;

//var_2 = V * ( 1 - S * ( var_h - var_i ) );
var_2 = ( 1 - ( var_h - var_i ) );

//var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) );
var_3 = ( var_h - var_i );

if ( var_i == 0 ) {
var_r = V ;
var_g = var_3 ;
var_b = var_1 ;
}
else if ( var_i == 1 ) {
var_r = var_2 ;
var_g = V ;
var_b = var_1 ;
}
else if ( var_i == 2 ) {
var_r = var_1 ;
var_g = V ;
var_b = var_3 ;
}
else if ( var_i == 3 ) {
var_r = var_1 ;
var_g = var_2 ;
var_b = V ;
}
else if ( var_i == 4 ) {
var_r = var_3 ;
var_g = var_1 ;
var_b = V ;
}
else {
var_r = V ;
var_g = var_1 ;
var_b = var_2 ;
}

R = (1-var_r) * 255; //RGB results = 0 ÷ 255
G = (1-var_g) * 255;
B = (1-var_b) * 255;
}

void loop() // run over and over again
{
for(int val=0;val<1024;val++)
{
//Serial.println(val);
float h = ((float)val)/1024;
int h_int = (int) 360*h;
int r, g, b;
h2rgb(h,r,g,b);

analogWrite(9, r);
analogWrite(10, g);
analogWrite(11, b);

delay(10);
}
}

No comments:

Post a Comment