A potentiometer stops at both ends, but the volume knob on a modern radio or car turns forever. That's a rotary encoder: it doesn't measure a position, it reports each small click and the direction of the turn. In this lesson one encoder controls two things: turn it to set the brightness of the RGB LED, press it, and the same knob now changes the colour.
What you'll learn
- How a rotary encoder reports direction with two signals
- How to count clicks without missing any
- How one knob can control several settings with a mode button
- How to mix a colour from a hue value
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- Rotary encoder module (45-in-1 Sensor Kit)
- RGB LED module (45-in-1 Sensor Kit)
- 3 resistors, 220 Ω (UNO R3 Starter Kit)
- Breadboard and jumper wires (UNO R3 Starter Kit)
Make it real: push a bottle cap or a ring of card onto the encoder shaft as a knob, and draw a mark on it so you can see it turn.
Wiring

| From | Through | To |
|---|---|---|
| Encoder CLK | UNO pin 2 | |
| Encoder DT | UNO pin 3 | |
| Encoder SW | UNO pin 4 | |
| Encoder + and GND | 5V and GND | |
| UNO pin 9 | 220 Ω resistor | RGB module R |
| UNO pin 10 | 220 Ω resistor | RGB module G |
| UNO pin 11 | 220 Ω resistor | RGB module B |
| RGB module − | GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
The sketch
const int CLK_PIN = 2;
const int DT_PIN = 3;
const int SW_PIN = 4;
const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
int brightness = 50; // 0 ... 100 %
int hue = 30; // 0 ... 359 on the colour wheel
bool colourMode = false; // false = knob sets brightness, true = knob sets colour
int lastClk;
int lastButton = HIGH;
void hueToRgb(int h, int &r, int &g, int &b) {
int part = h / 60;
int f = (h % 60) * 255 / 60;
switch (part) {
case 0: r = 255; g = f; b = 0; break;
case 1: r = 255 - f; g = 255; b = 0; break;
case 2: r = 0; g = 255; b = f; break;
case 3: r = 0; g = 255 - f; b = 255; break;
case 4: r = f; g = 0; b = 255; break;
default: r = 255; g = 0; b = 255 - f; break;
}
}
void showLight() {
int r, g, b;
hueToRgb(hue, r, g, b);
analogWrite(RED_PIN, r * brightness / 100);
analogWrite(GREEN_PIN, g * brightness / 100);
analogWrite(BLUE_PIN, b * brightness / 100);
}
void setup() {
Serial.begin(9600);
pinMode(CLK_PIN, INPUT);
pinMode(DT_PIN, INPUT);
pinMode(SW_PIN, INPUT_PULLUP);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
lastClk = digitalRead(CLK_PIN);
showLight();
}
void loop() {
int clk = digitalRead(CLK_PIN);
if (clk != lastClk && clk == LOW) { // one click
int direction = (digitalRead(DT_PIN) != clk) ? 1 : -1;
if (colourMode) {
hue = (hue + direction * 10 + 360) % 360; // the colour wheel goes round
} else {
brightness = constrain(brightness + direction * 5, 0, 100);
}
showLight();
Serial.print(colourMode ? "Colour: " : "Brightness: ");
Serial.println(colourMode ? hue : brightness);
}
lastClk = clk;
int button = digitalRead(SW_PIN);
if (button == LOW && lastButton == HIGH) { // the knob was pressed
colourMode = !colourMode;
Serial.println(colourMode ? "Mode: colour" : "Mode: brightness");
delay(200); // ignore the bounce
}
lastButton = button;
}
How it works
Inside the encoder are two switches, CLK and DT, that open and close as you turn the shaft, slightly out of step with each other. At every click CLK changes. At that moment, DT is different from CLK when you turn one way and the same when you turn the other way, and that tells the sketch the direction. Because it counts changes and not a position, the knob can turn forever in either direction.
One knob, two jobs: colourMode decides what a click changes. Brightness stops at 0 and 100 %, but the hue wraps round with % 360, because the colour wheel has no end either. The button is checked for the moment it goes from not-pressed to pressed, so one press switches the mode once.
Try this next
- Add a third mode that sets how fast the colour cycles by itself.
- Blink the LED once when the mode changes, so you can see which mode you're in.
- Use the encoder to set the speed of the DC motor or the angle of a servo.
Troubleshooting
-
It turns the wrong way: swap the CLK and DT wires, or swap
1 : -1in the sketch. -
One click counts as two, or some clicks are missed: turn the knob more slowly, and keep
loop()free of long delays. - One colour never appears: check that colour's resistor and its wire to pin 9, 10 or 11.