Learning Goals 5 min
- Wire a common-cathode RGB LED to three PWM pins (~9 R, ~10 G, ~11 B) using one 220 Ω resistor per channel.
- Set any visible colour by calling
analogWriteon all three channels in turn, using values 0–255. - Crossfade smoothly between two colours by ramping one channel up while the other ramps down — your first real animation across multiple pins.
Warm-Up 10 min
So far you've only fed one channel of analogWrite. The RGB LED has three inside one body — a tiny red chip, a tiny green chip, a tiny blue chip — sharing a single cathode (the long leg). Drive each with its own PWM pin and you mix any colour your eye can see.
Quick puzzle
Predict the colour the RGB LED will look:
analogWrite(R, 255);
analogWrite(G, 255);
analogWrite(B, 0);Reveal
Full red + full green + no blue = yellow. (In additive light mixing — different from paint mixing.) The three primary lights add: R + G = yellow, G + B = cyan, R + B = magenta, R + G + B = whitish.
New Concept · Three pins, one colour 20 min
What an RGB LED actually is
Look at one closely — it's a clear LED with four legs. Three are the red, green and blue anodes (one each); the long leg is the shared cathode. In a common-anode part the polarity flips (long leg = +, three short legs each tie to GND through a transistor) — Level 1 covered which kind you have in L01-30. For Level 2 we assume common cathode.
Wiring
| LED leg | Goes to | Through |
|---|---|---|
| R anode | Arduino ~9 | 220 Ω resistor |
| Cathode (longest leg) | GND rail | — |
| G anode | Arduino ~10 | 220 Ω resistor |
| B anode | Arduino ~11 | 220 Ω resistor |
One 220 Ω resistor per colour. The cathode pin is usually noticeably longer than the others; if you can't tell by length, the leg next to the flat spot on the bulb is one of the anodes — try both orientations until you see colour.
The additive mixing table
| R | G | B | Colour |
|---|---|---|---|
| 255 | 0 | 0 | Red |
| 0 | 255 | 0 | Green |
| 0 | 0 | 255 | Blue |
| 255 | 255 | 0 | Yellow |
| 0 | 255 | 255 | Cyan |
| 255 | 0 | 255 | Magenta |
| 255 | 255 | 255 | White (ish — see below) |
| 255 | 165 | 0 | Orange |
| 128 | 0 | 128 | Purple |
| 0 | 0 | 0 | Off |
Anything in between mixes proportionally — exactly the same numbers used by every web colour picker. 24-bit colour everywhere on the internet is just three of these channels times eight bits each.
The crossfade pattern
To smoothly transition from red to green, ramp red down from 255 to 0 while ramping green up from 0 to 255 — in the same loop, same speed:
for (int v = 0; v <= 255; v++) {
analogWrite(R, 255 - v); // 255 → 0 (red dims)
analogWrite(G, v); // 0 → 255 (green brightens)
delay(10);
}The eye sees a single point shifting smoothly through orange and lime on its way from red to green. The maths is identical to two fade loops sharing a counter — no new trick.
Why "white" isn't quite white
The red, green and blue chips inside the LED have different forward voltages and different efficiencies. So (255, 255, 255) often looks a bit cool / blue-tinted. To get a warmer white, knock the blue back a little — try (255, 220, 180). There's no "correct" — pick what looks white to your eye.
Worked Example · Red → green → blue → red 20 min
Step 1 — wiring
Build the wiring from the table above. The LED sits in row D of the breadboard with its four legs in adjacent columns; each anode runs through a 220 Ω resistor up to its Arduino pin; the cathode runs to the − rail; the − rail connects to Arduino GND.
Step 2 — the crossfade sketch
Save as rgb-crossfade.ino:
// L02-05: smooth crossfade R → G → B → R, repeating
const int R = 9;
const int G = 10;
const int B = 11;
const int STEP_DELAY = 10;
void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
analogWrite(R, 255); // start on red
}
void loop() {
// Red → Green
for (int v = 0; v <= 255; v++) {
analogWrite(R, 255 - v);
analogWrite(G, v);
delay(STEP_DELAY);
}
// Green → Blue
for (int v = 0; v <= 255; v++) {
analogWrite(G, 255 - v);
analogWrite(B, v);
delay(STEP_DELAY);
}
// Blue → Red
for (int v = 0; v <= 255; v++) {
analogWrite(B, 255 - v);
analogWrite(R, v);
delay(STEP_DELAY);
}
}Step 3 — upload & watch
Three smooth ramps. Total cycle = 3 × 256 × 10 ms ≈ 7.7 seconds. The LED walks through every primary, secondary and intermediate hue you can name.
Step 4 — a helper function to clean up
Three identical-shaped loops is a sign a function is hiding. Extract one:
void crossfade(int outPin, int inPin) {
for (int v = 0; v <= 255; v++) {
analogWrite(outPin, 255 - v);
analogWrite(inPin, v);
delay(STEP_DELAY);
}
}
void loop() {
crossfade(R, G);
crossfade(G, B);
crossfade(B, R);
}The main loop now reads like a stage direction: red fades to green, green fades to blue, blue fades to red. Add a fourth call (crossfade(R, G)... wait, that's the start of the next cycle anyway) and you can re-arrange the colour order without touching the loops.
Try It Yourself 20 min
Goal: Make a single static colour. Set the LED to a colour from the table — your choice — and leave it there. No fades.
Hint
void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
analogWrite(R, 255);
analogWrite(G, 165);
analogWrite(B, 0); // orange-ish
}
void loop() {}Goal: Build the crossfade sketch from the worked example, then refactor it using the crossfade(outPin, inPin) helper. Confirm the colours and speed look identical to before.
Goal: Make the colour cycle through six distinct hues: red → yellow → green → cyan → blue → magenta → red. That's six crossfades per cycle instead of three.
Hint
Each crossfade brings one channel up while another goes down — the third stays put. So red → yellow is R at 255, G ramps 0 → 255, B at 0. Yellow → green is the opposite: G at 255, R ramps 255 → 0, B at 0.
void ramp(int upPin, int downPin, int holdPin, int holdValue) {
analogWrite(holdPin, holdValue);
for (int v = 0; v <= 255; v++) {
analogWrite(upPin, v);
analogWrite(downPin, 255 - v);
delay(STEP_DELAY);
}
}
void loop() {
ramp(G, B, R, 255); // red → yellow → green-ish? wait — read it carefully
// Trace this in your head before you upload. The pattern requires care.
}This one needs some thought — write the six ramp calls in your notebook first, with their colour names in a comment. The traceability is the lesson.
Mini-Challenge · The traffic light 15 min
Use the single RGB LED to imitate a traffic-light cycle:
- Red for 4 seconds.
- Yellow (R = 255, G = 100, B = 0) for 1 second.
- Green for 4 seconds.
- Crossfade green → yellow over 0.5 seconds.
- Yellow for 1 second.
- Crossfade yellow → red over 0.5 seconds.
- Repeat.
It works if:
- The colours look distinct — red is unmistakably red, green clearly green, yellow visibly between.
- The crossfades are smooth, not stepped.
- Total cycle is about 11 seconds.
- The code uses a function (
setColour(r, g, b)is a good name) so the main loop reads like a script.
Reveal one valid sketch
const int R = 9;
const int G = 10;
const int B = 11;
void setColour(int r, int g, int b) {
analogWrite(R, r);
analogWrite(G, g);
analogWrite(B, b);
}
void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
}
void loop() {
setColour(255, 0, 0); delay(4000); // red
setColour(255, 100, 0); delay(1000); // yellow
setColour(0, 255, 0); delay(4000); // green
// green → yellow, 0.5 s = 500 ms / 256 ≈ 2 ms per step
for (int v = 0; v <= 255; v++) {
setColour(v, 255 - v / 3, 0); // green dims to ~170 (yellow's G)
delay(2);
}
setColour(255, 100, 0); delay(1000);
// yellow → red, 0.5 s
for (int v = 100; v >= 0; v--) {
setColour(255, v, 0);
delay(5);
}
}Notice setColour reads almost like English. The crossfade loops still do the maths, but the main shape of the program is "red 4 s, yellow 1 s, green 4 s, fade, yellow 1 s, fade" — exactly the spec.
Recap 5 min
An RGB LED is three LEDs in one body sharing a cathode. Three PWM pins control the three brightnesses; the eye mixes them additively. Set a colour with three analogWrite calls; crossfade between colours by ramping one channel up while another goes down. Wrap the three writes in setColour(r, g, b) and your sketch reads like a paint-by-numbers script. Tomorrow we use the same hardware for a calmer project — the breathing mood lamp.
- RGB LED
- An LED containing red, green and blue chips in one body, with three anode legs and one shared cathode (common cathode) or vice versa (common anode).
- Common cathode / common anode
- Which of the two shared legs sits at GND vs +5 V. Common cathode is the easier default — anodes go to PWM pins, cathode to GND.
- Additive mixing
- Light mixing: R + G = yellow, G + B = cyan, R + B = magenta, R + G + B = white-ish. Opposite of paint (subtractive).
- Crossfade
- Smooth transition between two states by ramping one variable up while the related one ramps down in the same loop.
setColour(r, g, b)- Convention helper that takes three brightnesses and writes them to the three RGB pins. Keeps the main sketch readable.
Homework 5 min
Match the colour. Pick any four colours on a website (use the "inspect" tool to copy their hex codes — e.g. #FF6B35). Convert each hex code into R, G, B values (each pair of hex digits in hex codes is one channel: FF = 255, 6B = 107, 35 = 53).
- Write a sketch that holds the first colour for 2 seconds, then jumps to the second for 2 seconds, then the third, then the fourth.
- Upload it. Photograph the LED with each colour and compare to the original web colour. Note any obvious mismatches.
- Tweak any value where the LED looks "off" — usually blue is over-strong, so try reducing the blue channel by 30–50.
Bring back next class:
- The four hex codes you chose with their R, G, B conversions.
- Notes on any colour that needed tweaking and what worked.
- The
hw-l02-05.inofile.