'''
Sencillo menu manejado por un enoder rotativo
'''
import time, micropython
from machine import Pin, I2C, Timer
from ssd1306 import SSD1306_I2C
from lib_oled import FDisplay_lineas, FProled
micropython.alloc_emergency_exception_buf(100)
# Definicion de pines del rotary encoder
sw_a = 4
sw_b = 5
sw_sw = 6
p_a = Pin(sw_a, Pin.IN)
p_b = Pin(sw_b, Pin.IN)
p_s = Pin(sw_sw, Pin.IN)
#------------------------------------------------------
# Oled pins and objects
i2c=I2C(0,sda=Pin(20), scl=Pin(21), freq=400000)
devices = i2c.scan()
#I2C_ADDR = hex(devices[0])
#print(I2C_ADDR)
oled = SSD1306_I2C(128, 64, i2c)
temperatura = 25
cron_running = Timer()
cronometro = 0
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
# ISR routines
def a_isr(pin):
global valor
b=p_b.value()
if b==1:
valor=1
else:
valor=-1
def sw_isr(pin):
global switch_p, sw_presionado, ticks_sw_presionado
ticks_sw_presionado = time.ticks_ms()
sw_presionado = True
switch_p += 1
# ---------------------------------------------- Funciones del menú -------------------------------------------
def FDisplay_cursor() -> None:
if decimal == 0:
x=" " * (11 -menu[item_menu][4]) + "_" if menu[item_menu][4] > 0 else " " * 12 + "_"
else:
x=" " * (12 -menu[item_menu][4]) + " " * decimal + "_"
FProled(oled, x,4)
def FP_Numerico() -> str:
v = menu[item_menu][2]
v += valor/(10**decimal)
if v < menu[item_menu][6]:
v = menu[item_menu][6]
if v > menu[item_menu][5]:
v = menu[item_menu][5]
menu[item_menu][2] = v
formato = "Valor: {:6." + str(menu[item_menu][4]) + "f}"
return formato.format(v)
def FP_Opciones():
op = menu[item_menu][2]
op += valor
if op < 0:
op = 0
if op > menu[item_menu][4] - 1 :
op = menu[item_menu][4] -1
menu[item_menu][2] = op
return menu[item_menu][5][menu[item_menu][2]]
def FImprime_valor() -> None:
t = menu[item_menu][3]() # Llama a la funcion que corresponde y devuelve string con el valor formateado
FProled(oled, t,3)
def FFormat_crono() -> str:
tiempo = time.gmtime(time.time() - crono) # Segundos desde el Running en formato gtime
return "Tiempo: {:2d}:{:2d}:{:2d}".format(tiempo[3], tiempo[4], tiempo[5])
def Fmide_magnitudes() -> Tuple:
return(1.25,12,33) # Retorna Intensidad, Voltaje y temperatura
def Fcron_running(timer):
global energia, temperatura, potencia
i, v, temperatura = Fmide_magnitudes() # mide intensidad y voltaje
potencia = i * v
energia += potencia * 1/3600
lineas = ("Modo: " + menu[0][5][menu[0][2]],
"Int.(A): {:2.3f}".format(i),
"Vol.(V): {:2.2f}".format(v),
"Pot.(W): {:3.2f}".format(potencia),
FFormat_crono(),
"Modo: Running !!",
"Temp:(C): {:3.0f}".format(temperatura),
"Ener.(Wh): {:3.1f}".format(energia))
FDisplay_lineas(oled, lineas)
def FP_Display_review() -> None:
lineas = (
"Modo: " + menu[0][5][menu[0][2]],
"Int.(A): {:2.3f}".format(menu[1][2]),
"Vol.(V): {:2.2f}".format(menu[2][2]),
"Pot.(W): {:2.2f}".format(menu[3][2]),
"Tiempo(Min): {:3.0f}".format(menu[4][2])
)
FDisplay_lineas(oled, lineas)
def FReset_valores() -> None:
global ingreso_campo, item_menu, item_campo, running, review, modo_item_valor
ingreso_campo = [0, 1, 2, 4, 5] # Campos a ingresar Empieza con modo I constante
item_menu=0
item_campo = 0
running = False
review = False
modo_item_valor = 0
FProled(oled, menu[0][1], 1)
# Tablas de menues
menu = [
# para numericos [tipo (1=num, 0=opc, 2=tiempo, 3=temp, 4=energ), "Leyenda", Valor inicial, Funcion, decimales (0-3 = decimales), max, min]
# para opciones [tipo, "Leyenda", Opcion inicial, Funcion, #opciones, ("opciones")]
[0, "Modo (Icte/Pcte)", 0, FP_Opciones, 2, ("Int cte", "Pot cte")],
[1, "Int (.001 a 5 A)", 0, FP_Numerico, 3, 5, 0],
[1, "Volt (0 a 15 V)", 0, FP_Numerico, 2, 15, 0],
[1, "Pot (.01 a 75 W)", 0, FP_Numerico, 2, 75, 0],
[1, "Tiempo: (min)", 0, FP_Numerico, 0, 120, 0],
[0, "status:", 1, FP_Opciones, 3, ("Run", "Review", "Cancel")],
[3, "Temp.(°C): nnn", 0, None],
[4, "Ene (Wh)", 0, None]
]
# 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=sw_isr, trigger=Pin.IRQ_FALLING) # establece IRQ en el switch del encoder
# Inicialización de variables ---------------------------------------------------------------
crono=time.time()
valor=0
switch = 0
FReset_valores() # Empieza con la opción 1:Modo y la imprime en display
while True:
if valor: # Giro del encoder (ignora en modo review)
if modo_item_valor == 0: # Modo items menú: Navega los items del menú
item_campo += valor if (
item_campo < len(ingreso_campo)-1 and valor == 1 or
item_campo > 0 and valor == -1) else 0
# print(ingreso_campo)
item_menu = ingreso_campo [item_campo]
FProled(oled, menu[item_menu][1], 1) # Muestra nuevo item
if menu[item_menu][0] == 1: # Próximo campo es numérico. Arranca con decimal = 0
decimal = 0
else:
FImprime_valor() # Modo valores de items: cambia valores segun funcion propia de c/item
valor = 0 # Valor en 0 hasta próximo evento
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: # Simple click
if running: # Si está en modo Running, hace Stop y vuelve al menú Status
cron_running.deinit()
FProled(oled)
FReset_valores()
elif review: # Esta en review y con botón lo borra
FProled(oled)
FReset_valores()
elif modo_item_valor == 0: # En modo Items menú, Pasa a modo cambio de valor
modo_item_valor = 1
FImprime_valor() # Imprime valor inicial
if menu[item_menu][0] == 1: # Es campo numérico. Va cursor
FDisplay_cursor()
else: # En modo cambio de valores, pasa a cambio de dígito
if menu[item_menu][0] == 1: # el campo es numérico, cambia dígito
decimal += 1
if decimal > menu[item_menu][4]: # Ya se ingresaron todos los dígitos decimales
decimal = 0 # pasa al primer dígito nuevamente
FDisplay_cursor()
switch = 0
elif switch > 1: # Doble click
if menu[item_menu][0] == 0: # Es campo de opciones, Fin de ingreso de opciones
FProled (oled, "", 3)
FProled (oled, "", 4)
if item_menu == 0: # Item Modo
if menu[item_menu][2] == 0:
ingreso_campo =[0, 1, 2, 4, 5] # Modo Normal de operacion, Int cte
else:
ingreso_campo = [0, 2, 3, 4, 5] # Modo Pot cte
elif item_menu == 5: # Item Run/Review/Cancel
if menu[5][2] == 1: # Review
review = True
FP_Display_review()
if menu[5][2] == 0: # Run
running = True
crono = time.time()
energia = 0
FProled(oled)
cron_running.init(period=1000, mode=Timer.PERIODIC, callback=Fcron_running)
else: # Es campo numérico, Fin de ingreso de valor
decimal = 0
FProled(oled, "",4)
FProled(oled, "",3)
modo_item_valor = 0 # Pasa a modo cambio de item
switch = 0
time.sleep(.5)
Loading
ssd1306
ssd1306