Introduction: Why RGB Full-Color LEDs?

“A single-color LED isn’t enough” — if you’ve felt that way, RGB LEDs are the answer.

While a regular LED emits only one color, an RGB full-color LED combines red, green, and blue in a single component. Mix them freely and you get — in theory — 16,777,216 colors. Lighting effects, status indicators, illumination projects: the applications are unlimited.

This guide covers two stages of RGB LED control with Arduino’s PWM (Pulse Width Modulation):

STEP 1: 8-color digital output
→ Use digitalWrite() for ON/OFF control; understand additive color mixing

STEP 2: 16.7 million color gradient with PWM
→ Use analogWrite() for 256-step brightness control per channel; achieve smooth color transitions

Arduino UNO R4 Minima

Arduino UNO R4 Minima

Arduino UNO R4 Minima starter kit

Arduino UNO R4 Minima starter kit


RGB LED Structure and How It Works

Three LED Chips in One Package

An RGB full-color LED contains three LED chips inside a single transparent package:

  • R (Red): ~620–630 nm wavelength
  • G (Green): ~515–530 nm wavelength
  • B (Blue): ~460–470 nm wavelength

These are the three primary colors of light — the basic components that human cone cells detect.

RGB LED circuit diagram

Internal structure of an RGB full-color LED (common-cathode type)

Common-Cathode vs. Common-Anode

RGB LEDs come in two configurations:

Type Common Pin Each color pin Arduino control
Common-Cathode GND (−) HIGH = ON digitalWrite(R, HIGH)
Common-Anode VCC (+) LOW = ON digitalWrite(R, LOW)

This guide uses common-cathode. Each color’s anode (+) connects to an Arduino digital pin; the common cathode (−) connects to GND.

Additive Color Mixing

Combining RGB channels produces these colors:

R G B Result
Red
Green
Blue
Yellow
Magenta
Cyan
White
Off

(● = ON, ○ = OFF)

That’s 2³ = 8 combinations. But if you control each channel’s brightness, you get 256 × 256 × 256 = 16,777,216 colors — which is what PWM enables.


Parts List

Part Spec Qty Notes
Arduino UNO R3 or R4 Minima 1 Must have PWM pins
RGB full-color LED Common-cathode, 4 pins 1 5mm diffused recommended
Resistor 220Ω (1/4W) 3 One per color channel
Breadboard Standard size 1
Jumper wires Male-to-male 4

STEP 1: 8-Color Control with Digital Output

Circuit Design

Start simple — just ON/OFF per channel.

RGB LED circuit and schematic

Basic RGB LED circuit (common-cathode)

Key circuit points:

  1. Current-limiting resistors are mandatory
    Connect a 220Ω resistor in series with each color channel. Arduino UNO outputs 5V; RGB LED forward voltages are ~2.0V (red) and ~3.2V (green/blue). Without resistors, excess current destroys the LED.

    Current calculation:
    Red:    I = (5V − 2.0V) / 220Ω ≈ 13.6 mA
    Green/Blue: I = (5V − 3.2V) / 220Ω ≈ 8.2 mA
    Both well under the 20 mA LED rating ✓
    
  2. Use PWM-capable pins from the start
    For STEP 2, use PWM pins (Arduino UNO: 3, 5, 6, 9, 10, 11) so you don’t need to rewire later:

    • Pin 9 → Red (R)
    • Pin 10 → Blue (B)
    • Pin 11 → Green (G)
  3. Common cathode goes to GND
    The longest pin on the RGB LED (common cathode) connects to Arduino GND.

Sample Code: 8-Color Cycle

#define R 9    // Red
#define G 11   // Green
#define B 10   // Blue

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

void loop() {
   // 1. Red
   digitalWrite(R, HIGH); delay(500); digitalWrite(R, LOW);
   // 2. Green
   digitalWrite(G, HIGH); delay(500); digitalWrite(G, LOW);
   // 3. Blue
   digitalWrite(B, HIGH); delay(500); digitalWrite(B, LOW);
   // 4. Yellow (Red + Green)
   digitalWrite(R, HIGH); digitalWrite(G, HIGH);
   delay(500);
   digitalWrite(R, LOW); digitalWrite(G, LOW);
   // 5. Cyan (Green + Blue)
   digitalWrite(G, HIGH); digitalWrite(B, HIGH);
   delay(500);
   digitalWrite(G, LOW); digitalWrite(B, LOW);
   // 6. Magenta (Red + Blue)
   digitalWrite(R, HIGH); digitalWrite(B, HIGH);
   delay(500);
   digitalWrite(R, LOW); digitalWrite(B, LOW);
   // 7. White (all on)
   digitalWrite(R, HIGH); digitalWrite(G, HIGH); digitalWrite(B, HIGH);
   delay(500);
   // 8. Off
   digitalWrite(R, LOW); digitalWrite(G, LOW); digitalWrite(B, LOW);
   delay(500);
}

Demo Video

Troubleshooting

Symptom Cause Fix
LED doesn’t light at all Wiring error or reverse polarity Verify cathode (longest pin) is at GND
One color doesn’t work Broken wire or missing resistor Re-check that channel’s connections
LED burns out immediately Missing current-limiting resistor Always use 220Ω on each channel
Colors look mixed Diffused LED characteristic Normal — this is additive mixing as expected

STEP 2: 16.7 Million Colors with PWM

How PWM Works

Digital pins only output HIGH (5V) or LOW (0V). But by switching rapidly between the two states and varying the ON-time ratio (duty cycle), you can produce an effective analog voltage. That’s PWM (Pulse Width Modulation).

Duty cycle   0% (always LOW)  → effective voltage 0V   (off)
Duty cycle  50% (half and half) → effective voltage 2.5V (mid brightness)
Duty cycle 100% (always HIGH) → effective voltage 5V   (full brightness)

Arduino UNO’s PWM has 8-bit (256-step) resolution, giving each channel a 0–255 range:

256 (R) × 256 (G) × 256 (B) = 16,777,216 colors

Using analogWrite()

analogWrite(pin, value);  // value: 0 (off) to 255 (full brightness)

Important: On Arduino UNO, PWM is only available on pins 3, 5, 6, 9, 10, 11.

Three-Phase Sine Wave for Smooth Color Gradients

Drive each channel’s brightness along a sine curve, with each channel’s phase offset by 120 degrees (85 steps). The result is a smooth rainbow cycle.

RGB LED output phases

Three-phase sine wave phase control (each channel offset by 85 steps)

Phase offsets:

  • Red (R): 0° (reference)
  • Green (G): 120° (offset by 85 steps)
  • Blue (B): 240° (offset by 170 steps)

When red is at peak brightness, green and blue are at intermediate or low brightness. As time passes, the brightness balance continuously shifts, producing a cycling gradient: red → orange → yellow → green → cyan → blue → purple → red…

Sample Code: 16.7M Color Gradient

#define R 9    // Red
#define G 11   // Green
#define B 10   // Blue

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

void loop() {
   uint8_t r, g, b;
   uint8_t i;

   for (i = 0;; i++) {  // infinite loop; i overflows naturally as uint8_t
      // Scale sin() output from [-1, +1] to [0, 255]
      r = (sin(2 * 3.14 / 255 * i) + 1) * (255 / 2);
      g = (sin(2 * 3.14 / 255 * (i + 85)) + 1) * (255 / 2);   // 120° phase offset
      b = (sin(2 * 3.14 / 255 * (i + 170)) + 1) * (255 / 2);  // 240° phase offset

      analogWrite(R, r);
      analogWrite(G, g);
      analogWrite(B, b);
      
      delay(20);  // update every 20ms → one full cycle ≈ 5 seconds
   }
}

Code breakdown:

  1. Smooth brightness with sine function

    • 2 * 3.14 = 2π (one full cycle)
    • / 255 completes the cycle in 255 steps
    • i cycles through 0–255 via uint8_t overflow
  2. Scaling −1…+1 to 0…255

    • + 1 shifts range to 0…2
    • * (255 / 2) expands to 0…255
  3. Why 85 steps of phase offset

    360° / 3 channels = 120°
    255 steps × (120 / 360) ≈ 85 steps
    

Demo Video

What to check:

  • ✅ Colors transition smoothly, not abruptly
  • ✅ Cycling: red → orange → yellow → green → blue → purple
  • ✅ One full cycle in approximately 5 seconds (255 steps × 20 ms)
  • ✅ No visible flicker (PWM at ~490/980 Hz is invisible to the human eye)

Customization Ideas

Adjust Gradient Speed

delay(5);   // fast (~1.3 sec/cycle) — disco effect
delay(20);  // default (~5 sec/cycle) — calm ambiance
delay(100); // slow (~25 sec/cycle) — meditative

Sensor-Driven Color

Map an analog sensor value (temperature, light) to RGB brightness:

int sensorValue = analogRead(A0);  // 0–1023
int brightness = map(sensorValue, 0, 1023, 0, 255);
analogWrite(R, brightness);
analogWrite(G, 255 - brightness);  // inverse
analogWrite(B, 128);               // fixed

Multiple RGB LEDs

  • Shift register (74HC595): control many LEDs with few pins
  • WS2812B (NeoPixel): individually control hundreds of LEDs over a single wire

Summary

What You Learned

Additive color mixing — RGB combinations produce 8+ colors
8-color digital controldigitalWrite() basics, common-cathode wiring
PWM with analogWrite() — 256-step brightness → 16.7M colors
Three-phase sine wave control — mathematical approach to beautiful gradients

Where PWM Goes Next

PWM techniques apply far beyond LED control:

  • DC motor speed control — vary rotation speed
  • Servo motor control — angle positioning (internally uses PWM)
  • Speaker drivingtone() for melody playback
  • Dimmer circuits — stepless brightness control for white LEDs


FAQ

Q1. I have a common-anode RGB LED. What changes?
Connect the anode (longest pin) to 5V/VCC, and connect each color’s cathode to Arduino pins. Logic is inverted: digitalWrite(R, LOW) turns it on; analogWrite(R, 255 - brightness) for PWM control.

Q2. Can I change the PWM frequency?
Yes, but it requires direct timer register manipulation. For most uses, the defaults (pins 5/6 ≈ 980 Hz; pins 3/9/10/11 ≈ 490 Hz) are fine.

Q3. How do I synchronize multiple RGB LEDs to the same color?
Connect the corresponding color pins in parallel. Keep total current under Arduino’s 40 mA per-pin limit; use a transistor driver if needed.

Q4. The LED flickers when running on batteries.
Insufficient power supply. Full-brightness RGB LEDs draw up to 60 mA (20 mA × 3). Use 4× AA batteries (6V) with a regulator, or a 5V USB power bank.

Q5. I want to control many LEDs individually.
Use addressable LEDs like WS2812B (NeoPixel) or APA102 — hundreds of individually controllable full-color LEDs over a single data wire.