A rotary encoder is the clicky knob you find on volume dials and 3D printer menus: turn it and it reports how far and which way it moved, plus it usually has a built-in pushbutton. This tutorial wires one up to an ESP8266 and reads direction and click count over serial, a nice building block for menus, speed controls or servo positioning.
The full tutorial, with every detail and the line-by-line code explanation, is on our site: ESP8266 - Rotary Encoder
What you need
- ESP8266 NodeMCU ESP-12F
- ESP8266 D1 Mini NodeMCU ESP-12F
- ESP8266 NodeMCU ESP-12E (Uno-form)
- Micro USB Cable
- ESP8266 NodeMCU ESP-12F (SMD-form)
- USB Cable Type-A to Type-C (for USB-A PC)
- USB Cable Type-C to Type-C (for USB-C PC)
- Rotary Encoder
- Jumper Wires
- Breadboard
- Screw Terminal Expansion Board for ESP8266
- DIYables Sensor Kit (18 sensors/displays)
Wiring
The encoder module has four pins. CLK goes to D7, DT goes to D6, and SW (the pushbutton output) goes to D5. VCC connects to the ESP8266's 3.3V (or up to 5V) supply and GND to ground. SW is normally open and relies on a pull-up so it reads HIGH when the knob isn't pressed and LOW when it is.
How it works
Inside the encoder, a slotted disc connects two pins, A (CLK) and B (DT), to a shared ground pin as you turn the knob. Because A and B touch ground at slightly different times, their signals are 90 degrees out of phase, known as quadrature encoding. Turning clockwise makes A go LOW before B; counter-clockwise makes B go LOW before A. By watching what DT is doing at the moment CLK changes from LOW to HIGH, you can tell which direction the knob just turned.
Code
The sketch reads CLK_PIN on every loop and compares it to its previous state. On a LOW-to-HIGH transition it checks digitalRead() on DT_PIN: DT HIGH means counter-clockwise (decrease the counter), DT LOW means clockwise (increase it). The direction and running count print to Serial. The ezButton library handles the SW pin with built-in debouncing, calling button.isPressed() to report clicks. An interrupt-based version of the same logic avoids polling CLK on every loop, so the ESP8266 won't miss fast turns while busy doing other work.
esp8266-rotary-encoder.ino
/*
* This ESP8266 NodeMCU code was developed by newbiely.com
*
* This ESP8266 NodeMCU code is made available for public use without any restriction
*
* For comprehensive instructions and wiring diagrams, please visit:
* https://newbiely.com/tutorials/esp8266/esp8266-rotary-encoder
*/
#include <ezButton.h> // The library to use for SW pin
#define CLK_PIN D7 // The ESP8266 pin D7 connected to the rotary encoder's CLK pin
#define DT_PIN D6 // The ESP8266 pin D6 connected to the rotary encoder's DT pin
#define SW_PIN D5 // The ESP8266 pin D5 connected to the rotary encoder's SW pin
#define DIRECTION_CW 0 // clockwise direction
#define DIRECTION_CCW 1 // counter-clockwise direction
int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;
ezButton button(SW_PIN); // create ezButton object for pin 7;
void setup() {
Serial.begin(9600);
// Configure encoder pins as inputs
pinMode(CLK_PIN, INPUT);
pinMode(DT_PIN, INPUT);
button.setDebounceTime(50); // set debounce time to 50 milliseconds
// read the initial state of the rotary encoder's CLK pin
prev_CLK_state = digitalRead(CLK_PIN);
}
void loop() {
button.loop(); // MUST call the loop() function first
// read the current state of the rotary encoder's CLK pin
CLK_state = digitalRead(CLK_PIN);
// If the state of CLK is changed, then pulse occurred
// React to only the rising edge (from LOW to HIGH) to avoid double count
if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
// if the DT state is HIGH
// The encoder is rotating in counter-clockwise direction => decrease the counter
if (digitalRead(DT_PIN) == HIGH) {
counter--;
direction = DIRECTION_CCW;
} else {
// The encoder is rotating in clockwise direction => increase the counter
counter++;
direction = DIRECTION_CW;
}
Serial.print("Rotary Encoder:: direction: ");
if (direction == DIRECTION_CW)
Serial.print("CLOCKWISE");
else
Serial.print("ANTICLOCKWISE");
Serial.print(" - count: ");
Serial.println(counter);
}
// save last CLK state
prev_CLK_state = CLK_state;
if (button.isPressed()) {
Serial.println("The button is pressed");
}
}
Full tutorial
The complete tutorial - wiring diagram, code explanation and troubleshooting - is here: https://newbiely.com/tutorials/esp8266/esp8266-rotary-encoder

Top comments (0)