# main_threads.py simplificado (frames intactos, con print)
from machine import Pin, SPI, PWM
import max7219, tm1637, time, _thread
# ----------------------------
# Hardware
# ----------------------------
spi = SPI(1, baudrate=10000000, sck=Pin(25), mosi=Pin(32))
display = max7219.Matrix8x8(spi, Pin(33), 8)
display.brightness(5); display.fill(0); display.show()
button = Pin(16, Pin.IN, Pin.PULL_UP)
buzzer = PWM(Pin(26)); buzzer.duty(0)
ir1, ir2 = Pin(5, Pin.IN), Pin(19, Pin.IN)
tm = tm1637.TM1637(clk=Pin(14), dio=Pin(12))
sem_rojo, sem_amar, sem_verde = Pin(2, Pin.OUT), Pin(0, Pin.OUT), Pin(4, Pin.OUT)
# Locks
lock_display, lock_buzzer, lock_tm = _thread.allocate_lock(), _thread.allocate_lock(), _thread.allocate_lock()
# ----------------------------
# Frames del muñeco (se dejan tal cual)
# ----------------------------
frame1 = [
".......XXX......",
".....XXXXXXX....",
"....XXXXXXXXX...",
"...XXXXXXXXXXX..",
"...XXXXXXXXXXX..",
"...XXXXXXXXXXX..",
"....XXXXXXXXX...",
".....XXXXXXX....",
".......XXX......",
".....XXXXXXX....",
"....XX.XXX.XX...",
"....XX.XXX.XX...",
"....XX.XXX.XX...",
"....XX.XXX.XX...",
"....XX.XXX.XX...",
".......XXX......",
"......XXXXX.....",
".....XX...XX....",
".....XX...XX....",
".....XX...XX....",
".....XX...XX....",
".....XX...XX....",
".....XX...XX....",
"................",
]
frame2 = [
".......XXX......",
".....XXXXXXX....",
"....XXXXXXXXX...",
"...XXXXXXXXXXX..",
"...XXXXXXXXXXX..",
"...XXXXXXXXXXX..",
"....XXXXXXXXX...",
".....XXXXXXX....",
".......XXX......",
".....XXXXXXX....",
"....XX.XXX.XXX..",
"....XX.XXX..XXX.",
".XX.XX.XXX...XX.",
"..XXXX.XXX..XX..",
"...XX..XXX.XX...",
".......XXX......",
"......XXXXX.....",
"....XXX...XX....",
"...XX.....XX....",
"...XX.....XX....",
"...XX......XX.X.",
"....XXX.....XX.X",
".....X..........",
"................",
]
frames = [frame1, frame2]
# ----------------------------
# Funciones auxiliares
# ----------------------------
def set_pixel(x, y, val=1):
module = (y // 8) * 4 + (x // 8)
display.pixel(module * 8 + (x % 8), y % 8, val)
def rotate_frame(frame):
return ["".join(frame[y][len(frame[0])-1-x] for y in range(len(frame))) for x in range(len(frame[0]))]
def draw_frame_on_display(frame, x_offset=8):
if not lock_display.acquire(False): return
try:
display.fill(0)
for y, row in enumerate(rotate_frame(frame)):
for x, c in enumerate(row):
if c == "X": set_pixel(x + x_offset, y)
display.show()
finally:
lock_display.release()
# ----------------------------
# Buzzer
# ----------------------------
melody = [262, 330, 392, 523]
def play_melody_once():
if not lock_buzzer.acquire(False): return
try:
for note in melody:
buzzer.freq(note); buzzer.duty(512); time.sleep(0.15)
buzzer.duty(0); time.sleep(0.03)
finally:
buzzer.duty(0); lock_buzzer.release()
# ----------------------------
# TM1637
# ----------------------------
def mostrar_velocidad(valor):
if not lock_tm.acquire(False):
time.sleep_ms(50)
if not lock_tm.acquire(False): return
try:
tm.show("----") if valor > 9999 else tm.number(int(valor))
finally:
lock_tm.release()
# ----------------------------
# Hilos
# ----------------------------
def thread_medir_velocidad():
print("Hilo velocidad iniciado")
while True:
while ir1.value(): time.sleep_ms(5)
t1 = time.ticks_ms()
while not ir1.value(): time.sleep_ms(2)
detected2 = False
while time.ticks_diff(time.ticks_ms(), t1) < 5000:
if not ir2.value():
t2 = time.ticks_ms()
while not ir2.value(): time.sleep_ms(2)
detected2 = True; break
time.sleep_ms(5)
if not detected2:
print("Timeout: no se detectó IR2")
continue
dt = time.ticks_diff(t2, t1)/1000
if dt <= 0:
print("Error en medición dt<=0")
continue
v = int((1/dt)*3.6)
print("Tiempo:", dt, "s → Vel:", v, "km/h")
mostrar_velocidad(v)
time.sleep_ms(200)
boton_habilitado = False
def thread_button_animation():
global boton_habilitado
print("Hilo botón iniciado")
while True:
if not button.value() and boton_habilitado:
time.sleep_ms(200)
if not button.value():
print("Botón presionado: lanzando animación y melodía (30s)")
start = time.time()
while time.time()-start < 30:
for f in frames:
draw_frame_on_display(f)
play_melody_once()
if time.time()-start >= 30: break
time.sleep(0.4)
buzzer.duty(0)
if lock_display.acquire(True):
display.fill(0); display.show(); lock_display.release()
time.sleep_ms(500)
time.sleep_ms(50)
def thread_semaforo():
global boton_habilitado
print("Hilo semáforo iniciado")
while True:
sem_verde.value(1); sem_amar.value(0); sem_rojo.value(0)
print("Semáforo: VERDE 30s"); time.sleep(30)
sem_verde.value(0); sem_amar.value(1); sem_rojo.value(0)
print("Semáforo: AMARILLO 2s"); time.sleep(2)
sem_verde.value(0); sem_amar.value(0); sem_rojo.value(1)
print("Semáforo: ROJO 30s")
boton_habilitado = True;
for i in range(7):
print("Contador botón habilitado:", 7-i, "s"); time.sleep(1)
boton_habilitado = False; time.sleep(23)
sem_verde.value(0); sem_amar.value(1); sem_rojo.value(0)
print("Semáforo: transición a VERDE"); time.sleep(2)
sem_amar.value(0)
# ----------------------------
# Lanzar hilos
# ----------------------------
print("Iniciando hilos...")
for f in [thread_medir_velocidad, thread_button_animation, thread_semaforo]:
_thread.start_new_thread(f, ())