Skip to content

Commit ec1af01

Browse files
author
varna9000
committed
Add encoder lib
1 parent 06ae4c9 commit ec1af01

File tree

2 files changed

+120
-21
lines changed

2 files changed

+120
-21
lines changed

LICENSE

-21
This file was deleted.

rotary_quad_encoder.py

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Licenced under the GNU GPL Version 3
2+
# Copyright (c) 2019 Michael Lehman ([email protected])
3+
# https://github.com/drakoswraith/rotaryquadencoder
4+
#---------------------------------------------------------------------------------------------------------
5+
6+
from machine import Pin
7+
from micropython import const
8+
9+
# Values returned by 'process'
10+
_DIR_NONE = const(0x0) # No complete step yet.
11+
_DIR_CW = const(0x10) # clockwise step
12+
_DIR_CCW = const(0x20) # counter clockwise step
13+
_R_START = const(0x0)
14+
15+
16+
class RotaryQuadEncoder():
17+
RANGE_UNBOUNDED = const(1)
18+
RANGE_WRAP = const(2)
19+
RANGE_BOUNDED = const(3)
20+
21+
def __init__(self, pin1, pin2, pins_pull_up=False, half_steps=False, track_count=False, reverse=False, range_mode=RANGE_UNBOUNDED, min=0, max=1024):
22+
self._ttable = None
23+
self._state = 0x0
24+
self._pinstate = 0x0
25+
self._half_steps = half_steps
26+
27+
self.track_count = track_count # whether or not to track the count
28+
self.reverse = reverse # whether or not to reverse the result - only applies to tracked count
29+
self.count = 0x0
30+
self.range_mode = range_mode # which counting method to use
31+
self.min = min # min and max values for bounded/wrap
32+
self.max = max
33+
34+
if pins_pull_up:
35+
self.pin1 = Pin(pin1, Pin.IN)
36+
self.pin2 = Pin(pin2, Pin.IN)
37+
else:
38+
self.pin1 = Pin(pin1, Pin.IN, Pin.PULL_UP)
39+
self.pin2 = Pin(pin2, Pin.IN, Pin.PULL_UP)
40+
41+
42+
# The below state table has, for each state (row), the new state
43+
# to set based on the next encoder output. From left to right in,
44+
# the table, the encoder outputs are 00, 01, 10, 11, and the value
45+
# in that position is the new state to set.
46+
if self._half_steps:
47+
_R_CCW_BEGIN = 0x1
48+
_R_CW_BEGIN = 0x2
49+
_R_START_M = 0x3
50+
_R_CW_BEGIN_M = 0x4
51+
_R_CCW_BEGIN_M = 0x5
52+
self._ttable = (
53+
(_R_START_M, _R_CW_BEGIN, _R_CCW_BEGIN, _R_START), # R_START (00)
54+
(_R_START_M | _DIR_CCW, _R_START, _R_CCW_BEGIN, _R_START), # R_CCW_BEGIN
55+
(_R_START_M | _DIR_CW, _R_CW_BEGIN, _R_START, _R_START), # R_CW_BEGIN
56+
(_R_START_M, _R_CCW_BEGIN_M, _R_CW_BEGIN_M, _R_START), # R_START_M (11)
57+
(_R_START_M, _R_START_M, _R_CW_BEGIN_M, _R_START | _DIR_CW), # R_CW_BEGIN_M
58+
(_R_START_M, _R_CCW_BEGIN_M, _R_START_M, _R_START | _DIR_CCW), #R_CCW_BEGIN_M
59+
)
60+
else:
61+
_R_CW_FINAL = 0x1
62+
_R_CW_BEGIN = 0x2
63+
_R_CW_NEXT = 0x3
64+
_R_CCW_BEGIN = 0x4
65+
_R_CCW_FINAL = 0x5
66+
_R_CCW_NEXT = 0x6
67+
self._ttable = (
68+
(_R_START, _R_CW_BEGIN, _R_CCW_BEGIN, _R_START), #_R_START
69+
(_R_CW_NEXT, _R_START, _R_CW_FINAL, _R_START | _DIR_CW), #_R_CW_FINAL
70+
(_R_CW_NEXT, _R_CW_BEGIN, _R_START, _R_START), #_R_CW_BEGIN
71+
(_R_CW_NEXT, _R_CW_BEGIN, _R_CW_FINAL, _R_START), #_R_CW_NEXT
72+
(_R_CCW_NEXT, _R_START, _R_CCW_BEGIN, _R_START), #_R_CCW_BEGIN
73+
(_R_CCW_NEXT, _R_CCW_FINAL, _R_START, _R_START | _DIR_CCW), #_R_CCW_FINAL
74+
(_R_CCW_NEXT, _R_CCW_FINAL, _R_CCW_BEGIN, _R_START), # _R_CCW_NEXT
75+
)
76+
self.process() #call once to initialize, else it will take two clicks to start counting
77+
78+
def process(self):
79+
# Grab state of input pins.
80+
self._pinstate = (self.pin2.value() << 1) | self.pin1.value()
81+
# Determine new state from the pins and state table.
82+
self._state = self._ttable[self._state & 0xf][self._pinstate]
83+
# Return emit bits, ie the generated event.
84+
result = self._state & 0x30
85+
86+
if self.track_count:
87+
increment = 0x0
88+
if result == 0x10:
89+
increment = 0x1
90+
elif result == 0x20:
91+
increment = -0x1
92+
93+
if increment != 0x0:
94+
if self.reverse:
95+
increment *= -1
96+
97+
if self.range_mode == self.RANGE_WRAP:
98+
self.count = self._wrap(self.count, increment, self.min, self.max)
99+
elif self.range_mode == self.RANGE_BOUNDED:
100+
self.count = self._bound(self.count, increment, self.min, self.max)
101+
else:
102+
self.count += increment
103+
return self.count
104+
else:
105+
return None
106+
else:
107+
return result
108+
109+
def _wrap(self, value, incr, lower_bound, upper_bound):
110+
range = upper_bound - lower_bound + 1
111+
value = value + incr
112+
113+
if value < lower_bound:
114+
value += range * ((lower_bound - value) // range + 1)
115+
116+
return lower_bound + (value - lower_bound) % range
117+
118+
def _bound(self, value, incr, lower_bound, upper_bound):
119+
return min(upper_bound, max(lower_bound, value + incr))
120+

0 commit comments

Comments
 (0)