from machine import Pin
from picozero import Speaker
import time
# --- 1. 硬件配置 (Pins) ---
# 車用燈: 紅(10), 黃(11), 綠(12)
v_red = Pin(10, Pin.OUT)
v_yellow = Pin(11, Pin.OUT)
v_green = Pin(12, Pin.OUT)
# 行用燈: 紅(18), 綠(19), 請求燈(22)
p_red = Pin(18, Pin.OUT)
p_green = Pin(19, Pin.OUT)
req_led = Pin(22, Pin.OUT)
# 輸入裝置: 按鈕(20), 蜂鳴器(21)
button = Pin(20, Pin.IN, Pin.PULL_DOWN)
buzzer = Speaker(21)
# --- 2. 參數設定 (Variables) ---
MODE = 1 # 1: 下一個紅燈前限按一次; 2: 隨時可按
V_GREEN_TIME = 30 # 車輛綠燈時長
P_TOTAL_GREEN = 20 # 行人綠燈總時長 (含閃爍)
V_PRE_RED = 5 # 車輛準備轉紅 (綠+黃)
V_PRE_GREEN = 3 # 車輛準備轉綠 (紅+黃)
# 計算行人閃爍時間 (最低 8 秒)
P_FLASH_TIME = max(int(P_TOTAL_GREEN / 3), 8)
P_STEADY_GREEN = P_TOTAL_GREEN - P_FLASH_TIME
# --- 3. 系統狀態變量 ---
state = "VEHICLE_PASS" # 初始狀態: 車輛通行
start_time = time.ticks_ms()
request_active = False # 是否有過馬路請求
has_processed_request = False # 模式1專用:本輪是否已處理過請求
def all_off():
"""關閉所有燈號"""
for pin in [v_red, v_yellow, v_green, p_red, p_green, req_led]:
pin.value(0)
def handle_buzzer(pattern_type, current_ms):
"""處理蜂鳴器節奏 (非阻塞)"""
# pattern_type: "slow", "fast", "flash"
cycle_ms = current_ms % 1000
if pattern_type == "slow":
# 慢速: 每秒響 0.1 秒
if cycle_ms < 100: buzzer.on()
else: buzzer.off()
elif pattern_type == "fast":
# 快速: 每 0.2 秒一個週期 (0.1響, 0.1停)
if (cycle_ms % 200) < 100: buzzer.on()
else: buzzer.off()
elif pattern_type == "flash":
# 閃爍 pattern: [XXXX ] 前0.8秒快速, 後0.2秒停
if cycle_ms < 800:
if (cycle_ms % 200) < 100: buzzer.on()
else: buzzer.off()
else:
buzzer.off()
# --- 4. 主循環 ---
print("系統啟動: 當前模式", MODE)
while True:
current_ms = time.ticks_ms()
elapsed = (current_ms - start_time) / 1000
# --- A. 按鈕偵測邏輯 ---
if button.value() == 1:
if not request_active:
if MODE == 1 and not has_processed_request:
request_active = True
req_led.value(1)
print("收到請求 (模式1)")
elif MODE == 2:
request_active = True
req_led.value(1)
print("收到請求 (模式2)")
# --- B. 狀態機邏輯 ---
if state == "VEHICLE_PASS":
# 車綠(12) ON, 行紅(18) ON
all_off()
v_green.value(1)
p_red.value(1)
if request_active: req_led.value(1)
handle_buzzer("slow", current_ms)
# 檢查是否縮短時間
current_limit = V_GREEN_TIME - V_PRE_RED
if request_active and (current_limit - elapsed > 8):
# 剩餘時間大於8秒,縮短至8秒
start_time = current_ms - (current_limit - 8) * 1000
if elapsed >= current_limit:
state = "VEHICLE_PRE_RED"
start_time = current_ms
elif state == "VEHICLE_PRE_RED":
# 車綠+黃(11,12) ON, 行紅(18) ON
all_off()
v_green.value(1)
v_yellow.value(1)
p_red.value(1)
if request_active: req_led.value(1)
handle_buzzer("slow", current_ms)
if elapsed >= V_PRE_RED:
state = "PEDESTRIAN_PASS"
start_time = current_ms
request_active = False # 重置請求
req_led.value(0)
if MODE == 1: has_processed_request = True
elif state == "PEDESTRIAN_PASS":
# 車紅(10) ON, 行綠(19) ON
all_off()
v_red.value(1)
p_green.value(1)
handle_buzzer("fast", current_ms)
if elapsed >= P_STEADY_GREEN:
state = "PEDESTRIAN_FLASH"
start_time = current_ms
elif state == "PEDESTRIAN_FLASH":
# 車紅(10) ON, 行綠(19) 閃爍
all_off()
v_red.value(1)
# 行人綠燈閃爍 (0.5s 切換)
p_green.value(1 if (current_ms // 500) % 2 == 0 else 0)
# 車輛準備轉綠 (最後3秒加入黃燈)
if (P_FLASH_TIME - elapsed) <= V_PRE_GREEN:
v_yellow.value(1)
handle_buzzer("flash", current_ms)
if elapsed >= P_FLASH_TIME:
state = "VEHICLE_PASS"
start_time = current_ms
has_processed_request = False # 開啟新的一輪
time.sleep(0.01) # 稍微減輕 CPU 負擔