Dimming with PWM
analogWrite does not lower the voltage. It switches the LED fully on and off hundreds of times a second, and the duty, 0 to 255, is the share of each cycle it is on. Every pulse carries the full current; only the average falls. The eye is kinder to dim light than the arithmetic, so a fade in equal steps looks wrong, and a 2.2 power fixes it.
Full on, for part of the time
The transistor is either off or fully on. There is no half-on in this
circuit, and analogWrite does not ask for one: it switches the pin HIGH for
part of each cycle and LOW for the rest. Move the slider.
Every pulse is the full current VCC gives, about 168 mA from 5 V. What the duty changes is how long each pulse lasts, and so the average: at 170 of 255 the LED is on two thirds of the time and averages about 112 mA. The heat in the LED and its resistor follows the average, which is why capping the duty keeps them inside their ratings.
The cycle is short: 490 times a second on an Uno's D9 and D10, 1000 times on an ESP32 or a Pico. Your eye sees the average.
A fade that looks even
The eye answers roughly to the logarithm of light, not the light itself. So the step from 0 to 17 of 255 looks like a big jump, and the step from 153 to 170 looks like nothing.
The fix is to choose the duty for each step through a power of about 2.2: tiny duties for the first steps, big ones at the end. The fade sketch does exactly that, and the MicroPython version too. 2.2 is a rule of thumb from LED fading code, not a measurement of these LEDs or of your eye; try 2 or 2.5 if the fade looks uneven to you.
The same correction applies to the mix: dim both colours by the same corrected step and the colour holds while the brightness falls.
The code
Fades the warm LED up and down in 100 steps, then the cool one, each step sent through a 2.2 power so the fade looks even. Change WARM_PIN and COOL_PIN to the pins you wired.
/*
Dual Bright LEDs - a fade that looks even TK95 / /p/tk95
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 5V (VBUS on a Pico). It only feeds the LEDs, so 5V is
safe on a 3.3 V board. Never the Uno's 3.3V pin.
3000K -> D9, GPIO 25, GPIO 4 or GP14 (a PWM pin)
6500K -> D10, GPIO 26, GPIO 5 or GP15 (a PWM pin)
Uno, ESP32, ESP32-S3, Pico, in that order.
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.
Serial Monitor 115200
*/
// The pins 3000K and 6500K are wired to.
// Uno: 9. ESP32: 25. ESP32-S3: 4. Pico: 14.
const int WARM_PIN = 4;
// Uno: 10. ESP32: 26. ESP32-S3: 5. Pico: 15.
const int COOL_PIN = 5;
// Two thirds of full: the cap for VCC on 5V.
const int MAX_DUTY = 170;
const int STEPS = 100;
// Step 0..STEPS to a duty, through a 2.2 power: the eye answers
// roughly to the logarithm of light, so equal steps of duty do not
// look equal. 2.2 is the usual rule of thumb.
int dutyFor(int step) {
return lround(pow((float)step / STEPS, 2.2) * MAX_DUTY);
}
void fade(int pin, const char *name) {
Serial.print(name);
Serial.println(": up");
for (int s = 0; s <= STEPS; s++) {
analogWrite(pin, dutyFor(s));
delay(20);
}
Serial.print(name);
Serial.println(": down");
for (int s = STEPS; s >= 0; s--) {
analogWrite(pin, dutyFor(s));
delay(20);
}
}
void setup() {
// LOW first: nothing on the board holds the transistors off.
pinMode(WARM_PIN, OUTPUT);
digitalWrite(WARM_PIN, LOW);
pinMode(COOL_PIN, OUTPUT);
digitalWrite(COOL_PIN, LOW);
Serial.begin(115200);
}
void loop() {
fade(WARM_PIN, "3000K");
fade(COOL_PIN, "6500K");
}The top of the fade is MAX_DUTY, 170 of 255, the cap for VCC on 5V. The sketch compiles for an ESP32-S3, an ESP32 and an Uno; pow() and lround() are in every Arduino core.
View on GitHub · blocks/tk95-dual-bright-leds/arduino/dual_leds_fade/dual_leds_fade.ino @ v1.8The same fade in MicroPython: duty_u16 from 0 to 43690, through the same 2.2 power, 20 ms a step.
"""
Dual Bright LEDs - a fade that looks even, MicroPython TK95
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 5V (VBUS on a Pico). It only feeds the LEDs.
3000K -> GPIO 25 on an ESP32, GPIO 4 on an ESP32-S3, GP14 on a Pico
6500K -> GPIO 26 on an ESP32, GPIO 5 on an ESP32-S3, GP15 on a Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
"""
import time
from machine import Pin, PWM
# GPIO numbers. ESP32: 25 and 26. ESP32-S3: 4 and 5. Pico: 14 and 15.
WARM_PIN = 4
COOL_PIN = 5
# Two thirds of full: the cap for VCC on 5V.
MAX_DUTY = 43690
STEPS = 100
# LOW first: nothing on the board holds the transistors off.
Pin(WARM_PIN, Pin.OUT, value=0)
Pin(COOL_PIN, Pin.OUT, value=0)
warm = PWM(Pin(WARM_PIN))
cool = PWM(Pin(COOL_PIN))
for led in (warm, cool):
led.freq(1000)
led.duty_u16(0)
def duty_for(step):
# Through a 2.2 power, so equal steps look equal.
return round((step / STEPS) ** 2.2 * MAX_DUTY)
def fade(led, name):
print(name + ": up")
for s in range(STEPS + 1):
led.duty_u16(duty_for(s))
time.sleep_ms(20)
print(name + ": down")
for s in range(STEPS, -1, -1):
led.duty_u16(duty_for(s))
time.sleep_ms(20)
while True:
fade(warm, "3000K")
fade(cool, "6500K")The pin numbers are GPIO numbers: 4 and 5 on an ESP32-S3, 25 and 26 on an ESP32, 14 and 15 on a Pico. On a Pico GP14 and GP15 share one PWM slice, so they share one frequency, which is all this needs.
View on GitHub · blocks/tk95-dual-bright-leds/micropython/dual_leds_fade.py @ v1.8When it does not work
That is a straight fade: equal steps of duty. The first few steps already look bright and the last hundred look the same. Send each step through a power of about 2.2, as the fade sketch does, and it climbs evenly.
PWM switches them 490 times a second on an Uno's D9 and D10 and 1000 times on an ESP32 or a Pico. Your eye blends that; a camera's rolling shutter shows it as bands. Full on removes it; on an ESP32 a higher PWM frequency, set with analogWriteFrequency, can too.
At 1 or 2 of 255 the LED is on for under one percent of each cycle. It is still lit, very faintly, in a dark room. With the 2.2 correction the fade spends several steps there.
The block's current against each board's 5V and 3.3 V pins.
What your supply must give →Edit this page — content/books/dual-bright-leds/dimming-with-pwm.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Dual Bright LEDs
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.