RGB LED, voltages, diffuser, color correctness

I just interfaced an RGB LED with the arduino, and I have some questions.

The specs of the LED state the following voltages for each color:

red: 1,7V
green: 2,2V
blue: 3V
I=20 mA

given the 5V output of the arduino output pins, what resistor would I have to but between the output pin and the LED? sorry for asking such lame questions, but electronics wasn’t my major :slight_smile:

also, what light diffuser would you guys recommend, to diffuse the light, so that it’s not so stingy?

and: did anyone have a chance to calibrate an RGB LED to be ‘about’ color correct? for example, it seems to me that the green LED is way weaker than the other two. also, there are two blue LEDs in the RGB LED - what would be the reason for that?

For calculating diode current…

The Arduino pins drive at 5V, so the sum of the diode and resistor voltages will be 5.
Consider the blue led which says it drops 3V, that means the resistor will drop 2V.
Ohm’s law says: V=IR… that is… volts = amps * ohms.
Since we know V and I we can solve for R…
V = IR
2v = 0.020a * Rohms
100(v/a) = 100 ohms
A 100 ohm resistor will do just fine. (Maybe one size larger so you don’t go out of spec if the resistor is on the low side of the tolerance band.)

I haven’t tried it, but maybe a cotton ball would make a nice diffuser. Shining on a bit of frosted glass would be a more traditional way.

Calibrating is harder. You might assume that the LED is made so that 20ma into each color is a pretty white color, but that probably won’t be true. It will be off somehow. You could increase the resistor for whatever the dominant color is until you get a white that you like.

Also to be aware of… and I could swear I’d stuck it in the forum, but I can’t find it to reference…
Human vision is not linear. If you want to control, say the red LED and cut its brightness in half, then cutting the current in half is not going to do it. The perceived brightness is sort of close to the log() of the current. I use this lookup table to convert an “intended visual brightness” to a “current to the LED”. It is a little lumpy, but close.

#include <avr/pgmspace.h>
// This is is an exponential function, scaled and shifted so 0..255 maps onto 0..255
// For i from 0 to 255... round( pow( 2.0, i/32.0) - 1)
// We are going to use it to compensate for the nonlinearity of human vision.
static const PROGMEM uint8_t delog[] = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1, 
  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2, 
  2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3, 
  3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   5, 
  5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,   6,   6,   7,   7, 
  7,   7,   7,   8,   8,   8,   8,   8,   9,   9,   9,   9,   9,  10,  10,  10, 
  10,  11,  11,  11,  11,  12,  12,  12,  12,  13,  13,  13,  14,  14,  14,  15, 
  15,  15,  16,  16,  16,  17,  17,  18,  18,  18,  19,  19,  20,  20,  21,  21, 
  22,  22,  23,  23,  24,  24,  25,  25,  26,  26,  27,  28,  28,  29,  30,  30, 
  31,  32,  32,  33,  34,  35,  35,  36,  37,  38,  39,  40,  40,  41,  42,  43, 
  44,  45,  46,  47,  48,  49,  51,  52,  53,  54,  55,  56,  58,  59,  60,  62, 
  63,  64,  66,  67,  69,  70,  72,  73,  75,  77,  78,  80,  82,  84,  86,  88, 
  90,  91,  94,  96,  98, 100, 102, 104, 107, 109, 111, 114, 116, 119, 122, 124, 
  127, 130, 133, 136, 139, 142, 145, 148, 151, 155, 158, 161, 165, 169, 172, 176, 
  180, 184, 188, 192, 196, 201, 205, 210, 214, 219, 224, 229, 234, 239, 244, 250, 

};

// Watch that PROGMEM and how we need to use pgm_read_byte() to get to 
// the data. PROGMEM forces the table to stay in flash. You don't have enough
// RAM to go copying big data structures like this into RAM. You have to use pgm_read_byte()
// or a similar function to get to data in the flash.

// then in your code you can do...
uint8_t intendedbrightness;
...
analogWrite( something, pgm_read_byte(delog+intendedbrightness) );