kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
encoder.py: improve tracking of detents.
rodzic
95af8c625f
commit
29ec451ad8
|
@ -7,15 +7,15 @@ import uasyncio as asyncio
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
|
|
||||||
class Encoder:
|
class Encoder:
|
||||||
delay = 100 # Pause (ms) for motion to stop
|
delay = 100 # Pause (ms) for motion to stop/limit callback frequency
|
||||||
|
|
||||||
def __init__(self, pin_x, pin_y, v=0, vmin=None, vmax=None, div=1,
|
def __init__(self, pin_x, pin_y, v=0, div=1, vmin=None, vmax=None,
|
||||||
callback=lambda a, b : None, args=(), mod=0):
|
mod=None, callback=lambda a, b : None, args=()):
|
||||||
self._pin_x = pin_x
|
self._pin_x = pin_x
|
||||||
self._pin_y = pin_y
|
self._pin_y = pin_y
|
||||||
self._x = pin_x()
|
self._x = pin_x()
|
||||||
self._y = pin_y()
|
self._y = pin_y()
|
||||||
self._v = 0 # Initialise hardware value
|
self._v = v * div # Initialise hardware value
|
||||||
self._cv = v # Current (divided) value
|
self._cv = v # Current (divided) value
|
||||||
if ((vmin is not None) and v < vmin) or ((vmax is not None) and v > vmax):
|
if ((vmin is not None) and v < vmin) or ((vmax is not None) and v > vmax):
|
||||||
raise ValueError('Incompatible args: must have vmin <= v <= vmax')
|
raise ValueError('Incompatible args: must have vmin <= v <= vmax')
|
||||||
|
@ -44,33 +44,31 @@ class Encoder:
|
||||||
self._v -= 1 if y ^ self._pin_x() else -1
|
self._v -= 1 if y ^ self._pin_x() else -1
|
||||||
self._tsf.set()
|
self._tsf.set()
|
||||||
|
|
||||||
async def _run(self, vmin, vmax, div, modulo, cb, args):
|
async def _run(self, vmin, vmax, div, mod, cb, args):
|
||||||
pv = self._v # Prior hardware value
|
pv = self._v # Prior hardware value
|
||||||
cv = self._cv # Current divided value as passed to callback
|
pcv = self._cv # Prior divided value passed to callback
|
||||||
pcv = cv # Prior divided value passed to callback
|
lcv = pcv # Current value after limits applied
|
||||||
|
plcv = pcv # Previous value after limits applied
|
||||||
delay = self.delay
|
delay = self.delay
|
||||||
while True:
|
while True:
|
||||||
await self._tsf.wait()
|
await self._tsf.wait()
|
||||||
await asyncio.sleep_ms(delay) # Wait for motion to stop
|
await asyncio.sleep_ms(delay) # Wait for motion to stop.
|
||||||
new = self._v # Sample hardware (atomic read)
|
hv = self._v # Sample hardware (atomic read).
|
||||||
a = new - pv # Hardware change
|
if hv == pv: # A change happened but was negated before
|
||||||
# Ensure symmetrical bahaviour for + and - values
|
continue # this got scheduled. Nothing to do.
|
||||||
q, r = divmod(abs(a), div)
|
pv = hv
|
||||||
if a < 0:
|
cv = round(hv / div) # cv is divided value.
|
||||||
r = -r
|
if not (dv := cv - pcv): # dv is change in divided value.
|
||||||
q = -q
|
continue # No change
|
||||||
pv = new - r # Hardware value when local value was updated
|
lcv += dv # lcv: divided value with limits/mod applied
|
||||||
cv += q
|
lcv = lcv if vmax is None else min(vmax, lcv)
|
||||||
if vmax is not None:
|
lcv = lcv if vmin is None else max(vmin, lcv)
|
||||||
cv = min(cv, vmax)
|
lcv = lcv if mod is None else lcv % mod
|
||||||
if vmin is not None:
|
self._cv = lcv # update ._cv for .value() before CB.
|
||||||
cv = max(cv, vmin)
|
if lcv != plcv:
|
||||||
if modulo:
|
cb(lcv, lcv - plcv, *args) # Run user CB in uasyncio context
|
||||||
cv %= modulo
|
|
||||||
self._cv = cv # For value()
|
|
||||||
if cv != pcv:
|
|
||||||
cb(cv, cv - pcv, *args) # User CB in uasyncio context
|
|
||||||
pcv = cv
|
pcv = cv
|
||||||
|
plcv = lcv
|
||||||
|
|
||||||
def value(self):
|
def value(self):
|
||||||
return self._cv
|
return self._cv
|
||||||
|
|
Ładowanie…
Reference in New Issue