Text Editor
Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.
Alternatively, you can use any text editor that saves simple text files.
Code
Copy the code shown below and paste it into Mu, then save it to your CIRCUITPY drive with the name code.py
# SPDX-FileCopyrightText: 2021 Tod Kurt @todbot and John Park for Adafruit Industries # SPDX-License-Identifier: MIT # QT Py encoder based on https://github.com/todbot/qtpy-knob # Retroreflective chromakey light ring # Mount a rotary encoder directly to an Adafruit QT Py, # add some neopixels to get a color/brightness controller # import time import board from digitalio import DigitalInOut, Direction, Pull import neopixel import rotaryio dim_val = 0.2 NUM_PIX = 24 PIX_TYPE = "RGB" # RGB or RGBW if PIX_TYPE == "RGB": ORDER = (1, 0, 2) GREEN = (0, 255, 0) BLUE = (0, 0, 255) WHITE = (255, 255, 255) BLACK = (0, 0, 0) else: ORDER = (1, 0, 2, 3) GREEN = (0, 255, 0, 0) BLUE = (0, 0, 255, 0) WHITE = (0, 0, 0, 255) BLACK = (0, 0, 0, 0) colors = [GREEN, BLUE, WHITE, BLACK] current_color = 0 ring = neopixel.NeoPixel( board.MISO, NUM_PIX, brightness=0.2, auto_write=False, pixel_order=ORDER ) ring.fill(colors[current_color]) ring.show() # button of rotary encoder button = DigitalInOut(board.MOSI) button.pull = Pull.UP # Use pin A2 as a fake ground for the rotary encoder fakegnd = DigitalInOut(board.A2) fakegnd.direction = Direction.OUTPUT fakegnd.value = False encoder = rotaryio.IncrementalEncoder(board.A3, board.A1) print("---Chromakey Light Ring---") last_encoder_val = encoder.position ring_pos = 0 rainbow_pos = 0 last_time = time.monotonic() ring_on = True while True: encoder_diff = last_encoder_val - encoder.position # encoder clicks since last read last_encoder_val = encoder.position if button.value is False: # button pressed current_color = (current_color + 1) % len(colors) ring.fill(colors[current_color]) ring.show() time.sleep(0.5) # debounce else: if encoder_diff > 0: if dim_val >= 0.01: dim_val = (dim_val - 0.01) % 1.0 ring.brightness = dim_val ring.show() elif encoder_diff < 0: if dim_val <= 0.99: dim_val = (dim_val + 0.01) % 1.0 ring.brightness = dim_val ring.show() time.sleep(0.01)
How It Works
Libraries
First, the libraries are imported -- time
for debouncing pauses, board
for pin definitions, digitalio
to set pins to inputs or outputs and to use the encoder knob button, neopixel
for RGB LEDs, and rotaryio
for reading the encoder.
NeoPixel Setup
Next, the dim_val
variable is created and set for the starting brightness value of 20%.
Then NUM_PIX
variable is set to the number of NeoPixels in the ring you're using, in this case 24.
Depending on the type of NeoPixel ring you use, you'll set it to either "RGB" or "RGBW".
PIX_TYPE = "RGB" # RGB or RGBW if PIX_TYPE == "RGB": ORDER = (1, 0, 2) GREEN = (0, 255, 0) BLUE = (0, 0, 255) WHITE = (255, 255, 255) BLACK = (0, 0, 0) else: ORDER = (1, 0, 2, 3) GREEN = (0, 255, 0, 0) BLUE = (0, 0, 255, 0) WHITE = (0, 0, 0, 255) BLACK = (0, 0, 0, 0)
A list for colors
is created so you can cycle between them using the push encoder button, then the ring is set up and turned on to the first color in the list.
colors = [GREEN, BLUE, WHITE, BLACK] current_color = 0 ring = neopixel.NeoPixel( board.MISO, NUM_PIX, brightness=0.2, auto_write=False, pixel_order=ORDER ) ring.fill(colors[current_color]) ring.show()
Pin Setup
You'll set up the encoder pins next. Based on the physical layout of the encoder legs, you'll need to set pin A2 as a "fake" ground by setting it to be an output pin. Thanks again to Tod Kurt for this setup.
The encoder pins are on A3 and A2.
# button of rotary encoder button = DigitalInOut(board.MOSI) button.pull = Pull.UP # Use pin A2 as a fake ground for the rotary encoder fakegnd = DigitalInOut(board.A2) fakegnd.direction = Direction.OUTPUT fakegnd.value = False encoder = rotaryio.IncrementalEncoder(board.A3, board.A1)
The state of the encoder position is stored in the last_encoder_val
variable to compare it to the currently read value, thus detecting if the knob is being turned and if so in which direction.
Main Loop
The main loop of the program does the following things:
Compares the encoder value to the last encoder value.
If the encoder value is increasing (knob is turned clockwise), the brightness is increased. Conversely, if the encoder value is decreasing, the brightness is decreased.
When the push encoder button is pressed, the color is switched to the next one in the colors
list.
while True: encoder_diff = last_encoder_val - encoder.position # encoder clicks since last read last_encoder_val = encoder.position if button.value is False: # button pressed current_color = (current_color + 1) % len(colors) ring.fill(colors[current_color]) ring.show() time.sleep(0.5) # debounce else: if encoder_diff > 0: if dim_val >= 0.01: dim_val = (dim_val - 0.01) % 1.0 ring.brightness = dim_val ring.show() elif encoder_diff < 0: if dim_val <= 0.99: dim_val = (dim_val + 0.01) % 1.0 ring.brightness = dim_val ring.show() time.sleep(0.01)
Page last edited January 21, 2025
Text editor powered by tinymce.