The first count
Five wires, no library, and a sketch that watches CLOCK. Each time it falls, the sketch looks at DATA: still HIGH, CLOCK went first and the count goes up; already LOW, DATA went first and it goes down. Turn the knob and the serial monitor counts.
Five wires
GND to GND. VCC to your board's logic supply: 5V on an Uno, 3V3 on the three 3.3 V boards. CLOCK, DATA and BTN to three digital pins. NC stays unconnected.
The pins are the same in every sketch in this book: D2, D3 and D4 on an Uno; GPIO 25, GPIO 26 and GPIO 27 on an ESP32; GPIO 4, GPIO 5 and GPIO 6 on an ESP32-S3; GP13, GP14 and GP15 on a Pico. None of them is read by the chip at boot or tied up with its flash memory, so the block cannot stop the board from starting. This sketch would work on any plain digital pins; the later ones need pins that can raise an interrupt, and on an Uno only D2 and D3 can.
The sketch
It keeps the last level of CLOCK it saw and compares every new read with it. Only on the pass where CLOCK has just gone from HIGH to LOW does it do anything: it reads DATA once and moves the count.
- DATA still HIGH means CLOCK fell first.
count++. - DATA already LOW means DATA fell first.
count--.
Rises of CLOCK are ignored, so one cycle of the contacts is one step of the count. Two contacts out of step has the waveforms this is reading.
What you should see
The serial monitor at 115200 prints the count each time it changes. Turn the knob one way a few clicks, then back:
1
2
3
2
1
0If clockwise counts down, swap count++ and count--: which contact leads
is the part's choice, not a fault. If a click moves the count by two, or two
clicks move it by one, your part's clicks do not sit one cycle apart; mark
the knob, turn it once round and compare.
Turn it slowly and it counts every click. Flick it and it may not, and the reason is in why polling misses steps.
The code
No library. pinMode makes CLOCK and DATA inputs; the loop reads CLOCK, and on the pass where it has just gone LOW it reads DATA to find the direction. Change the three pin numbers to the pins you wired.
/*
Rotary Encoder - first count TK06 / /p/tk06
Wiring. Count from the square pad on the TinkerBlock board, knob
up, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
(CLOCK, DATA and BTN all reach whatever VCC is)
NC -> nothing (unconnected on the board)
BTN -> D4 on an Uno, GPIO 27 on an ESP32, GPIO 6 on an
ESP32-S3, GP15 on a Raspberry Pi Pico
CLOCK -> D2, GPIO 25, GPIO 4, GP13 (the same four boards)
DATA -> D3, GPIO 26, GPIO 5, GP14
Arduino IDE
Tools > Board your board, e.g. ESP32S3 Dev Module
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library needed.
*/
// CLOCK, DATA and BTN, as GPIO numbers.
// Uno: 2, 3, 4. ESP32: 25, 26, 27. ESP32-S3: 4, 5, 6. Pico: 13, 14, 15.
const int CLOCK_PIN = 4;
const int DATA_PIN = 5;
const int BUTTON_PIN = 6; // not used until the next sketch
long count = 0;
int lastClock = HIGH; // at rest, the pull-up holds it HIGH
void setup() {
Serial.begin(115200);
pinMode(CLOCK_PIN, INPUT); // the block has its own pull-ups
pinMode(DATA_PIN, INPUT);
}
void loop() {
int clockLevel = digitalRead(CLOCK_PIN);
if (clockLevel != lastClock) { // CLOCK has changed...
if (clockLevel == LOW) { // ...and it has just fallen
if (digitalRead(DATA_PIN) == HIGH) {
count++; // CLOCK fell first
} else {
count--; // DATA fell first
}
Serial.println(count);
}
lastClock = clockLevel;
}
}INPUT, not INPUT_PULLUP: the block has its own 10 kΩ pull-ups on CLOCK and DATA. The sketch counts one step per fall of CLOCK. There is no delay() in loop(), on purpose: the next articles are about what one does to the count.
The same count in MicroPython, for an ESP32, an ESP32-S3 or a Pico. Pin.IN makes the pins inputs and value() returns 1 or 0: 1 is HIGH, the contact open.
"""
Rotary Encoder - first count, MicroPython TK06 / /p/tk06
Wiring. Count from the square pad on the TinkerBlock board, knob
up, header at the bottom:
GND -> GND
VCC -> 3V3 (never 5V: CLOCK, DATA and BTN all reach VCC)
NC -> nothing (unconnected on the board)
BTN -> GPIO 27 on an ESP32, GPIO 6 on an ESP32-S3,
GP15 on a Raspberry Pi Pico
CLOCK -> GPIO 25, GPIO 4, GP13 (the same three boards)
DATA -> GPIO 26, GPIO 5, GP14
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine is built in.
"""
from machine import Pin
# CLOCK, DATA and BTN, as GPIO numbers.
# ESP32: 25, 26, 27. ESP32-S3: 4, 5, 6. Pico: 13, 14, 15.
CLOCK_PIN = 4
DATA_PIN = 5
clock = Pin(CLOCK_PIN, Pin.IN) # no pull: the block has its own
data = Pin(DATA_PIN, Pin.IN)
count = 0
last_clock = 1 # at rest, held HIGH
while True:
level = clock.value()
if level != last_clock: # CLOCK has changed...
if level == 0: # ...and it has just fallen
if data.value() == 1:
count += 1 # CLOCK fell first
else:
count -= 1 # DATA fell first
print(count)
last_clock = levelThere is no Uno here: an Uno cannot run MicroPython. No pull argument: the block's own pull-ups hold CLOCK and DATA HIGH. MicroPython runs slower than compiled C, so this one loses count sooner when turned fast. Stop it with Ctrl-C in Thonny's shell.
When it does not work
Nothing is wrong. Which contact leads when you turn clockwise depends on the part. Swap count++ and count-- in the sketch, or swap the numbers in CLOCK_PIN and DATA_PIN, and it counts the other way.
The sketch counts one fall of CLOCK per cycle. On many EC11 parts one click is one cycle, but on parts whose clicks sit every half-cycle it counts every other click. Turn the knob one full turn and compare the count with the clicks you felt.
Check VCC and GND first: without them CLOCK never rises or never falls. Then the pin numbers: CLOCK_PIN and DATA_PIN are GPIO numbers, printed beside the pins on your board, not positions along the header. On an ESP32-S3, also set Tools > USB CDC On Boot to Enabled.
This sketch has to read CLOCK within a quarter of a cycle of each fall, and anything slow in loop() makes it late. The next chapter shows why, and counts with an interrupt instead.
BTN reads HIGH when the knob is pushed in, and a sketch that uses it to zero the count.
The switch in the shaft →Edit this page — content/books/rotary-encoder/the-first-count.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Rotary Encoder
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.