1+ """
2+ A CircuitPython 'crank' USB HID demo
3+ Uses a ItsyBitsy M0 + Rotary Encoder -> USB HID keyboard
4+ """
5+
6+ import board
7+ from digitalio import DigitalInOut , Direction , Pull
8+ from adafruit_hid .keyboard import Keyboard
9+ from adafruit_hid .keycode import Keycode
10+ from adafruit_hid .consumer_control import ConsumerControl
11+ from adafruit_hid .consumer_control_code import ConsumerControlCode
12+
13+ # Encoder button is a digital input with pullup on D9
14+ button = DigitalInOut (board .D9 )
15+ button .direction = Direction .INPUT
16+ button .pull = Pull .UP
17+
18+ # Rotary encoder inputs with pullup on D10 & D11 on ItsyBitsy
19+ rot_a = DigitalInOut (board .D10 )
20+ rot_a .direction = Direction .INPUT
21+ rot_a .pull = Pull .UP
22+ rot_b = DigitalInOut (board .D11 )
23+ rot_b .direction = Direction .INPUT
24+ rot_b .pull = Pull .UP
25+
26+ # Used to do HID output, see below
27+ kbd = Keyboard ()
28+
29+ ######################### MAIN LOOP ##############################
30+
31+ # the counter counts up and down, it can roll over! 16-bit value
32+ encoder_counter = 0
33+ # direction tells you the last tick which way it went
34+ encoder_direction = 0
35+
36+ # constants to help us track what edge is what
37+ A_POSITION = 0
38+ B_POSITION = 1
39+ UNKNOWN_POSITION = - 1 # initial state so we know if something went wrong
40+
41+ rising_edge = falling_edge = UNKNOWN_POSITION
42+
43+ # get initial/prev state and store at beginning
44+ last_button = button .value
45+ rotary_prev_state = [rot_a .value , rot_b .value ]
46+
47+ while True :
48+ # reset encoder and wait for the next turn
49+ encoder_direction = 0
50+
51+ # take a 'snapshot' of the rotary encoder state at this time
52+ rotary_curr_state = [rot_a .value , rot_b .value ]
53+
54+ if rotary_curr_state != rotary_prev_state :
55+ #print("Changed")
56+ if rotary_prev_state == [True , True ]:
57+ # we caught the first falling edge!
58+ if not rotary_curr_state [A_POSITION ]:
59+ #print("Falling A")
60+ falling_edge = A_POSITION
61+ elif not rotary_curr_state [B_POSITION ]:
62+ #print("Falling B")
63+ falling_edge = B_POSITION
64+ else :
65+ # uhh something went deeply wrong, lets start over
66+ continue
67+
68+ if rotary_curr_state == [True , True ]:
69+ # Ok we hit the final rising edge
70+ if not rotary_prev_state [B_POSITION ]:
71+ rising_edge = B_POSITION
72+ # print("Rising B")
73+ elif not rotary_prev_state [A_POSITION ]:
74+ rising_edge = A_POSITION
75+ # print("Rising A")
76+ else :
77+ # uhh something went deeply wrong, lets start over
78+ continue
79+
80+ # check first and last edge
81+ if (rising_edge == A_POSITION ) and (falling_edge == B_POSITION ):
82+ encoder_counter -= 1
83+ encoder_direction = - 1
84+ print ("%d dec" % encoder_counter )
85+ elif (rising_edge == B_POSITION ) and (falling_edge == A_POSITION ):
86+ encoder_counter += 1
87+ encoder_direction = 1
88+ print ("%d inc" % encoder_counter )
89+ else :
90+ # (shrug) something didn't work out, oh well!
91+ encoder_direction = 0
92+
93+ # reset our edge tracking
94+ rising_edge = falling_edge = UNKNOWN_POSITION
95+
96+ rotary_prev_state = rotary_curr_state
97+
98+ # Check if rotary encoder went up
99+ if encoder_direction == 1 :
100+ ConsumerControl ().send (ConsumerControlCode .VOLUME_DECREMENT ) #Volume Down
101+ # kbd.press(Keycode.LEFT_ARROW)
102+ # kbd.release_all()
103+
104+ # Check if rotary encoder went down
105+ if encoder_direction == - 1 :
106+ ConsumerControl ().send (ConsumerControlCode .VOLUME_INCREMENT ) #Volume Up
107+ # kbd.press(Keycode.RIGHT_ARROW)
108+ # kbd.release_all()
109+
110+ # Button was 'just pressed'
111+ if (not button .value ) and last_button :
112+ print ("Button pressed!" )
113+ kbd .press (Keycode .SPACE ) #Keycode for space bar
114+ kbd .release_all ()
115+
116+ elif button .value and (not last_button ):
117+ print ("Button Released!" )
0 commit comments