Source: https://mokxi.com/libraries/aiesp32rotaryencoder
Updated: 2026-11-11

Libraries / Input

Arduino library · Input

# AiEsp32RotaryEncoder: a bounded knob value on the ESP32

AiEsp32RotaryEncoder by Igor Antolic is made for the common job of using a KY-040 knob as a menu control or a setting: it turns rotation into a value kept between a minimum and a maximum, optionally wrapping around, and it reads the knob’s push button in the same object. It works on the ESP32 family and the ESP8266.

Open the example in the editor See the calls

Built in on Mokxi: #include <AiEsp32RotaryEncoder.h> and it builds, with nothing to install. Free, and no account needed.

## What Ai Esp32 Rotary Encoder does

The value is counted in an interrupt, and the library needs you to supply the interrupt function: a short IRAM_ATTR function that calls readEncoder_ISR(), passed to setup(). From then on encoderChanged() tells loop() when the value moved, readEncoder() gives it, and isEncoderButtonClicked() reports a press of the shaft.

The steps argument says how many edges make one click; 4 suits a KY-040, so one detent changes the value by one. setBoundaries(0, 2, false) in the runnable example holds the value between 0 and 2: turning further does nothing, which is what you want for a three-item menu. In Mokxi, setAcceleration() is accepted but not applied, so every detent counts one however fast the knob turns.

Library Manager name | Ai Esp32 Rotary Encoder

Author | Igor Antolic

Include | #include <AiEsp32RotaryEncoder.h>

Boards | ESP32-C3, ESP32-C6, Seeed XIAO ESP32-C3, ESP32-C3 SuperMini, Seeed XIAO ESP32-C6, ESP32 DevKit, ESP32-DevKitC V4, LOLIN32 Lite, Wemos D1 R32, Cheap Yellow Display, TTGO T-Display, ESP32-S3-DevKitC-1, Seeed XIAO ESP32-S3, Arduino Nano ESP32, ESP8266 NodeMCU

In the simulator | Simulated: it runs against the part the way it does on the bench.

Parts it drives | Rotary encoder, KY-040

## Install it

It builds on ESP32-C3, ESP32-C6, Seeed XIAO ESP32-C3, ESP32-C3 SuperMini, Seeed XIAO ESP32-C6, ESP32 DevKit, ESP32-DevKitC V4, LOLIN32 Lite, Wemos D1 R32, Cheap Yellow Display, TTGO T-Display, ESP32-S3-DevKitC-1, Seeed XIAO ESP32-S3, Arduino Nano ESP32, ESP8266 NodeMCU.

In Mokxi it is built in: #include <AiEsp32RotaryEncoder.h> and the sketch compiles, with no download, no zip and no Library Manager.

On a real board, install "Ai Esp32 Rotary Encoder" by Igor Antolic from the Arduino IDE’s Library Manager (Sketch, Include Library, Manage Libraries), or add Ai Esp32 Rotary Encoder to lib_deps in PlatformIO. Mokxi follows the calls of release 1.7.0, so a sketch written here builds there too.

What to know in the simulator: setAcceleration() is accepted and not applied: every detent counts one.

- ESP32-C3
- ESP32-C6
- Seeed XIAO ESP32-C3
- ESP32-C3 SuperMini
- Seeed XIAO ESP32-C6
- ESP32 DevKit
- ESP32-DevKitC V4
- LOLIN32 Lite
- Wemos D1 R32
- Cheap Yellow Display
- TTGO T-Display
- ESP32-S3-DevKitC-1
- Seeed XIAO ESP32-S3
- Arduino Nano ESP32
- ESP8266 NodeMCU

## The calls you will use

In the order a sketch meets them.

### AiEsp32RotaryEncoder rotaryEncoder(A_PIN, B_PIN, BUTTON_PIN, -1, 4)

A knob with CLK on A_PIN, DT on B_PIN and its switch on BUTTON_PIN. The -1 means no VCC pin, and 4 is the edges per click.

### rotaryEncoder.readEncoder_ISR()

The work the interrupt does. Call it from your own IRAM_ATTR function and nowhere else.

### rotaryEncoder.begin()

Sets the pins up. Call it in setup() before setup(readEncoderISR).

### rotaryEncoder.setup(readEncoderISR)

Attaches your interrupt function to both encoder pins.

### rotaryEncoder.setBoundaries(0, 100, false)

Keeps the value between 0 and 100. With true as the last argument it wraps from the top back to the bottom.

### rotaryEncoder.encoderChanged()

Non-zero when the value has moved since the last check, so loop() only redraws on a change.

### rotaryEncoder.readEncoder()

The current value, inside the boundaries.

### rotaryEncoder.setEncoderValue(50)

Sets the value, for starting a setting at its saved level.

### rotaryEncoder.isEncoderButtonClicked()

True once for each press of the knob’s button.

## Example: A bounded value from a knob on an ESP32-C3

On the ESP32-C3-DevKitM-1. It runs in the browser exactly as printed.

sketch.ino · ESP32-C3-DevKitM-1

### Wiring

- ESP32-C3-DevKitM-1 2 to Rotary encoder, KY-040 CLK
- ESP32-C3-DevKitM-1 3 to Rotary encoder, KY-040 DT
- ESP32-C3-DevKitM-1 4 to Rotary encoder, KY-040 SW
- ESP32-C3-DevKitM-1 3V3 to Rotary encoder, KY-040 VCC
- ESP32-C3-DevKitM-1 GND to Rotary encoder, KY-040 GND

Open it in the editor, wired and ready to run

## Common errors and how to fix them

### One click moves the value by 2 or 4, or only every other click counts

The steps argument does not match the knob. A KY-040 has 4 edges per detent, so pass 4; try 2 for knobs with half as many detents per cycle.

### The ESP32 crashes with a Guru Meditation error when the knob turns

The interrupt function is missing IRAM_ATTR or does more than call readEncoder_ISR(). Keep it to that one line, and do the printing in loop() after encoderChanged().

### The value stops at 0 and will not go negative

setBoundaries() sets the lower limit, and the default range starts at 0. Call setBoundaries(-100, 100, false) or whatever range the setting needs.

## Keep going

### Learn

- Arduino Rotary Encoder (KY-040): Wiring and Code
- ESP32 Interrupts: attachInterrupt and Debounce

### Parts

- Rotary encoder, KY-040

### More input libraries

- XPT2046_Touchscreen
- Keypad
- OneButton
- Encoder
- RotaryEncoder
- CapacitiveSensor
- IRremote
- Adafruit MCP23017 Arduino Library

Every built-in library · Open the editor

## Try Ai Esp32 Rotary Encoder without installing anything

Open the example, change the sketch, and keep your version in a free account.

Start building free

Open the editor
