跳到主要内容

交通灯

重要提示:关于开发板的兼容性

本教程的核心逻辑适用于所有 ESP32 开发板,但所有操作步骤均以 微雪 ESP32-S3-Zero 迷你开发板 为例进行讲解。如果您使用其他型号的开发板,请根据实际情况修改相应设置。

项目介绍

这个项目展示了一个交通灯的模拟程序,通过 ESP32 的 GPIO 引脚控制三个 LED 灯的亮灭,模拟交通灯的红、黄、绿灯切换过程。

硬件连接

需要使用的器件有:

  • LED * 3
  • 330Ω 电阻 * 3
  • 面包板 * 1
  • 导线
  • ESP32 开发板

按照下面接线图连接电路:

ESP32-S3-Zero 引脚图

ESP32-S3-Zero-Pinout

接线图

代码实现

import time
import machine

# 定义红、黄、绿灯分别连接的 GPIO 引脚号
RED_LED_PIN = 7
YELLOW_LED_PIN = 8
GREEN_LED_PIN = 9

# 定义红、绿、黄灯各自的持续时间
RED_LIGHT_DURATION = 10 # 红灯亮 10 秒
GREEN_LIGHT_DURATION = 8 # 绿灯亮 8 秒
YELLOW_LIGHT_DURATION = 3 # 黄灯阶段总共持续 3 秒
YELLOW_BLINK_INTERVAL = 0.5 # 黄灯闪烁间隔

# 初始化 LED 引脚为输出模式
red_led = machine.Pin(RED_LED_PIN, machine.Pin.OUT)
yellow_led = machine.Pin(YELLOW_LED_PIN, machine.Pin.OUT)
green_led = machine.Pin(GREEN_LED_PIN, machine.Pin.OUT)

def all_lights_off():
"""一个辅助函数,用于关闭所有灯。"""
red_led.off()
yellow_led.off()
green_led.off()

# 程序开始
print("交通灯模拟程序开始运行。..")
print(f"配置:红灯={RED_LIGHT_DURATION}s, 绿灯={GREEN_LIGHT_DURATION}s, 黄灯={YELLOW_LIGHT_DURATION}s")
print(f"黄灯闪烁间隔:{YELLOW_BLINK_INTERVAL}s")

try:
# 创建一个无限循环来模拟交通灯的持续工作
while True:
# --- 绿灯阶段 ---
print("绿灯亮")
all_lights_off() # 先关闭所有灯,确保状态干净
green_led.on() # 点亮绿灯
time.sleep(GREEN_LIGHT_DURATION) # 等待绿灯设定的时间

# --- 黄灯闪烁阶段 ---
print("黄灯闪烁")
green_led.off() # 熄灭绿灯

# 计算在指定的黄灯总时长内,应该闪烁多少次
# 一个完整的闪烁周期是 (亮 + 灭),时长为 YELLOW_BLINK_INTERVAL * 2
# 用总时长除以单个周期时长,得到闪烁次数
num_blinks = int(YELLOW_LIGHT_DURATION / (YELLOW_BLINK_INTERVAL * 2))

# 确保即使设置的总时间很短,也至少会闪烁一次
if num_blinks == 0:
num_blinks = 1

for _ in range(num_blinks):
yellow_led.on() # 点亮黄灯
time.sleep(YELLOW_BLINK_INTERVAL) # 亮一会
yellow_led.off() # 熄灭黄灯
time.sleep(YELLOW_BLINK_INTERVAL) # 灭一会

# 确保在进入红灯阶段前,黄灯是熄灭的
yellow_led.off()

# --- 红灯阶段 ---
print("红灯亮")
# 此时黄灯和绿灯已经熄灭,只需点亮红灯
red_led.on()
time.sleep(RED_LIGHT_DURATION) # 等待红灯设定的时间

except KeyboardInterrupt:
print("\n 程序被用户中断。")

finally:
# 无论程序是正常结束还是被中断,最后都确保所有灯都关闭
all_lights_off()
print("所有交通灯已关闭,程序结束。")

代码解释

  • 导入库machine 库用于控制硬件,time 库用于实现延时。

  • 常量定义:程序开头定义了 GPIO 引脚号(RED_LED_PIN 等)和各灯持续时间(RED_LIGHT_DURATION 等)。将这些参数集中管理,便于后续根据实际需求快速调整,而无需深入修改逻辑代码。

    # 定义红、黄、绿灯分别连接的 GPIO 引脚号
    RED_LED_PIN = 7
    YELLOW_LED_PIN = 8
    GREEN_LED_PIN = 9

    # 定义红、绿、黄灯各自的持续时间
    RED_LIGHT_DURATION = 10 # 红灯亮 10 秒
    GREEN_LIGHT_DURATION = 8 # 绿灯亮 8 秒
    YELLOW_LIGHT_DURATION = 3 # 黄灯阶段总共持续 3 秒
    YELLOW_BLINK_INTERVAL = 0.5 # 黄灯闪烁间隔
  • 引脚初始化:使用 machine.Pin 类创建三个对象,分别对应红、黄、绿灯。machine.Pin.OUT 参数将引脚配置为输出模式,允许程序控制高低电平。

    # 初始化 LED 引脚为输出模式
    red_led = machine.Pin(RED_LED_PIN, machine.Pin.OUT)
    yellow_led = machine.Pin(YELLOW_LED_PIN, machine.Pin.OUT)
    green_led = machine.Pin(GREEN_LED_PIN, machine.Pin.OUT)
  • 辅助函数all_lights_off() 函数用于同时关闭所有 LED。在状态切换前调用此函数,可以确保没有灯处于意外点亮的状态,提高代码的健壮性。

    def all_lights_off():
    """一个辅助函数,用于关闭所有灯。"""
    red_led.off()
    yellow_led.off()
    green_led.off()
  • 主循环逻辑:程序在一个无限循环 while True 中依次执行三个阶段:

    • 绿灯阶段:先调用 all_lights_off() 清除状态,点亮绿灯,并延时 GREEN_LIGHT_DURATION 秒。
    • 黄灯闪烁:计算闪烁次数(总时长除以单次周期),通过 for 循环控制黄灯交替亮灭,模拟警示效果。
    • 红灯阶段:点亮红灯并延时 RED_LIGHT_DURATION 秒。由于黄灯已在上一阶段结束时熄灭,此处直接点亮红灯即可。
  • 异常处理:使用 try...except...finally 结构增强程序的稳定性。

    • except KeyboardInterrupt:捕获用户中断信号(如 Ctrl+C),允许程序优雅退出。
    • finally:无论程序正常结束还是被中断,都会执行 all_lights_off() 关闭所有灯,防止硬件处于不确定状态。

参考链接