人体感应灯
本教程的核心逻辑适用于所有 ESP32 开发板,但所有操作步骤均以 微雪 ESP32-S3-Zero 迷你开发板 为例进行讲解。如果您使用其他型号的开发板,请根据实际情况修改相应设置。
项目介绍
本项目通过 PIR(被动红外)传感器检测人体存在,自动控制 WS2812 LED 灯带的开关,实现智能感应照明功能。当传感器检测到人体活动时,灯带自动点亮;当持续一段时间未检测到活动后,灯带自动熄灭。
硬件连接
需要使用的器件有:
- PIR 运动传感器 * 1
- WS2812 灯条 * 1
- 面包板 * 1
- 导线
- ESP32 开发板
按照下面接线图连接电路:
ESP32-S3-Zero 引脚图


- 电源连接:PIR 传感器和 WS2812 灯带都需要连接到 5V 电源。
- 跳线帽设置:PIR 模块的跳线帽需要设置为 H 模式(高电平触发模式)。
- 调试建议:为方便初次调试,建议先将 PIR 模块的检测距离调节到最低,避免误触发,待功能验证正常后再根据实际需求调整。
代码实现
import time
import machine
import neopixel
# --- 配置 ---
PIR_PIN = 7
LED_PIN = 8
NUM_LEDS = 8
TIMEOUT = 5000 # 也就是人离开后,灯还亮多久(毫秒)
COLOR = (128, 0, 128)
# --- 初始化 ---
pir = machine.Pin(PIR_PIN, machine.Pin.IN, machine.Pin.PULL_DOWN)
np = neopixel.NeoPixel(machine.Pin(LED_PIN), NUM_LEDS)
def switch_light(on):
color = COLOR if on else (0, 0, 0)
np.fill(color)
np.write()
# --- 主程序 ---
try:
print("系统启动。.. (按 Ctrl+C 停止)")
is_on = False
last_motion_time = time.ticks_ms()
# 刚开始先强制关灯,防止状态不同步
switch_light(False)
while True:
current_time = time.ticks_ms()
# --- 核心逻辑修正 ---
# 1. 只要传感器是高电平 (有人),就一直刷新时间戳
if pir.value() == 1:
last_motion_time = current_time
# 如果灯没亮,赶紧点亮
if not is_on:
print("检测到有人 -> 开灯")
switch_light(True)
is_on = True
# 2. 如果传感器是低电平 (无人),才开始计算超时
else:
# 只有灯亮着的时候才需要判断是否超时
if is_on:
# 计算:现在时间 - 最后一次有人时间
duration = time.ticks_diff(current_time, last_motion_time)
if duration > TIMEOUT:
print("超时无人 -> 关灯")
switch_light(False)
is_on = False
# 这里加个小延时,防止关灯电压波动导致的瞬间误触
time.sleep_ms(1000)
# 循环检查频率,100ms 足够了,反应很快且不费电
time.sleep_ms(100)
except KeyboardInterrupt:
print("\n 用户手动停止")
finally:
# 无论发生什么,确保最后灯是灭的
print("清理资源,关闭灯带。..")
switch_light(False)
代码解释
-
导入库:
machine库用于控制硬件(GPIO),neopixel库用于控制 WS2812 LED 灯带,time库用于实现延时和时间戳管理。 -
常量定义:程序开头定义了 PIR 传感器和 LED 灯带的 GPIO 引脚号、LED 数量、超时时长和灯光颜色。将这些参数集中管理,便于后续根据实际需求快速调整,而无需深入修改逻辑代码。
# --- 配置 ---
PIR_PIN = 7
LED_PIN = 8
NUM_LEDS = 8
TIMEOUT = 5000 # 也就是人离开后,灯还亮多久(毫秒)
COLOR = (128, 0, 128) -
GPIO 初始化:使用
machine.Pin类创建 PIR 传感器对象,配置为输入模式并启用下拉电阻;使用neopixel.NeoPixel类创建灯带对象,控制 WS2812 LED。# --- 初始化 ---
pir = machine.Pin(PIR_PIN, machine.Pin.IN, machine.Pin.PULL_DOWN)
np = neopixel.NeoPixel(machine.Pin(LED_PIN), NUM_LEDS)PIR 传感器(被动红外传感器)通过检测人体红外辐射来判断是否有人移动。配置为输入模式并启用下拉电阻,确保在无信号时引脚读数为低电平。
-
辅助函数:
switch_light(on)函数封装了灯带的开关控制。def switch_light(on):
color = COLOR if on else (0, 0, 0)
np.fill(color)
np.write()- 参数
on为True时,所有 LED 设置为COLOR;为False时,设置为(0, 0, 0)即关闭。 np.fill(color)将所有 LED 设置为指定颜色。np.write()将颜色数据写入灯带,使其显示。
- 参数
-
主循环逻辑:程序在一个无限循环
while True中持续监测 PIR 传感器并控制灯光。-
初始化状态:程序启动时强制关灯(
switch_light(False)),确保状态同步。 -
核心逻辑:
-
检测到有人(PIR 高电平):
- 立即刷新时间戳
last_motion_time = current_time。 - 如果灯未亮,则点亮灯并设置
is_on = True。
- 立即刷新时间戳
-
未检测到人(PIR 低电平):
- 仅在灯已亮的情况下才计算超时时长。
- 使用
time.ticks_diff()计算自最后一次检测到人以来的时长。 - 如果超过
TIMEOUT设定的时长,则关灯并设置is_on = False。 - 关灯后延时 1 秒,防止关灯时的电压波动导致误触发。
-
-
循环检查频率:每 100ms 检查一次,既保证快速响应,又避免过度占用 CPU。
-
-
异常处理:使用
try...except...finally结构增强程序稳定性。except KeyboardInterrupt:捕获用户中断(Ctrl+C),允许程序优雅退出。finally:无论程序如何结束,都强制调用switch_light(False)关闭灯带,防止硬件处于不确定状态。