from machine import Pin, SPI
import time
import max7219
intentos_fallidos = 0
MAX_INTENTOS = 3
tiempo_bloqueo = 30 # segundos
# ==========================================
# 1. CONFIGURACIÓN DE HARDWARE
# ==========================================
# --- Teclado Matricial 4x4 ---
# Filas en pines 3, 2, 1, 0 y Columnas en 7, 6, 5, 4
filas = [Pin(i, Pin.OUT) for i in [3, 2, 1, 0]]
columnas = [Pin(i, Pin.IN, Pin.PULL_DOWN) for i in [7, 6, 5, 4]]
mapa_teclas = [
["1","2","3","A"],
["4","5","6","B"],
["7","8","9","C"],
["*","0","#","D"]
]
# --- Display de 7 Segmentos ---
# Pines del 8 al 14
segmentos = [Pin(i, Pin.OUT) for i in range(8, 15)]
# Mapa hexadecimal para los estados requeridos:
# 0 -> Acceso denegado, 1 -> Acceso permitido, 2 -> Error en sistema, 3 -> Alerta
mapa_7seg = {
0: [1,1,1,1,1,1,0], # 0
1: [0,1,1,0,0,0,0], # 1
2: [1,1,0,1,1,0,1], # 2
3: [1,1,1,1,0,0,1], # 3
8: [1,1,1,1,1,1,1] # Apagado/Limpiar (Depende si es cátodo o ánodo, asumiendo cátodo)
}
# --- Matriz de LEDs MAX7219 ---
# SPI0: SCK=18, MOSI=19, CS=17
spi = SPI(0, baudrate=1000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
cs = Pin(17, Pin.OUT)
display_matriz = max7219.Matrix8x8(spi, cs, 4)
display_matriz.brightness(8)
# ==========================================
# 2. FUNCIONES DE CONTROL
# ==========================================
def escanear_teclado():
for i, fila in enumerate(filas):
fila.value(1)
for j, col in enumerate(columnas):
if col.value() == 1:
tecla = mapa_teclas[i][j]
print("DEBUG: Tecla detectada ->", tecla)
# Eliminamos el 'while' que bloquea
# Usamos un sleep muy corto solo para el rebote
time.sleep(0.1)
fila.value(0)
return tecla
fila.value(0)
return None
def mostrar_7seg(valor):
if valor in mapa_7seg:
patron = mapa_7seg[valor]
for i in range(7):
segmentos[i].value(patron[i])
else:
# Apagar si el valor no está mapeado
for i in range(7):
segmentos[i].value(0)
def mostrar_mensaje_matriz(texto):
display_matriz.fill(0)
display_matriz.text(texto, 0, 0, 1)
display_matriz.show()
# ==========================================
# 3. LÓGICA DE LA MÁQUINA DE ESTADOS
# ==========================================
PASSWORD_CORRECTA = "1234"
# Teclas especiales
TECLA_INICIO_LIMPIEZA = "*"
TECLA_ENTER = "#"
# Estados
ESTADO_INACTIVO = 0
ESTADO_INGRESANDO = 1
ESTADO_CONCEDIDO = 2
ESTADO_DENEGADO = 3
ESTADO_BLOQUEADO = 4
estado_actual = ESTADO_INACTIVO
buffer_password = ""
mostrar_mensaje_matriz("ESPR") # Patrón de espera
mostrar_7seg(-1) # Apagar 7 segmentos
while True:
tecla = escanear_teclado()
if tecla:
# Reiniciar/Iniciar sistema
if tecla == TECLA_INICIO_LIMPIEZA:
estado_actual = ESTADO_INGRESANDO
buffer_password = ""
mostrar_mensaje_matriz("----")
mostrar_7seg(-1)
elif estado_actual == ESTADO_INGRESANDO:
if tecla == TECLA_ENTER:
if buffer_password == PASSWORD_CORRECTA:
estado_actual = ESTADO_CONCEDIDO
intentos_fallidos = 0
else:
intentos_fallidos += 1
# Verificar si se alcanzó el límite de errores[cite: 1]
if intentos_fallidos >= MAX_INTENTOS:
estado_actual = ESTADO_BLOQUEADO
else:
estado_actual = ESTADO_DENEGADO
else:
if len(buffer_password) < 4:
buffer_password += tecla
mostrar_mensaje_matriz(buffer_password)
# --- Procesamiento de Estados ---
if estado_actual == ESTADO_CONCEDIDO:
mostrar_7seg(1) # Estado 1: Acceso permitido[cite: 1]
mostrar_mensaje_matriz(" OK ")
time.sleep(3)
estado_actual = ESTADO_INACTIVO
mostrar_mensaje_matriz("ESPR")
mostrar_7seg(-1)
buffer_password = ""
elif estado_actual == ESTADO_DENEGADO:
mostrar_7seg(0) # Estado 0: Acceso denegado[cite: 1]
mostrar_mensaje_matriz(" NO ")
time.sleep(2)
estado_actual = ESTADO_INACTIVO
mostrar_mensaje_matriz("ESPR")
mostrar_7seg(-1)
buffer_password = ""
elif estado_actual == ESTADO_BLOQUEADO:
mostrar_7seg(2) # Estado 2: Error en sistema
mostrar_mensaje_matriz("BLOC")
# Bucle de espera no bloqueante para detectar intrusos
inicio_espera = time.time()
while time.time() - inicio_espera < tiempo_bloqueo:
# Si alguien presiona una tecla durante el bloqueo, activamos Alerta
tecla_intrusa = escanear_teclado()
if tecla_intrusa:
mostrar_7seg(3) # Estado 3: Alerta
mostrar_mensaje_matriz("!!!!") # Mensaje visual de alerta
time.sleep(1) # Mantener alerta un segundo
mostrar_7seg(2) # Regresar a mostrar el estado de Error
mostrar_mensaje_matriz("BLOC")
time.sleep(0.1) # Pequeña pausa para no saturar el CPU
# Al terminar el tiempo, resetear el sistema
intentos_fallidos = 0
estado_actual = ESTADO_INACTIVO
mostrar_mensaje_matriz("ESPR")
mostrar_7seg(-1)
buffer_password = ""
time.sleep(0.01)