Project showcase
RGB Light Control with Arduino

RGB Light Control with Arduino © MIT

Set up an RGB LED to phase through the colors of the rainbow, or use twist knobs to make a custom color.

  • 7 respects

Components and supplies

Apps and online services

About this project


The goal of this project was to familiarize myself with RGB LEDs and the use of pulse width modulation (PWM) to control the overall brightness of an LED as well as its color composition.

If you're unfamiliar with PWM or duty cycles, I suggest you take a look at my write-up about them to get a deeper understanding of how things will be working in this project. PWM is used to simulate analog signals in order to allow LEDs to output a variable brightness.

Dimming a Red LED

I started off by trying to dim a single LED before delving into more complicated things. In order to accomplish this, I built an LED circuit as seen in the schematic below.

I controlled the brightness of the LED by modifying the duty cycle of the PWM pin. After setting up the code to supply an output signal to pin 3, I used the function analogWrite() to set the duty cycle. The function accepts integers from 0 to 255, which correspond to duty cycles of 0-100%. To test that everything works, I tried a 100% duty cycle, and saw that the LED was glowing quite brightly. Reducing the duty cycle to 50% (127) saw a noticeable reduction in brightness. You can see this code in the attachments below.

I still had a button wired up from my project on debouncing buttons and switches, so I decided to include it in this design as well. I set up the code to have the Arduino gradually reduce the brightness with every click until the LED was off, and then to start over. This code is in the attachments.

By setting WaveForms Live to trigger on the falling edge of the button signal, I was able to capture the PWM duty cycles change.

You'll notice in the screenshots below that the change in duty cycle isn't instantaneous. Instead, there is a stabilization period during which the duty cycle is somewhere between the previous and new values. This doesn't matter with LED brightness, but other PWM applications may see unwanted behavior due to this effect.


RGB LEDs are actually 3 LEDs built into a single compact package. They closely resemble regular LEDs, except they have 4 legs instead of 2. The long leg is the common anode or common cathode, depending on which type you have, and the other three are connected to each color the LED can output: red, green, and blue. Typically the short leg that is separated from the others is red, the middle is green, and the outside is blue. Refer to the image below.

To configure the circuit for controlling the LED color, I needed to have individual PWM pins attached to each of the colors. By varying the relative brightness of each of the three component colors with PWM, the LED can create a wide range of colors, spanning the visible spectrum. As with the red LED earlier, Arduino pin 3 is attached to the base of the transistor. However, this time it is functioning only as an on/off signal. The PWM signals, and thus the brightness of each LED, will be controlled by the three pins connected to the color legs of the LED. See the schematic below.

Note: since my RGB LED is a common anode, its response to the PWM signals is inverse - a 100% duty cycle would cause the LED to be constantly off, and a 0% duty cycle would cause it to be constantly on. If the LED is a common cathode, it would function like a regular LED, with a 100% duty cycle causing it to be on.

Setting a Consistent Brightness

Running all three colors at full brightness (0% duty cycles) made the LED painfully bright, but it did demonstrate that it can create white light. I wanted to make the LED display any color I wanted, but at a consistent, viewable brightness. To make the brightness consistent regardless of the color being generated, I needed to have the same total amount of power supplied to the three colors in the LED even as the as the color ratios changed.

I found that the best way for me to think about power was in terms of a value out of 255. Then, I need to pick a sum of duty cycles, shared by the three colors. For example, if I made the sum of the duty cycles 100 (out of 255), and wanted a white light, I would set each color to 33. This would be the same brightness as if I set the red to 100 and the other two to 0, or made yellow with 50 red, 50 green, and 0 blue.

Ultimately I found that a total out of 30 made for the best viewing brightness.

To test my understanding of the color control, I had the code cycle through the 6 base colors of the rainbow, based off the RGB values listed in the Simple English Wikipedia article about rainbows. Here are each of the colors, normalized to a duty cycle sum of 30.

Color Adjustment with OpenScope

At this point I realized red was over-represented in most of the colors. In the pictures above, you may have noticed the yellow had a red tint to it, even though red and green are supposed to be equally represented in that color. I set the Arduino to output a yellow color, and, according to print statements in the code, both pins were receiving the same PWM duty cycle command. I decided to check the signals with the OpenScope to see what was really going on.

Looking at the signals with an oscilloscope revealed that the duty cycles were indeed equal, but the voltage drop across the LEDs was not the same. This prompted me to look up a datasheet for an RGB LED, where it became apparent that my problem was stemming from the fact that my green and blue LEDs were not receiving the same amount of current as the red. Since green and blue LEDs have a larger voltage drop than red, they require a smaller resistance to have the same current flowing through them. With 150Ω resistors on all three, I had about half the current flowing through blue and green as red.

After putting in correct resistances (approximately 55Ω for each green and blue, 110Ω for red), I took pictures of the rainbow colors again. As you can tell, the colors are more balanced, namely the orange and yellow don't have a red tint.

Mixing Custom Colors

Finally, I wanted to be able to make the LED output any color, based on a mixture of the red, green, and blue components. I set up three potentiometers to function as knobs, putting them into voltage dividers with 10kΩ resistors. Using the analog input pins to measure the voltages in the dividers, the Arduino calculates the ratio of the three colors and sets the PWM duty cycles based on the brightness discussed above. This allowed me to twist the knobs and get the ratio of the three knobs expressed as the color that ratio generates.

Below are WaveForms Live screenshots of the red and green PWM signals as I change the ratio from 1:0 (red) to 1:1 (yellow) to 0:1 (green). As you can see, the sum of the two pulse widths remains the same as the ratios change. By using cursors it can be ascertained that the pulse width sum is 240µs. The top line is the red signal and the bottom line the green signal.

The schematic below shows how to wire up the potentiometers, and code to control this circuit is included in the attachments section. The code for the rainbow and color selection modes is all in one file. To choose between these two modes, just change which function is commented out.


Basic Red LED Arduino
Set the brightness of the LED through code by changing the dutyCycle variable.
//Set the duty cycle percentage: change to any value 0-100
float dutyCycle = 50;

//set I/O pins
//pin 3 will connect to the base of the NPN transistor and set the LED brightness
int LED = 3;

//set the duty cycle percentage (0-100)
float dutyCycle = 50;

void setup() {
   pinMode(LED, OUTPUT);
   digitalWrite(LED, HIGH);


void loop() {
  analogWrite(LED, ((float)(dutyCycle/100))*255);

Brightness ToggleArduino
Based on a button click, the code switches through a set number of brightness levels between full bright and off. Change number of levels by changing the numSteps variable.
//Set the number of steps between full bright and off by changing to any value
//greater than zero
float numSteps = 4;

//keep track of which step we're on
float stepNum = numSteps;

//set I/O pins
//pin 3 will connect to the base of the NPN transistor and set the LED brightness
int LED = 3;

//pin 4 will be used to monitor the button
int SWTCH = 4;

void setup() {
   //set pin modes
   pinMode(LED, OUTPUT);
   pinMode(SWTCH, INPUT);

   //initially set LED to full brightness
   digitalWrite(LED, HIGH);

   //initiallize serial interface to print the PWM value for each button click

void loop() {
  //monitor the switch pin for a drop in voltage
  if(digitalRead(SWTCH) == 0){

void toggle(){
  //wait for the signal to stabilize
  //make sure the inital drop wasn't random noise
  if(digitalRead(SWTCH) == 0){
    //reduce stepNum by 1

    //reset numSteps if it's past zero
    if(stepNum < 0){
      stepNum = numSteps;

    //set new PWM duty cycle
    analogWrite(LED, (stepNum/numSteps)*255);

    //print new duty cycle to serial monitor
    //wait for the signal to go high again before doing anything else
    while(digitalRead(SWTCH) == 0){
    //wait for the signal to stabilize
Rainbow/Custom Color LEDArduino
Iterates through 6 colors in the rainbow with 1s delay for each color, or allows you to set the color with potentiometer dials. In loop(), switch commenting between setColor() and rainbowStrobe() to toggle the two modes.
//set I/O pins
//pin 3 will connect to the base of the NPN transistor and trigger the LED on/off
int LED = 3;

//digital pins 9, 10, 11 are PWM enabled, so they will be used to sink the current for the Red, Green, and Blue LEDs in the RGB LED
int red = 9;
int green = 10;
int blue = 11;

//analog pins A0-A2 will be used for potentiometer input
int rLevel = A0;
int gLevel = A1;
int bLevel = A2;

//define the RGB values for each color of the rainbow: red, orange, yellow, green, blue, violet
float rainbowArrayRGB[][6] = {{255,255,255,0,0,139},{0,127,255,255,0,0},{0,0,0,0,255,255}};

//array to indicate which PWM line to set the values to
int colorsArray[] = {red, green, blue};

//light intensity
int brightness = 30;

//track which mode LED is in
bool toggle;

void setup() {
  //set pin input/output modes
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(rLevel, INPUT);
  pinMode(gLevel, INPUT);
  pinMode(bLevel, INPUT);

  //initially turn on the LED
  digitalWrite(LED, HIGH);

void loop() {
  //swap comments between these two functions to access one or the other mode: color selection or rainbow.
//  rainbowStrobe();


void setColor(){
  float colorLevels[3] = {analogRead(rLevel), analogRead(gLevel), analogRead(bLevel)};
  float levelSum = 0;
  for(int i = 0; i < sizeof(colorsArray); i++){
    if(colorLevels[i] > 1024){
      colorLevels[i] = 1024;
    else if(colorLevels[i] < 8){
      colorLevels[i] = 0;
    levelSum += colorLevels[i];

  for(int i = 0; i < sizeof(colorsArray); i++){
    analogWrite(colorsArray[i], 255 - brightness*(colorLevels[i]/levelSum));

void rainbowStrobe(){
  for(int i = 0; i < sizeof(rainbowArrayRGB[0])/sizeof(rainbowArrayRGB[0][1]); i++){
    for(int j = 0; j < sizeof(rainbowArrayRGB)/sizeof(rainbowArrayRGB[0]); j++){
      analogWrite(colorsArray[j], 255-brightness*(rainbowArrayRGB[j][i]/(rainbowArrayRGB[0][i]+rainbowArrayRGB[1][i]+rainbowArrayRGB[2][i])));


Similar projects you might like

Control an LED with the Remote Control

Project showcase by Nicholas_N

  • 23 respects

Control RGB LED using Bluetooth

Project showcase by kamatalaashish

  • 1 comment
  • 16 respects

Control a RGB Led using Arduino and a smartphone's camera

Project tutorial by Mr robot Maker

  • 1 comment
  • 10 respects

WIZnet S2E Light Control

Project tutorial by Team S2ELighting

  • 7 respects

Control your light system with your voice

Project tutorial by Maha Raafat

  • 160 respects

RGB Camera Backlight Control With Android Mobile

Project tutorial by DIY Partners

  • 1 comment
  • 8 respects
Add projectSign up / Login