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.
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.
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.
void IRAM_ATTR readEncoderISR() {
rotaryEncoder.readEncoder_ISR();
}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.
#include "AiEsp32RotaryEncoder.h"
#define ROTARY_ENCODER_A_PIN 2
#define ROTARY_ENCODER_B_PIN 3
#define ROTARY_ENCODER_BUTTON_PIN 4
#define ROTARY_ENCODER_STEPS 4
AiEsp32RotaryEncoder rotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, -1,
ROTARY_ENCODER_STEPS, false);
void IRAM_ATTR readEncoderISR() {
rotaryEncoder.readEncoder_ISR();
}
void setup() {
Serial.begin(115200);
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
rotaryEncoder.setBoundaries(0, 2, false); // 0, 1 or 2, and no further
Serial.println("ready");
}
void loop() {
if (rotaryEncoder.encoderChanged()) {
Serial.print("Value: ");
Serial.println(rotaryEncoder.readEncoder());
}
if (rotaryEncoder.isEncoderButtonClicked()) {
Serial.println("button pressed");
}
}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
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
Try Ai Esp32 Rotary Encoder without installing anything
Open the example, change the sketch, and keep your version in a free account.