'''
Sencillo ejemplo de como conectar un rotary encoder mas display
de 7 segmentos utilizando el 74hc595 conectado en cascada. El encoder se maneja
con una sencilla interrupción de hardware. Probado en protoboard funcionando ok.
En este ejemplo, no se utiliza un filtro RC para el encoder porque Wokwi no
cuenta con componentes analógicos, pero hacen falta en la realidad
'''
import time, micropython
from machine import Pin, Timer
# Definicion de pines del MC
CLOCK = 26
LATCH = 27
DATA = 28 # pin DS de dígito unidades
sw_a = 4
sw_b = 5
sw_sw = 6
flash = 7
# pines del 74hc595
p_clk = Pin(CLOCK, Pin.OUT, Pin.PULL_UP)
p_lat = Pin(LATCH, Pin.OUT, Pin.PULL_UP)
p_dat = Pin(DATA, Pin.OUT, Pin.PULL_UP)
# pines del rotary encoder
p_a = Pin(sw_a, Pin.IN)
p_b = Pin(sw_b, Pin.IN)
p_s = Pin(sw_sw, Pin.IN)
p_flash = Pin(flash, Pin.OUT)
cronometro = Timer()
switch_p = 0
cuenta_clicks = 500 # cuenta clicks por 500 ms para saber si es 1 o 2 (o mas)
sw_presionado = False
ticks_sw_presionado = 0
micropython.alloc_emergency_exception_buf(100)
# Tupla con la definicion de segmentos de cada digito
seg=(
#a,b,c,d,e,f,g,p
(1,1,1,1,1,1,0,0), # 0
(0,1,1,0,0,0,0,0), # 1
(1,1,0,1,1,0,1,0), # 2
(1,1,1,1,0,0,1,0), # 3
(0,1,1,0,0,1,1,0), # 4
(1,0,1,1,0,1,1,0), # 5
(1,0,1,1,1,1,1,0), # 6
(1,1,1,0,0,0,0,0), # 7
(1,1,1,1,1,1,1,0), # 8
(1,1,1,1,0,1,1,0) # 9
)
def Fdisp_7s(unid, dec):
'''
Fdisp_7s es una función que muestra los relojes en un display de 7 segmentos de 2 dígitos
el uso es: Fdisp_7s(du: int (0-9), dd: int (0-9))
du y dd son enteros que representan dígitos de 0 a 9 en las unidades y decenas
'''
p_lat.off()
for i in range(7,-1,-1): # envío de dígito mas significativo
p_clk.off()
p_dat.value(seg[dec][i])
p_clk.on()
for i in range(7,-1,-1): # envío de dígito menos significativo
p_clk.off()
p_dat.value(seg[unid][i])
p_clk.on()
p_lat.on()
# ---------------------------
# ISR routine
def a_isr(pin):
global reloj
if not running:
b=p_b.value()
if b==1:
reloj+=5
else:
reloj-=1
def s_isr(pin):
global switch_p, sw_presionado, ticks_sw_presionado
ticks_sw_presionado = time.ticks_ms()
sw_presionado = True
switch_p += 1
def Fcontando(timer) -> None:
global reloj
reloj -= 1
Fdisp_7s(*Funidad_decena(reloj))
if reloj == 0:
Fstop()
pass
def Fstop() -> None:
global running, reloj
running = False
reloj = 0
cronometro.deinit()
p_flash.value(0)
def Funidad_decena(min) -> ():
unid = min % 10
dec = min // 10
return (unid, dec)
# Main
time.sleep(0.1) # Wait for USB to become ready
p_a.irq(handler=a_isr, trigger=Pin.IRQ_FALLING) # establece IRQ en el pin A del encoder
p_s.irq(handler=s_isr, trigger=Pin.IRQ_FALLING) # establece IRQ en el switch del encoder
reloj=0
reloj_ant = 1
switch = 0
running = False
while True:
if sw_presionado: # Botón presionado . Determina si es 1 click o 2
if time.ticks_diff(time.ticks_ms(), ticks_sw_presionado) > cuenta_clicks:
switch = switch_p # switch_p tiene los clicks acumulados en cuenta_clicks ms
switch_p = 0
if switch == 1:
if not running:
cronometro.init(period=1000, mode=Timer.PERIODIC, callback=Fcontando)
running = True
else:
running = False
cronometro.deinit()
if switch == 2:
Fstop()
switch = 0
if reloj != reloj_ant:
if not running:
Fdisp_7s(*Funidad_decena(reloj))
reloj_ant = reloj
time.sleep(1)
if running:
p_flash.value(1-p_flash.value())