Arduino library · Input

ESP32Encoder: counting a quadrature encoder on the ESP32

ESP32Encoder by Kevin Harrington counts quadrature encoders on the ESP32, both the KY-040 knobs used for menus and the encoders on motor shafts used in robots. On a real chip it uses the pulse counter hardware, so counting takes no CPU time and keeps up with fast motors, and the count is a 64-bit number that does not overflow.

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

What ESP32Encoder does

You choose how many edges to count. attachFullQuad() counts every edge of both pins, four per cycle, for the most counts per turn of a motor. attachHalfQuad() counts two per cycle, and attachSingleEdge() one. A KY-040 knob has one cycle per click, so half quad gives 2 a click, which the runnable example shows: two clicks read as 4.

Pull resistors are chosen for every encoder at once with the static useInternalWeakPullResistors setting, before attaching. In Mokxi the counting is done from pin interrupts rather than the pulse counter, sharing the four slots of the Encoder library, so it counts the same edges a real ESP32 would. setFilter() is accepted and not needed, since the simulated knob does not bounce unless told to.

Library Manager nameESP32Encoder
AuthorKevin Harrington
Include#include <ESP32Encoder.h>
BoardsESP32-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
In the simulatorSimulated: it runs against the part the way it does on the bench.
Parts it drivesRotary 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.

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

On a real board, install "ESP32Encoder" by Kevin Harrington from the Arduino IDE’s Library Manager (Sketch, Include Library, Manage Libraries), or add ESP32Encoder to lib_deps in PlatformIO. Mokxi follows the calls of release 5.0.0, so a sketch written here builds there too.

What to know in the simulator: Counted from pin interrupts rather than the chip’s pulse counter, sharing Encoder.h’s four slots.

The calls you will use

In the order a sketch meets them.

ESP32Encoder encoder

One encoder object. Make one per encoder; pins are given when it is attached.

ESP32Encoder::useInternalWeakPullResistors = puType::up

Turns on the internal pull-ups for the encoder pins. Set it before attaching; puType::none is for modules with their own resistors.

encoder.attachHalfQuad(4, 5)

Starts counting on two pins, two counts per cycle. Which pin is named first decides which direction counts up.

encoder.attachFullQuad(4, 5)

Counts four per cycle, every edge of both pins, which gives a motor encoder four times the counts of single edge.

encoder.getCount()

The count so far as an int64_t. Cast it to int32_t or long before printing on cores whose Serial lacks a 64-bit print.

int32_t count = (int32_t)encoder.getCount();
Serial.println("Encoder count = " + String(count));

encoder.setCount(0)

Sets the count to any value, for zeroing at a home position. clearCount() sets it to 0.

encoder.pauseCount()

Stops counting until resumeCount(), without losing the value.

Example: A rotary encoder on an ESP32-C3

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

sketch.ino · ESP32-C3-DevKitM-1
#include <ESP32Encoder.h>

ESP32Encoder encoder;

void setup() {
  Serial.begin(115200);
  ESP32Encoder::useInternalWeakPullResistors = puType::up;
  encoder.attachHalfQuad(2, 3);  // CLK, DT: clockwise counts up
  encoder.setCount(0);
  Serial.println("Encoder Start");
}

void loop() {
  static int32_t last = 0;
  int32_t count = (int32_t)encoder.getCount();
  if (count != last) {
    Serial.println("Encoder count = " + String(count));
    last = count;
  }
}

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 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

call of overloaded println(int64_t) is ambiguous

getCount() returns a 64-bit number that Serial.println() on some cores cannot print directly. Cast it first, (int32_t)encoder.getCount(), or wrap it in String().

The count goes down when the knob is turned clockwise

The pins are named in the opposite order from your wiring. Swap the two pin numbers in attachHalfQuad() or attachFullQuad(); no wiring change is needed.

One click changes the count by 2 or 4 instead of 1

That is the counting mode: half quad gives 2 per click and full quad 4. Divide getCount() by that number, or use attachSingleEdge() for one count per click.

Questions and answers

Does ESP32Encoder work on an Arduino Uno?

No, it is written for the ESP32 family. On an Uno use the Encoder library, which counts from pin interrupts in the same way.

Try ESP32Encoder without installing anything

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