from machine import Pin, PWM, I2C
from time import ticks_ms, ticks_diff, sleep_ms, sleep_us
LCD_ADDR = 0x27
# ================== LCD 16x2 I2C (PCF8574) ==================
class LCD:
def __init__(self, i2c, addr=0x27):
self.i2c = i2c
self.addr = addr
sleep_ms(50)
for n in (0x30, 0x30, 0x30, 0x20): # modo 4 bits
self._nibble(n)
sleep_ms(5)
self.cmd(0x28) # 2 líneas
self.cmd(0x0C) # pantalla encendida, sin cursor
self.cmd(0x06)
self.clear()
def _nibble(self, n):
# bits: D7-D4 | luz=0x08 | E=0x04 | RW=0x02 | RS=0x01
self.i2c.writeto(self.addr, bytes([n | 0x08 | 0x04]))
sleep_us(2)
self.i2c.writeto(self.addr, bytes([(n | 0x08) & ~0x04]))
sleep_us(60)
def _byte(self, v, rs):
self._nibble((v & 0xF0) | rs)
self._nibble(((v << 4) & 0xF0) | rs)
def cmd(self, c):
self._byte(c, 0)
def clear(self):
self.cmd(0x01)
sleep_ms(3)
def write(self, texto, fila=0):
self.cmd(0x80 | (0x40 * fila))
for ch in (texto + " " * 16)[:16]: # rellena para borrar lo anterior
self._byte(ord(ch), 1)
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100000)
lcd = LCD(i2c, LCD_ADDR)
# ================== PINES ==================
in1 = PWM(Pin(0)) # GP0 -> LED giro derecha
in2 = PWM(Pin(1)) # GP1 -> LED giro izquierda
in1.freq(1000)
in2.freq(1000)
fan = Pin(2, Pin.OUT) # LED del ventilador
led_rojo, led_azul, led_verde = Pin(6, Pin.OUT), Pin(7, Pin.OUT), Pin(8, Pin.OUT)
buzzer = Pin(9, Pin.OUT)
btn_ciclo = Pin(10, Pin.IN, Pin.PULL_UP)
btn_inicio = Pin(11, Pin.IN, Pin.PULL_UP)
btn_paro = Pin(12, Pin.IN, Pin.PULL_UP)
# nombre, vel %, giro s, pausa s, total s, (rojo, azul, verde), ventilador
CICLOS = [
("Caliente", 90, 8, 2, 60, (1, 0, 0), 1),
("Frio", 70, 8, 2, 60, (0, 1, 0), 1),
("Ventilacion", 40, 5, 5, 40, (0, 0, 1), 1),
("Delicada", 35, 4, 4, 50, (0, 1, 1), 0),
]
# ================== FUNCIONES ==================
def motor(vel, direccion): # 1 derecha, -1 izquierda, 0 paro
d = int(vel * 65535 / 100)
in1.duty_u16(d if direccion == 1 else 0)
in2.duty_u16(d if direccion == -1 else 0)
def mostrar(leds):
for pin, v in zip((led_rojo, led_azul, led_verde), leds):
pin.value(v)
def pantalla_seleccion(i):
lcd.write("Ciclo: %d/%d" % (i + 1, len(CICLOS)), 0)
lcd.write(CICLOS[i][0], 1)
def presionado(b): # antirrebote
if b.value() == 0:
sleep_ms(30)
if b.value() == 0:
while b.value() == 0:
sleep_ms(10)
return True
return False
def esperar(seg, inicio, total): # espera, vigila paro y actualiza tiempo
t = ticks_ms()
ultimo = -1
while ticks_diff(ticks_ms(), t) < seg * 1000:
if presionado(btn_paro):
return True
resta = max(total - ticks_diff(ticks_ms(), inicio) // 1000, 0)
if resta != ultimo:
ultimo = resta
lcd.write("Quedan %3d s" % resta, 1)
sleep_ms(10)
return False
def ejecutar(c):
nombre, vel, giro, pausa, total, leds, vent = c
mostrar(leds)
fan.value(vent)
inicio = ticks_ms()
direccion = 1
while ticks_diff(ticks_ms(), inicio) < total * 1000:
motor(vel, direccion)
lcd.write("%s %s" % (nombre, ">>" if direccion == 1 else "<<"), 0)
if esperar(giro, inicio, total):
return "PARO"
motor(0, 0)
lcd.write("%s pausa" % nombre, 0)
if esperar(pausa, inicio, total):
return "PARO"
direccion = -direccion
return "FIN"
def finalizar(resultado): # paro normal: frena, enfría y avisa
motor(0, 0)
mostrar((0, 0, 0))
lcd.write("Fin de ciclo" if resultado == "FIN" else "Paro manual", 0)
lcd.write("Enfriando...", 1)
fan.on()
sleep_ms(3000)
fan.off()
buzzer.on()
sleep_ms(300)
buzzer.off()
# ================== PROGRAMA PRINCIPAL ==================
sel = 0
mostrar(CICLOS[sel][5])
pantalla_seleccion(sel)
while True:
if presionado(btn_ciclo):
sel = (sel + 1) % len(CICLOS)
mostrar(CICLOS[sel][5])
pantalla_seleccion(sel)
if presionado(btn_inicio):
r = ejecutar(CICLOS[sel])
finalizar(r)
mostrar(CICLOS[sel][5])
pantalla_seleccion(sel)