Make a digital knob with the rotary encoder

Turn the rotary encoder to dim the RGB LED or change its colour, and press the knob to switch between the two: the same kind of knob as on a modern radio.
  • Level:Beginner
  • Duration: 40 min
  • Ages 10+
  • Platform: Arduino

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Make a digital knob with the rotary encoder – EEMENTOR STEM™ lesson

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

Breadboard wiring diagram: Make a digital knob with the rotary encoder
Breadboard view. Check each connection against the wiring table below.
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 : -1 in 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.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

UNO R3 Starter Kit | Arduino IDE Compatible | Free Tutorials $56.00

Shop the kit