# Contador regresivo con displays de ánodo común y 4 botones
from machine import Pin
import time
# CONFIG
DEBUG = False
# Pines de segmentos A-G
ledPins = [
Pin(26, Pin.OUT), # A
Pin(27, Pin.OUT), # B
Pin(14, Pin.OUT), # C
Pin(12, Pin.OUT), # D
Pin(13, Pin.OUT), # E
Pin(25, Pin.OUT), # F
Pin(33, Pin.OUT) # G
]
# Pines de control de displays
unidades = Pin(4, Pin.OUT)
decenas = Pin(5, Pin.OUT)
# LED indicador de fin
ledFin = Pin(32, Pin.OUT)
ledFin.value(0)
# Botones con resistencia pull-up interna
# Conectar: GPIO Pulsador GND
BTN_MODE = Pin(15, Pin.IN, Pin.PULL_UP) # Alterna programar/contar
BTN_INC = Pin(2, Pin.IN, Pin.PULL_UP) # Incrementar
BTN_DEC = Pin(18, Pin.IN, Pin.PULL_UP) # Decrementar
BTN_RESET = Pin(21, Pin.IN, Pin.PULL_UP) # Resetear a 00 y detener
# ESTADO
DEBOUNCE_MS = 80
_last_raw = {
"mode": BTN_MODE.value(),
"inc": BTN_INC.value(),
"dec": BTN_DEC.value(),
"rst": BTN_RESET.value()
}
_last_change = {
"mode": time.ticks_ms(),
"inc": time.ticks_ms(),
"dec": time.ticks_ms(),
"rst": time.ticks_ms()
}
_stable_state = dict(_last_raw)
set_time = 0 # Empieza en 00
i = set_time
counting = False
_last_second = time.ticks_ms()
# Tabla de dígitos (0 = encendido, 1 = apagado -> para ánodo común)
digits = [
0b0000001, # 0
0b1001111, # 1
0b0010010, # 2
0b0000110, # 3
0b1001100, # 4
0b0100100, # 5
0b0100000, # 6
0b0001111, # 7
0b0000000, # 8
0b0000100 # 9
]
# FUNCIONES DISPLAY
def clear_segments_off():
for p in ledPins:
p.value(1)
unidades.value(0)
decenas.value(0)
def showDigit(digit):
for j in range(7):
bit = (digit >> (6 - j)) & 1
ledPins[j].value(bit)
def displayNumber(num):
d = (num // 10) % 10
u = num % 10
# Decenas
clear_segments_off()
showDigit(digits[d])
decenas.value(1)
time.sleep_ms(4)
decenas.value(0)
# Unidades
clear_segments_off()
showDigit(digits[u])
unidades.value(1)
time.sleep_ms(4)
unidades.value(0)
def blink_with_display(number, times=12, period_ms=100):
half = period_ms // 2
for _ in range(times):
ledFin.value(1)
t0 = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), t0) < half:
displayNumber(number)
ledFin.value(0)
t1 = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), t1) < half:
displayNumber(number)
# FUNCIONES BOTONES
def update_button(name, pin):
"""
Manejo de debounce.
Devuelve True solo cuando hay flanco 1->0 (pulsación).
"""
now = time.ticks_ms()
raw = pin.value()
if raw != _last_raw[name]:
_last_raw[name] = raw
_last_change[name] = now
return False
if time.ticks_diff(now, _last_change[name]) >= DEBOUNCE_MS:
if raw != _stable_state[name]:
prev = _stable_state[name]
_stable_state[name] = raw
if prev == 1 and raw == 0: # flanco descendente
if DEBUG:
print("[BTN]", name, "pressed")
return True
return False
# INIT VISUAL
for _ in range(60):
displayNumber(0)
# LOOP PRINCIPAL
while True:
# Mostrar en display
displayNumber(i if counting else set_time)
# Botón MODE -> alterna programar/contar
if update_button("mode", BTN_MODE):
counting = not counting
if counting:
i = set_time
_last_second = time.ticks_ms()
if DEBUG:
print("MODE -> counting =", counting)
# Incrementar (solo programando)
if not counting and update_button("inc", BTN_INC):
if set_time < 99:
set_time += 1
if DEBUG:
print("INC -> set_time =", set_time)
# Decrementar (solo programando)
if not counting and update_button("dec", BTN_DEC):
if set_time > 0:
set_time -= 1
if DEBUG:
print("DEC -> set_time =", set_time)
# Reset -> fuerza a 00 y detiene
if update_button("rst", BTN_RESET):
i = 0
set_time = 0 # CORRECCIÓN: también reinicia el valor programado
counting = False
if DEBUG:
print("RST -> reset to 00")
# Conteo por segundo
if counting and time.ticks_diff(time.ticks_ms(), _last_second) >= 1000:
_last_second = time.ticks_ms()
if i > 0:
i -= 1
if DEBUG:
print("counting:", i)
else:
# Al terminar: parpadea LED y queda en 00
blink_with_display(0, times=12, period_ms=100)
i = set_time + 1
counting = True
if DEBUG:
print("FIN -> back to 00")