Switch branches/tags
Nothing to show
Find file History
SpotlightKid Clarify encoder acceleration usage
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
Latest commit cf402fd Mar 5, 2017
Failed to load latest commit information.


Rotary Encoder Library

The file encoder.py provides a module to read a rotary encoder connected to a MicroPython board. The class encoder.Encoder works with ESP-8266 boards. The file pyb_encoder.py provides a subclass (pyb_encoder.Encoder), which works with the pyboard or any board using the stmhal port (for example a STM32F4DISCOVERY board).

The rotary encoder needs to connect to two digital input pins of of the board, for which external interrupts can be enabled. The code employs gray code error checking using the technique described in this blog post, so no further hardware or software debouncing is needed and the library works well even with cheap encoders, which usually have switches with lots of bouncing.

Encoder Hookup

  • Connect the GND pin of the encoder to ground.
  • Connect the CLK pin of the encoder to a GPIO pin on the board (e.g. 'X11' on the pyboard).
  • Connect the DT pin of the encoder to another GPIO on the board (e.g. 'X12' on the pyboard).

If you configure the input pins with the internal pull-up resistors turned on, you don't need to connect 5V from the board to anything, since the input pins will provide the current for the switches in the encoder to function. Without the pull-up resistors, connect 5V or 3V3 from the board to the plus pin of the encoder.


When everything is hooked up, use the Encoder class like this:

from machine import sleep_ms
from encoder import Encoder  # or from pyb_encoder import Encoder

e = Encoder('X11', 'X12')  # optional: add pin_mode=Pin.PULL_UP
lastval = e.value

while True:
    val = e.value
    if lastval != val:
        lastpos = val

Clicks and Acceleration

Normally the encoder value is de-/increased by one for every encoder pulse. Most encoders generate several pulses per detent ("click"). You can pass the clicks keyword when instantiating the Encoder class to set the number of pulses per detent. A common value is four. This will result in an increment / decrement of one for every click with no acceleration.

If you have a large value range (you can set the range with the min_val and max_val keyword arguments), scrolling from one end of the range to the other can be very cumbersome. You can enable acceleration by passing a positive integer to the accel keyword argument. The proper value depends on value range and the type of the encoder, but usually low one-digit numbers like 3-5 work well. With acceleration enabled the increment/decrement per click increases the faster your turn the encoder. You can still make fine adjustment by turning the encoder slowly.

Currently, if you use the acceleration feature, you need to take care of decreasing the the current acceleration, which increases everytime a valid pulse is read from the encoder. Normally you would do this at the end of your main loop, i.e. once per poll interval:

oldval = 0
while True:
    val = enc.value
    if oldval != val:
        oldval = val

    enc.cur_accel = max(0, enc.cur_accel - enc.accel)


  • Integrate de-acceleration into interrupt callback (time-based).