228 lines
No EOL
5.9 KiB
Python
228 lines
No EOL
5.9 KiB
Python
from machine import PWM, UART, Pin, Timer
|
|
from micropython import const
|
|
import time
|
|
|
|
_PWM_MAX = const(65535)
|
|
_PWM_FREQ = const(2000)
|
|
|
|
_PIN_EN_MOTOR_VERT = const(14)
|
|
_PIN_A_MOTOR_VERT = const(13)
|
|
_PIN_B_MOTOR_VERT = const(12)
|
|
|
|
_PIN_EN_MOTOR_HOR = const(15)
|
|
_PIN_A_MOTOR_HOR = const(11)
|
|
_PIN_B_MOTOR_HOR = const(10)
|
|
|
|
_PIN_EN_BACKLIGHT = const(17)
|
|
_PIN_A_BACKLIGHT = const(18)
|
|
_PIN_B_BACKLIGHT = const(19)
|
|
_PIN_EN_FRONTLIGHT = const(16)
|
|
_PIN_A_FRONTLIGHT = const(20)
|
|
_PIN_B_FRONTLIGHT = const(21)
|
|
|
|
_PIN_LED_RED_BTN = const(2)
|
|
_PIN_LED_BLU_BTN = const(4)
|
|
|
|
_PIN_RED_BTN = const(3)
|
|
_PIN_BLU_BTN = const(5)
|
|
|
|
_PIN_SENS_END_VERT = const(0)
|
|
_PIN_SENS_CNT_VERT = const(0)
|
|
_PIN_SENS_END_HOR = const(0)
|
|
_PIN_SENS_CNT_HOR = const(0)
|
|
|
|
CMD_MOT_V = 'V' # run vertical motor
|
|
CMD_MOT_H = 'H' # run horizontal motor
|
|
CMD_BL = 'B' # backlight
|
|
CMD_FL = 'F' # frontlight
|
|
CMD_UI = 'U' # user interaction
|
|
CMD_RC = 'C' # recording
|
|
CMD_RW = 'R' # rewind
|
|
|
|
LED = PWM(Pin(25))
|
|
LED.freq(_PWM_FREQ)
|
|
|
|
class Scroll:
|
|
def __init__(self, cnt_pin:Pin, end_pin:Pin, en_pin:PWM, a_pin:Pin, b_pin:Pin) -> None:
|
|
self.c = 0
|
|
self._dir = 0
|
|
self._speed = 0
|
|
self.en_pin = en_pin
|
|
self.a_pin = a_pin
|
|
self.b_pin = b_pin
|
|
self.c_pin = cnt_pin
|
|
self.c_pin.irq(self._count, Pin.IRQ_RISING | Pin.IRQ_FALLING)
|
|
self.e_pin = end_pin
|
|
self.e_pin.irq(self._stop, Pin.IRQ_RISING)
|
|
|
|
def _count(self, pin):
|
|
self.c += self._dir
|
|
|
|
def _stop(self, pin):
|
|
self.a_pin.value(0)
|
|
self.b_pin.value(0)
|
|
|
|
@property
|
|
def dir(self):
|
|
return self._dir
|
|
|
|
@dir.setter
|
|
def dir(self, d):
|
|
self.a_pin.value(1 if d > 0 else 0)
|
|
self.b_pin.value(1 if d < 0 else 0)
|
|
self._dir = d
|
|
|
|
@property
|
|
def speed(self):
|
|
return self._speed * self._dir
|
|
|
|
@speed.setter
|
|
def speed(self, speed):
|
|
self._speed = speed
|
|
self.en_pin.duty_u16(speed * (_PWM_MAX // 100))
|
|
self.dir = (1 if speed > 0 else
|
|
(-1 if speed < 0 else 0))
|
|
|
|
pwm_bl = PWM(Pin(_PIN_EN_BACKLIGHT))
|
|
pwm_bl.freq(_PWM_FREQ)
|
|
pwm_fl = PWM(Pin(_PIN_EN_FRONTLIGHT))
|
|
pwm_fl.freq(_PWM_FREQ)
|
|
pwm_mv = PWM(Pin(_PIN_EN_MOTOR_VERT))
|
|
pwm_mv.freq(_PWM_FREQ)
|
|
pwm_mh = PWM(Pin(_PIN_EN_MOTOR_HOR))
|
|
pwm_mh.freq(_PWM_FREQ)
|
|
|
|
pin_mv_a = Pin(_PIN_A_MOTOR_VERT, Pin.OUT)
|
|
pin_mv_b = Pin(_PIN_B_MOTOR_VERT, Pin.OUT)
|
|
pin_mh_a = Pin(_PIN_A_MOTOR_HOR, Pin.OUT)
|
|
pin_mh_b = Pin(_PIN_B_MOTOR_HOR)
|
|
|
|
led_blu = Pin(_PIN_LED_BLU_BTN, Pin.OUT)
|
|
led_red = Pin(_PIN_LED_RED_BTN, Pin.OUT)
|
|
|
|
btn_blu = Pin(_PIN_BLU_BTN, Pin.IN, Pin.PULL_UP)
|
|
btn_red = Pin(_PIN_RED_BTN, Pin.IN, Pin.PULL_UP)
|
|
|
|
cnt_v = Pin(_PIN_SENS_CNT_VERT, Pin.IN)
|
|
cnt_h = Pin(_PIN_SENS_CNT_HOR, Pin.IN)
|
|
end_v = Pin(_PIN_SENS_END_VERT, Pin.IN)
|
|
end_h = Pin(_PIN_SENS_END_HOR, Pin.IN)
|
|
|
|
uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
|
|
|
|
scroll_h = Scroll(cnt_h, end_h, pwm_mh, pin_mh_a, pin_mh_b)
|
|
scroll_v = Scroll(cnt_v, end_v, pwm_mv, pin_mv_a, pin_mv_b)
|
|
|
|
def motor_vert(*opts):
|
|
_motorctrl(scroll_v, *opts)
|
|
return 'OK'
|
|
|
|
def motor_hor(*opts):
|
|
_motorctrl(scroll_h, *opts)
|
|
return 'OK'
|
|
|
|
def _motorctrl(scroll: Scroll, steps: int, *opts):
|
|
end = scroll.c + steps
|
|
while True:
|
|
err = end - scroll.c
|
|
if abs(err) > 4:
|
|
speed = (err / (2 * steps)) + 0.5
|
|
scroll.speed = int(100 * speed)
|
|
else:
|
|
scroll.speed = 0
|
|
break
|
|
time.sleep_ms(5)
|
|
|
|
def backlight(*opts):
|
|
_fade_led(pwm_bl, *opts)
|
|
return 'OK'
|
|
|
|
def frontlight(*opts):
|
|
_fade_led(pwm_fl, *opts)
|
|
return 'OK'
|
|
|
|
def _fade_led(led_pin: PWM, intensity: int, fade_ms: int, steps: int):
|
|
intensity = intensity * (_PWM_MAX // 100)
|
|
if fade_ms == 0:
|
|
led_pin.duty_u16(intensity)
|
|
return
|
|
|
|
cur_intensity = led_pin.duty_u16()
|
|
step = (intensity - cur_intensity) // steps
|
|
wait = fade_ms // steps
|
|
print(f'{cur_intensity} -> {intensity}, step={step}, wait={wait}')
|
|
|
|
if step != 0:
|
|
for i in range(steps):
|
|
cur_intensity += step
|
|
led_pin.duty_u16(cur_intensity)
|
|
time.sleep_ms(wait)
|
|
|
|
led_pin.duty_u16(intensity)
|
|
|
|
def user_interaction(timeout):
|
|
def _toggle_leds(timer):
|
|
led_blu.toggle()
|
|
led_red.toggle()
|
|
tmr = Timer()
|
|
tmr.init(freq=2, mode=Timer.PERIODIC, callback=_toggle_leds)
|
|
startime = time.ticks_ms()
|
|
timeout *= 1000
|
|
while time.ticks_diff(time.ticks_ms(), startime) < timeout:
|
|
b, r = btn_blu.value(), btn_red.value()
|
|
if (b + r) < 2:
|
|
tmr.deinit()
|
|
return 'B' if not b else 'R'
|
|
time.sleep_ms(50)
|
|
tmr.deinit()
|
|
led_blu.value(0)
|
|
led_red.value(0)
|
|
return 'T' # Timeout
|
|
|
|
def recording(timeout):
|
|
timeout *= 1000
|
|
startime = time.ticks_ms()
|
|
endtime = time.ticks_add(startime, timeout)
|
|
while time.ticks_diff(time.ticks_ms(), startime) < timeout:
|
|
if not btn_blu.value():
|
|
led_red.value(0)
|
|
return 'I'
|
|
restime = time.ticks_diff(endtime, time.ticks_ms())
|
|
if restime < 5000:
|
|
led_red.value((restime // 500) % 2)
|
|
time.sleep_ms(50)
|
|
return 'OK'
|
|
|
|
|
|
def rewind(*opts):
|
|
print(f'rewind({opts})')
|
|
|
|
###############################################################################
|
|
|
|
choice_map = {
|
|
CMD_MOT_V: motor_vert,
|
|
CMD_MOT_H: motor_hor,
|
|
CMD_BL: backlight,
|
|
CMD_FL: frontlight,
|
|
CMD_UI: user_interaction,
|
|
CMD_RW: rewind
|
|
}
|
|
|
|
def parseCmd(cmd_str: str):
|
|
cmd, parm_str = cmd_str.split(':')
|
|
parms = []
|
|
if len(parm_str) != 0:
|
|
parms = [int(x) for x in parm_str.split('+')]
|
|
resp = choice_map[cmd](*parms)
|
|
uart0.write(f'{resp}\n'.encode('utf-8'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
rxData = ''
|
|
while True:
|
|
rxBuf = uart0.read(1)
|
|
if rxBuf is not None:
|
|
rxData += rxBuf.decode('utf-8')
|
|
if rxData.endswith('\n'):
|
|
parseCmd(rxData.strip())
|
|
rxData = '' |