趣味灯条
本教程的核心逻辑适用于所有 ESP32 开发板,但所有操作步骤均以 微雪 ESP32-S3-Zero 迷你开发板 为例进行讲解。如果您使用其他型号的开发板,请根据实际情况修改相应设置。
项目介绍
这个项目展示了一个通过电位器控制 WS2812 可编程 LED 灯条的程序。通过旋转电位器,可以实时改变灯条的显示效果:灯条会依次经历三个阶段的颜色变化(黄色 → 绿色 → 红色),亮起的灯珠数量也会随着电位器的旋转而逐渐增加,形成流畅的视觉渐变效果。
硬件连接
需要使用的器件有:
- WS2812 灯条 * 1
- 电位器 * 1
- 面包板 * 1
- 导线
- ESP32 开发板
按照下面接线图连接电路:
ESP32-S3-Zero 引脚图


代码实现
import time
from machine import Pin, ADC
import neopixel
# --- 配置参数 ---
POT_PIN_NUM = 7 # 电位器引脚
NEO_PIN_NUM = 8 # WS2812 引脚
NUM_LEDS = 8 # 灯珠数量
# --- 颜色定义 (R, G, B) ---
COLOR_YELLOW = (255, 255, 0)
COLOR_GREEN = (0, 255, 0)
COLOR_RED = (255, 0, 0)
COLOR_OFF = (0, 0, 0)
# 初始化 WS2812 灯带
np = neopixel.NeoPixel(Pin(NEO_PIN_NUM), NUM_LEDS)
# 初始化电位器 (ADC)
pot = ADC(Pin(POT_PIN_NUM))
def update_leds(adc_val):
"""
根据 ADC 值更新 LED 状态
adc_val: 0 - 65535
"""
# 将 0-65535 映射到 0-24 (3 个阶段 * 8 个灯)
total_steps = 3 * NUM_LEDS
position = int((adc_val / 65535) * total_steps)
# 限制最大值,防止溢出
if position > total_steps:
position = total_steps
for i in range(NUM_LEDS):
# 逻辑判断:优先级从高到低 (红 -> 绿 -> 黄)
# 第三部分:红色覆盖 (当进度超过 16 + 灯的索引)
if position > (2 * NUM_LEDS + i):
np[i] = COLOR_RED
# 第二部分:绿色覆盖 (当进度超过 8 + 灯的索引)
elif position > (1 * NUM_LEDS + i):
np[i] = COLOR_GREEN
# 第一部分:黄色亮起 (当进度超过 灯的索引)
elif position > i:
np[i] = COLOR_YELLOW
# 其他情况:熄灭
else:
np[i] = COLOR_OFF
# 将数据写入灯带
np.write()
# --- 主程序 ---
print("系统启动:电位器控制 WS2812")
while True:
try:
# 读取电位器模拟值 (16 位无符号整数:0 - 65535)
val = pot.read_u16()
# 更新灯光
update_leds(val)
# 简单的延时,防止刷新过快
time.sleep_ms(50)
except KeyboardInterrupt:
# 按下 Ctrl+C 时熄灭所有灯
for i in range(NUM_LEDS):
np[i] = COLOR_OFF
np.write()
print("程序停止")
break
代码解释
-
导入库:
machine库用于控制硬件(ADC 和 GPIO),neopixel库用于控制 WS2812 灯带,time库用于实现延时。ESP32 MicroPython 固件默认包含neopixel库,无需手动安装。 -
配置参数:程序开头定义了电位器引脚号、WS2812 引脚号和灯珠数量。将这些参数集中管理,便于后续根据实际需求快速调整。
# --- 配置参数 ---
POT_PIN_NUM = 7 # 电位器引脚
NEO_PIN_NUM = 8 # WS2812 引脚
NUM_LEDS = 8 # 灯珠数量 -
颜色定义:程序以 RGB 三元组格式定义了四种颜色(黄、绿、红、关闭),每个值的范围是 0-255。这种预定义方式使代码更清晰易读。
# --- 颜色定义 (R, G, B) ---
COLOR_YELLOW = (255, 255, 0)
COLOR_GREEN = (0, 255, 0)
COLOR_RED = (255, 0, 0)
COLOR_OFF = (0, 0, 0) -
硬件初始化:
- 使用
neopixel.NeoPixel()初始化 WS2812 灯带,第一个参数是 GPIO 引脚对象,第二个参数是灯珠数量。 - 使用
machine.ADC()初始化电位器模拟输入。
# 初始化 WS2812 灯带
np = neopixel.NeoPixel(Pin(NEO_PIN_NUM), NUM_LEDS)
# 初始化电位器 (ADC)
pot = ADC(Pin(POT_PIN_NUM)) - 使用
-
核心函数
update_leds():根据电位器的 ADC 值更新 LED 灯带的显示状态。-
参数映射:将 ADC 的 0-65535 范围映射到 0-24(3 个阶段 × 8 个灯珠),代表整个显示进度。
# 将 0-65535 映射到 0-24 (3 个阶段 * 8 个灯)
total_steps = 3 * NUM_LEDS
position = int((adc_val / 65535) * total_steps) -
逐灯判断:遍历每个灯珠,根据当前
position值判断该灯应该显示的颜色。判断逻辑采用从高优先级到低优先级的顺序(红 → 绿 → 黄),确保颜色正确覆盖:for i in range(NUM_LEDS):
# 第三部分:红色覆盖 (当进度超过 16 + 灯的索引)
if position > (2 * NUM_LEDS + i):
np[i] = COLOR_RED
# 第二部分:绿色覆盖 (当进度超过 8 + 灯的索引)
elif position > (1 * NUM_LEDS + i):
np[i] = COLOR_GREEN
# 第一部分:黄色亮起 (当进度超过 灯的索引)
elif position > i:
np[i] = COLOR_YELLOW
# 其他情况:熄灭
else:
np[i] = COLOR_OFF -
数据写入:调用
np.write()将颜色数据发送到 WS2812 灯带。WS2812 采用单线串行通信协议,必须调用此方法才能让设置生效。
-
-
主循环逻辑:程序在一个无限循环
while True中执行以下操作:- 读取电位器:使用
pot.read_u16()读取 16 位无符号整数(范围 0-65535)。 - 更新灯带:调用
update_leds()函数根据读取的值更新灯带显示。 - 延时控制:使用
time.sleep_ms(50)实现 50 毫秒延时,防止刷新过快导致闪烁或资源浪费。
- 读取电位器:使用
-
异常处理:使用
try...except结构增强程序的稳定性。except KeyboardInterrupt:捕获用户中断信号(如 Ctrl+C),在退出前将所有灯珠熄灭,确保硬件处于安全状态。