The ANO Directional Navigation and Scroll Wheel Rotary Encoder is made up of 5 buttons and a two-direction rotary encoder. CircuitPython has two built in modules - digitalio and rotaryio - designed to work with buttons and rotary encoders, making it super simple to get started with this encoder! These modules make it easy to write Python code that allows you to read button presses and encoder rotation from the encoder.

This example uses a 12-pixel NeoPixel ring, along with the rotary encoder, to use the encoder to light up various pixels.

Additional Necessary Hardware

Hand holding NeoPixel Ring with 12  x 5050 RGB LED, lit up rainbow
Round and round and round they go! 12 ultra bright smart LED NeoPixels are arranged in a circle with 1.5" (37mm) outer diameter. The rings are 'chainable' - connect the...
$7.50
In Stock
Hook-up Wire Spool Set in box with 6 colorful wires coming out
Perfect for bread-boarding, free wiring, etc. This box contains 6 spools of solid-core wire. The wire is easy to solder to and when bent it keeps its shape pretty well. We like to have...
$15.95
In Stock

CircuitPython Microcontroller Wiring

Solder up the encoder to the breakout, and wire up the NeoPixel ring. Then, wire up the breakout and ring as shown below. This is an example of wiring the rotary encoder breakout and a NeoPixel ring to a Feather M4 Express.

This method of wiring the breakout takes advantage of the fact that the short side of a Feather has, in a row, exactly the 7 GPIO pins needed for the breakout. You can also wire this up to ANY microcontroller (with 7+ GPIO available) using jumper wires!
  • NeoPixel ring data in to Feather A0
  • NeoPixel ring ground to Feather GND
  • NeoPixel ring power to Feather 3.3v
  • Breakout ENCA to Feather D13
  • Breakout ENCB to Feather D12
  • Breakout COMA to Feather D11
  • Breakout SW1 to Feather D10
  • Breakout SW2 to Feather D9
  • Breakout SW3 to Feather D6
  • Breakout SW4 to Feather D5
  • Breakout SW5 to Feather SCL
  • Breakout COMB to Feather SDA

The wiring shown here ties COMA/B to digital outputs set LOW in code (instead of connected to GND) to allow for the direct-to-Feather connection.

Encoder and NeoPixel Example

To use with CircuitPython, you need to first install the NeoPixel library, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.

Thankfully, you can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.

Your CIRCUITPY/lib folder should contain the following folder and file:

  • neopixel.mpy
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
CircuitPython ANO Rotary Encoder and NeoPixel Ring example.
"""
import board
import digitalio
import rotaryio
import neopixel

# The pin assignments for the breakout pins. Update this is you are not using a Feather.
ENCA = board.D13
ENCB = board.D12
COMA = board.D11
SW1 = board.D10
SW2 = board.D9
SW3 = board.D6
SW4 = board.D5
SW5 = board.SCL
COMB = board.SDA

# Rotary encoder setup
encoder = rotaryio.IncrementalEncoder(ENCA, ENCB)
last_position = None

# NeoPixel ring setup. Update num_pixels if using a different ring.
num_pixels = 12
pixels = neopixel.NeoPixel(board.A0, num_pixels, auto_write=False)

# Set the COMA and COMB pins LOW. This is only necessary when using the direct-to-Feather or other
# GPIO-based wiring method. If connecting COMA and COMB to ground, you do not need to include this.
com_a = digitalio.DigitalInOut(COMA)
com_a.switch_to_output()
com_a = False
com_b = digitalio.DigitalInOut(COMB)
com_b.switch_to_output()
com_b = False

# Button pin setup
button_pins = (SW1, SW2, SW3, SW4, SW5)
buttons = []
for button_pin in button_pins:
    pin = digitalio.DigitalInOut(button_pin)
    pin.switch_to_input(digitalio.Pull.UP)
    buttons.append(pin)

while True:
    position = encoder.position
    if last_position is None or position != last_position:
        print("Position: {}".format(position))
        last_position = position

    pixels.fill((0, 0, 0))
    pixels[position % num_pixels] = (0, 150, 0)

    if not buttons[0].value:
        print("Center button!")
        pixels.fill((100, 100, 100))

    if not buttons[1].value:
        print("Up button!")
        pixels[0] = (150, 0 ,0)

    if not buttons[2].value:
        print("Left button!")
        pixels[3] = (150, 0, 0)

    if not buttons[3].value:
        print("Down button!")
        pixels[6] = (150, 0, 0)

    if not buttons[4].value:
        print("Right button!")
        pixels[9] = (150, 0, 0)

    pixels.show()

Rotate the encoder to see the green NeoPixel move around the NeoPixel ring. Press the outer directional buttons to see a red LED light up in a corresponding location on the ring. Finally, click the center button to see the entire ring light up white.

First you import the necessary modules and library.

Next, you provide the pin assignments. The variables are in order of the breakout, left to right, to make it easier to provide the pins you used to connect the breakout to your microcontroller. Update this if you connected the breakout in a different way than the wiring diagram above. Remember, the COMA and COMB pins are not needed in the code, if you connected them to ground.

Then, you setup the hardware. First up, you setup the rotary encoder, and create the last_position variable and set it to False. Second, you create the num_pixels variable and set it to the number of pixels on whatever NeoPixel hardware you're using. In the case of this ring, there are 12 pixels. Then you setup the NeoPixel ring, and set auto_write=False so that you must call show() to send any updates to the pixels. This eliminates flickering that occurs when updates are otherwise spammed throughout the loop.

Next, you setup the two COM pins as outputs and set them low by making them False.

Then, you setup the buttons. There are 5 buttons, and setup for all of them is the same. So, instead of doing all of them individually, you do them all at the same time. First, you create a Python tuple of the button pins. Then you create an empty list to hold your setup buttons. Finally, you setup each button, and append it to the list until all setup has been completed. Now, buttons contains a list of button objects available for you to use in your code.

Inside the loop, you first create the position variable and set it equal to the initial encoder position. Then, you check it against the last_position, and if it's changed, print the position to the serial console.

Next, you clear the pixels so the rest of the pixel updates show up as expected with encoder rotation and button presses.

Then, you turn on one pixel green, that is equal to the rotary encoder position, mapped out to the possible values of 0 to 11 (12 total values, 12 total pixels). This means as you rotate the encoder past 12 or -12, the pixel continues to loop around the ring.

Next, you check the button states. First, you check to see if the center button is pressed, and if so, light up the LEDs white, and print to the serial console. Then you check each of the outside buttons, light up a red LED on the ring that corresponds to the location of the button, and print to the serial console.

Finally, you call pixels.show() to update the NeoPixels.

That's all there is to using the ANO rotary encoder with a NeoPixel ring using CircuitPython!

This guide was first published on Oct 05, 2021. It was last updated on Sep 28, 2021.

This page (Python & CircuitPython) was last updated on May 25, 2023.

Text editor powered by tinymce.