A Simple Sketch to Display Primary Colors

The following sketch causes an RGB LED to shine in red light, then green light,
then blue light, each for 0.5 seconds.

When you run the code, you will be able to see the three individual LEDs
that are packaged within the RGB LED.

To control the brightness of any of the 3 LEDs inside an RGB LED, you must
write out a value between 0 and 255 to the pin controlling the R, G,
or B LED you want to change. The Arduino function to do this is:

analogWrite(pinNumber, value);

The variable pinNumber refers to the Arduino data pin where you attached one of
the 3 shorter legs of the RGB LED.

The variable value is an unsigned integer in the range 0 to 255.

Internally, the function analogWrite turns the voltage on pinNumer to
HIGH then LOW values very rapidly. If the amount of time spent in a HIGH
state is long, then the voltage level sensed by something attached to that pin
is close to 5V. If the amount of time spent in a LOW state is long, then
the voltage level sensed by an attached device is close to 0V. This
process is called “pulse width modulation”.

The code below states that the RGB LED being used is “Common Cathode” type.
In this case, the default voltage level of any of the pins of the RGB is HIGH
(i.e., 5V), and the only way for the Arduino to make it fainter is to send
a LOW value.

If you have a “common cathode” RGB LED”, then change the statement
that says

#define COMMON_ANODE true

so that it reads:

#define COMMON_ANODE false

In this case, the voltage level of one of the RGB pins is LOW, and you
would make it brighter by sending it a HIGH value.

/* This packet simply turns on the Red, Green, and Blue components of an
 *  RGB LED separately.
 */

#define BLUE 11
#define GREEN 10
#define RED 9

#define COMMON_ANODE true

void setup() {
  if (COMMON_ANODE) {
    dark = 255;
    bright = 0;
  } else {
    dark = 0;
bright = 255;
  }

  pinMode(BLUE, OUTPUT);
  analogWrite(BLUE, dark);
  pinMode(GREEN, OUTPUT);
  analogWrite(GREEN, dark);
  pinMode(RED, OUTPUT);
  analogWrite(RED, dark);
}

void loop() {
  analogWrite(RED, bright);
  delay(500);
  analogWrite(RED, dark);
  analogWrite(GREEN, bright);
  delay(500);
  analogWrite(GREEN, dark);
  analogWrite(BLUE, bright);
  delay(500);
  analogWrite(BLUE, dark);
}

A Program to Display the Colors of the Rainbow (in order)

RGB LEDs are frequently used to make light displays, where the color of the light
varies smoothly from one color to another. RGB values are not useful in these
applications because there is no simple way to change the RGB values to create a
smoothly-varying range of colors.

A different color system, HSV (for “Hue-Saturation-Value”) is better for these
applications, because the color (“hue”) can be varied smoothly through all
the visible colors. The other two components, S (saturation) and V (for “value” or
“brightness”) can be held constant at some (user-defined) settings.

Despite the convenience of the HSV system, RGB LEDs still need to get input
values in terms of R, G, and B, so any HSV color the user might select
has to be converted to its RGB equivalent before the RGB LED will respond.
The sketch below includes a function (hsvToRGB) which changes any input HSV
value to the corresponding RGB value. It is based on the
RGBConverter library.

/* This packet causes the combined light of the red, green, and blue LEDs within
 * an RGB LED to produce each of the colors of the rainbow, varying smoothly
 * from purple, to blue, to green, to yellow, to orange, to red.
 */

#define BLUE 11
#define GREEN 10
#define RED 9

#define COMMON_ANODE true

uint8_t dark;
uint8_t bright;
uint8_t rgb[3];

void setup() {
  if (COMMON_ANODE) {
    dark = 255;
    bright = 0;
  } else {
    dark = 0;
    bright = 255;
  }
  pinMode(BLUE, OUTPUT);
  analogWrite(BLUE, dark);
  pinMode(GREEN, OUTPUT);
  analogWrite(GREEN, dark);
  pinMode(RED, OUTPUT);
  analogWrite(RED, dark);
}

void loop() {
  double s=1.0;        // use fully saturated colors
  double tilt=0.5;     // 0 < tilt < 1; low values enhance blue light relative to red

  /* At first, the loop below might seem backwards.  But by causing the value of the 
    "hue" component to vary from 360 down to 0, the resulting colors range from violet to red.
    If the loop went in the opposite direction, e.g., for (int i=0; i<360; i++),
then the colors would begin with red and end with violet (which feels even more backwards).
  */
  for (int i = 360; i > 0; i--) {
    double h = i/360.; // the hsvToRGB function expects all input in the range 0 to 1.
    double v = tilt*h + (1-tilt);  // This depresses the 'v' or brightness component of colors near
                               // the end of the color wheel.  It's really a form of "color correction".
    hsvToRGB(h, s, v);
    analogWrite(RED,   rgb[0]);
    analogWrite(GREEN, rgb[1]);
    analogWrite(BLUE,  rgb[2]);
    delay(50);
  }
  delay(200);

  analogWrite(RED,   dark);
  analogWrite(GREEN, dark);
  analogWrite(BLUE,  dark);
  delay(1500);
}

/* This function was adapted from RGBConverter at http://github.com/ratkins/RGBConverter. */
void hsvToRGB(double h, double s, double v) {
  double r, g, b;
  int i = int(h*6);
  double f = h * 6 - i;
  double p = v * (1 - s);
  double q = v * (1 - f * s);
  double t = v * (1 - (1 - f) * s);

  switch(i % 6){
      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;
      case 5: r = v, g = p, b = q; break;
  }

  if (COMMON_ANODE) {
    rgb[0] = 255 - (uint8_t) (r * 255);
    rgb[1] = 255 - (uint8_t) (g * 255);
    rgb[2] = 255 - (uint8_t) (b * 255);
  } else {
    rgb[0] = (uint8_t) (r * 255);
    rgb[1] = (uint8_t) (r * 255);
    rgb[2] = (uint8_t) (r * 255);
  }  
}