RGB LED/Mixing/05. Mixing with PWM
Mixing · 05 of 9

Mixing with PWM

Each colour pin can do PWM, so each colour can be anywhere from off to full. Three duty cycles make one mixed colour: the diffuser blends the three chips and your eye adds the light. What it adds up to is not what the numbers suggest.

Three duty cycles

Mixing with PWM
Red255
Green120
Blue0
Your board
Red light
64 %
Green light
36 %
Blue light
0 %
Each pin is only ever fully on or fully off; the numbers set how much of each period it is on. The diffuser in the LED's white body blends the three dies, and your eye adds the light: the model calls this mix orange. The percentages under the drawing are each colour's share of the light, which is not the share of the numbers — green gives far more light per step than blue.

Each slider is one analogWrite value. A pin is still only ever fully on or fully off. The value sets what fraction of each period it spends on, and the LED flashes faster than an eye can follow, so you see the average. Brightness is a duty cycle covers that for one LED, and nothing about it changes with three.

What is new is the mix. The three chips sit a millimetre or two apart under a white diffuser, which spreads each one's light across the whole face of the package. Look at the LED from a little way off and the eye cannot separate them, so it sees one colour: the sum of the three lights.

What the sketch does

setColour(r, g, b) sends three values at once. The loop steps through each pair of colours, one mostly-red mix, and then all three at full, printing the numbers as it goes.

Red and green make a yellow to orange; green and blue a cyan; blue and red a purple to pink. Exactly which shade depends on the balance of light, and that is the point of the figure's percentages: they are each colour's share of the light, not its share of the numbers.

The numbers are not the light

Slide all three to 255. Each pin is on all the time, and each colour's share of the light is set only by how much light that LED gives at its current. From 5 V, according to the arithmetic in this book, green gives about half the light, red about two fifths and blue about an eighth.

So analogWrite sets a fraction of each LED's own maximum, and the three maximums are not the same. That is why the last step of the sketch, the one everybody expects to be white, is not.

The code

setColour sends three analogWrite values at once, 0 to 255 each. The loop steps through the three pairs and then all three. Change the three pin numbers to your PWM pins.

rgb_led_mixing.ino
/*
  RGB LED - mixing with PWM                               TK02 / /p/tk02

  Wiring. Count from the square pad on the TinkerBlock board, LED side
  up, header at the bottom:

    GND    -> GND
    NC     -> nothing   (both NC pins are unconnected on the board)
    NC     -> nothing
    RED    -> a PWM pin: D9 on an Uno, GPIO 25 on an ESP32,
              GPIO 4 on an ESP32-S3, GP13 on a Raspberry Pi Pico
    GREEN  -> D10, GPIO 26, GPIO 5, GP14
    BLUE   -> D11, GPIO 27, GPIO 6, GP15

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed. ESP32 boards need board package 2.0 or later.
*/

// Uno: 9, 10, 11. ESP32: 25, 26, 27. ESP32-S3: 4, 5, 6. Pico: 13, 14, 15.
const int RED_PIN = 4;
const int GREEN_PIN = 5;
const int BLUE_PIN = 6;

// 0 is off, 255 is full. Common cathode: no "255 -" anywhere.
void setColour(int r, int g, int b) {
  analogWrite(RED_PIN, r);
  analogWrite(GREEN_PIN, g);
  analogWrite(BLUE_PIN, b);
}

void show(int r, int g, int b) {
  setColour(r, g, b);
  Serial.print(r);
  Serial.print(", ");
  Serial.print(g);
  Serial.print(", ");
  Serial.println(b);
  delay(1500);
}

void setup() {
  Serial.begin(115200);
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
}

void loop() {
  show(255, 255, 0);    // red and green
  show(0, 255, 255);    // green and blue
  show(255, 0, 255);    // blue and red
  show(255, 60, 0);     // mostly red, a little green
  show(255, 255, 255);  // all three full: look closely
}

Watch the last step. 255, 255, 255 is every channel fully on, and it is not white. The next article works out what it is instead, and what to send for white.

When it does not work

One colour only goes fully on or fully off.

Its pin is not doing PWM. On an Uno only pins 3, 5, 6, 9, 10 and 11 can, and a library can take a pin's timer away: the Servo library stops PWM on 9 and 10, and tone() interferes with 3 and 11. On the ESP32 boards and the Pico every output pin can do PWM.

analogWrite is not declared, on my ESP32.

Update the ESP32 board package. analogWrite arrived in the ESP32 core's 2.0 releases and is standard in 3.x. On an old core, use the ledc functions instead; the ESP32 PWM article linked below shows both.

The colour flickers on camera but looks steady to me.

That is the PWM itself. A phone camera catches the off parts of each cycle, and with three channels switching it can show bands of different colours. It is not visible in the room and not a fault.

Red and green together are not the yellow I expected.

Equal numbers are not equal light: green gives more light per step than red, and the eye weighs them differently again. Turn one channel down until it looks right to you. The next article works out why the numbers and the colour disagree.

Where this goes next

What 255, 255, 255 really is, and what to send instead.

Why equal numbers are not white

Edit this page — content/books/rgb-led/mixing-with-pwm.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

RGB LED

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum