Skip to content

Instantly share code, notes, and snippets.

@nmorse
Last active February 15, 2021 00:10
Show Gist options
  • Save nmorse/c5f2c5188945dac34ad47c21d57387a8 to your computer and use it in GitHub Desktop.
Save nmorse/c5f2c5188945dac34ad47c21d57387a8 to your computer and use it in GitHub Desktop.
Simulated interrupt handler to test a rotary position algorithm (orig v1 from )
"""
Simulated interrupt handlers to test rotary position algorithms
features changing handles by entering (1 <enter> or 2 <enter>) into the console.
Todo: add more handler algorithms
"""
import board
from digitalio import DigitalInOut, Direction, Pull
import supervisor
# setup pins (a and b) for encoder
pin_a = DigitalInOut(board.D10)
pin_a.direction = Direction.INPUT
pin_a.pull = Pull.UP
pin_b = DigitalInOut(board.D9)
pin_b.direction = Direction.INPUT
pin_b.pull = Pull.UP
# to simulate an interrupt routine (detect pin changes)
last_a = -1
last_b = -1
class RotaryEncoderState :
state = 0
quarter = 0
position = 0
rotary = RotaryEncoderState()
# original algorithm
def interrupt_handler_1 (a, b) :
# a | b | a<<1 | a^b | a<<1 + a^b (aka decimal grey code index)
# --+---+------+-----+---------------
# 0 | 0 | 0 | 0 | 0
# 0 | 1 | 0 | 1 | 1
# 1 | 0 | 2 | 1 | 3
# 1 | 1 | 2 | 0 | 2
new_state = (a << 1) + (a ^ b)
change = (new_state - rotary.state) & 0x03
# print("change", change, "state", state, "new_state", new_state)
if change == 1 :
rotary.quarter += 1
print("quarter", rotary.quarter)
if change == 3 :
rotary.quarter -= 1
print("quarter", rotary.quarter)
# ignore other state transitions
rotary.state = new_state
# logic from the atmel-samd port: provides some damping and scales movement
# down by 4:1.
if rotary.quarter >= 4:
rotary.position += 1
rotary.quarter = 0
print("+++++ position", rotary.position)
if rotary.quarter <= -4 :
rotary.position -= 1
rotary.quarter = 0
print("----- position", rotary.position)
# an alternate version that only changes position at (a=1, b=1)
def interrupt_handler_2 (a, b) :
# a | b | a<<1 | a^b | a<<1 + a^b (aka decimal grey code index)
# --+---+------+-----+---------------
# 0 | 0 | 0 | 0 | 0
# 0 | 1 | 0 | 1 | 1
# 1 | 0 | 2 | 1 | 3
# 1 | 1 | 2 | 0 | 2
new_state = (a << 1) + (a ^ b)
change = (new_state - rotary.state) & 0x03
# print("change", change, "state", state, "new_state", new_state)
if change == 1 :
rotary.quarter += 1
print("quarter", rotary.quarter)
if change == 3 :
rotary.quarter -= 1
print("quarter", rotary.quarter)
# ignore other state transitions
rotary.state = new_state
# logic from the atmel-samd port: provides some damping and scales movement
# down by 4:1.
if rotary.quarter != 0 and rotary.state == 2:
if rotary.quarter > 0 :
rotary.position += 1
rotary.quarter = 0
print("+++++ position", rotary.position)
else :
rotary.position -= 1
rotary.quarter = 0
print("----- position", rotary.position)
# which handler to use
handler_index = "1"
print("\n\nAt any time, you may enter a handler index (1 <enter> or 2 <enter>)")
print("Using handler: {}".format(handler_index))
while True:
if supervisor.runtime.serial_bytes_available:
handler_index = input().strip()
if handler_index == "":
continue
if not (handler_index == "1" or handler_index == "2") :
print("invalid input, Enter a handler index (1 <enter> or 2 <enter>)")
else :
print("Changed to handler: {}".format(handler_index))
a = int(pin_a.value)
b = int(pin_b.value)
# # invert for testing
# a = 0 if a == 1 else 1
# b = 0 if b == 1 else 1
# simulating an interupt routine (only when a or b have changed)
if not a == last_a or not b == last_b :
# print(last_a, "->", a, " | ", last_b, "->", b)
if handler_index == "1" :
interrupt_handler_1(a, b)
if handler_index == "2" :
interrupt_handler_2(a, b)
# simulated interupt routine house keeping
last_a = a
last_b = b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment