from machine import Pin
import time
# ---------------- Hardware ----------------
led_red = Pin(14, Pin.OUT)
led_amber = Pin(13, Pin.OUT)
led_green = Pin(12, Pin.OUT)
# Button on GPIO15, use internal pull-up: not pressed = 1, pressed = 0
button = Pin(15, Pin.IN, Pin.PULL_UP)
# ---------------- Helpers ----------------
def all_off():
led_red.value(0)
led_amber.value(0)
led_green.value(0)
def apply_step(pattern, step_idx):
r, y, g = pattern[step_idx]
led_red.value(r)
led_amber.value(y)
led_green.value(g)
return r, y, g
def print_status(mode_fast, step_idx, r, y, g, reason="tick"):
mode_txt = "FAST" if mode_fast else "SLOW"
print("[{}] mode={}, step={}, LEDs=(R:{} Y:{} G:{})".format(
reason, mode_txt, step_idx, r, y, g
))
# ---------------- Patterns & Timings ----------------
pattern_slow = [
(0, 0, 1), # Green
(0, 1, 0), # Yellow
(1, 0, 0), # Red
]
pattern_fast = [
(1, 0, 0), # Red
(0, 1, 0), # Yellow
(0, 0, 1), # Green
]
STEP_MS_SLOW = 1200
STEP_MS_FAST = 500
# ---------------- State ----------------
mode_fast = False # False = slow pattern, True = fast pattern
step_idx = 0 # current index in pattern
last_step_ms = time.ticks_ms()
# Button debounce and edge detection
last_btn = 1 # last read value (1=released due to pull-up)
last_press_ms = 0
DEBOUNCE_MS = 120
# Start clean and show initial state
all_off()
active_pattern = pattern_fast if mode_fast else pattern_slow
r, y, g = apply_step(active_pattern, step_idx)
print_status(mode_fast, step_idx, r, y, g, reason="start")
while True:
# ---- Button edge detection with debounce (falling edge: 1 -> 0) ----
curr = button.value()
if last_btn == 1 and curr == 0:
now = time.ticks_ms()
if time.ticks_diff(now, last_press_ms) > DEBOUNCE_MS:
# Toggle mode on each press
mode_fast = not mode_fast
last_press_ms = now
# Reset to the beginning of the new pattern and APPLY IMMEDIATELY
step_idx = 0
active_pattern = pattern_fast if mode_fast else pattern_slow
r, y, g = apply_step(active_pattern, step_idx)
print_status(mode_fast, step_idx, r, y, g, reason="button-pressed")
# Update step timer so the next step waits a full interval
last_step_ms = now
last_btn = curr
# ---- Choose active pattern and step duration ----
if mode_fast:
active_pattern = pattern_fast
step_ms = STEP_MS_FAST
else:
active_pattern = pattern_slow
step_ms = STEP_MS_SLOW
# ---- Advance pattern based on time (non-blocking) ----
now = time.ticks_ms()
if time.ticks_diff(now, last_step_ms) >= step_ms:
# Move to next step
step_idx = (step_idx + 1) % len(active_pattern)
r, y, g = apply_step(active_pattern, step_idx)
print_status(mode_fast, step_idx, r, y, g, reason="tick")
last_step_ms = now
# Tiny idle delay (keeps CPU cool, doesn’t affect timing)
time.sleep_ms(2)