ESP32-S3 驱动 WS2812 灯环实现彩虹流光旋转效果 完整教程
难度:⭐⭐☆☆☆(新手可上手) 预计时间:30 分钟 测试环境:Arduino IDE 2.3.8 + FastLED v3.10.3 + ESP32 Arduino Core 3.3.8
TL;DR(快速上手):
- 接线:WS2812 灯环
DIN→ ESP32-S3GPIO40,VCC→ 5V,GND→ GND- 安装库:Arduino 库管理器搜索
FastLED(作者 Daniel Garcia),安装最新版- 按需修改代码里的
NUM_LEDS(灯珠数量)和LED_PIN(引脚)- 烧录,上电,灯环开始转
前言
家里一直躺着一个 WS2812 灯环,本来想等”以后有空”再玩。但见到它吃尘已久,清理清理,顺便做个简单的示例。
WS2812 系列的灯条/灯环/灯块最妙的地方是:整个灯只需要一根数据线,加上电源线,一共就是3条线就可以驱动,每颗 LED 都能独立控制颜色,靠的是内置的驱动芯片。不用译码器,不用位移寄存器,代码几十行搞定。
本文目标:用 ESP32-S3 + FastLED 库,实现一个彩虹颜色沿环旋转的流光动效,全程非阻塞,不影响后续扩展功能。
实验效果

灯环上 40 颗 LED 同时点亮,颜色按彩虹渐变分布,整体色调不停旋转,看起来像一圈彩色光在流动。
元件说明
WS2812 灯环
WS2812 灯环就像传声桶那样——把所有数据发送给第一个 LED ,它自己留下属于自己的那份颜色信息,剩下的传给下一颗,下一颗又留下自己那份颜色,剩下的又给下一颗,如此类推,整条链子依次串联,这又或者叫菊花链(daisy-chain)方式,一根线就能控制几十颗 (甚至几百颗)LED 各自发不同颜色。
例如:数据指令串: [红,蓝,绿,黄]
↓
LED ¹ 拿「红」亮红灯 → 把 [蓝,绿,黄] 传给下一位
↓
LED ² 拿「蓝」亮蓝灯 → 把 [绿,黄] 传给下一位
↓
LED ³ 拿「绿」亮绿灯 → 把 [黄] 传给下一位
...
...
...
| 参数 | 数值 |
|---|---|
| 驱动电压 | 5V |
| 单颗 LED 最大电流 | 60mA(R/G/B 各 20mA 全亮) |
| 数据信号电平 | 兼容 3.3V 逻辑(无需电平转换) |
| 通信协议 | 单总线 NZR(归零码) |
| 色彩顺序 | GRB |
| 刷新率 | 400Hz / 800Hz(取决于型号) |
选它的理由:接线极简(一根数据线),FastLED 原生支持,社区资料丰富,新手不容易踩坑。
WS2812B 一条数据线(单个 GPIO)理论上和实际能驱动多少颗 LED?
理论上限
几乎没有严格限制(可以驱动几千甚至上万颗)。 WS2812B 采用**菊花链(daisy-chain)**方式,后一颗 LED 的 DO 口接下一颗的 DI 口,数据一颗一颗往下传。只要微控制器能及时发出完整的数据帧,理论上可以无限级联。
实际推荐数量(一条数据线)
| 使用场景 | 推荐最大数量 | 说明 |
|---|---|---|
| 流畅动画/游戏(高刷新率) | 300~600 颗 | 推荐范围,刷新率能保持 30~60fps 以上 |
| 一般效果/氛围灯 | 800~1200 颗 | 比较常用上限,刷新率约 15~30fps |
| 极限情况 | 2000~4000+ 颗 | 可行,但刷新率很低(<10fps),信号容易出问题 |
| 专业/大型项目 | 几千~上万颗 | 必须分多条数据线并行驱动(ESP32 很适合) |
主要限制因素
- 刷新率(最关键) 每颗 LED 数据约 30μs(24bit)。
- 1000 颗 ≈ 30ms → 约 33fps
- 2000 颗 ≈ 60ms → 约 16fps(明显卡顿)
- 信号质量
- 数据线太长(>10~15 米)或 LED 数量过多,后面的 LED 容易出现花屏、乱色、闪烁。
- 建议每 500~1000 颗左右加信号放大器(74HCT245 / SN74AHCT125 等)或中继模块。
- 电源(不是数据线限制,但必须解决)
- 每颗全亮白色最大约 60mA(通常 20~30mA 平均)。
- 必须多点注电(每 1~2 米注电一次),否则电压降导致后端变暗/变色。
BOM 表
| 元件 | 规格 | 数量 |
|---|---|---|
| ESP32-S3 开发板 | 任意带 GPIO 的版本均可 | ×1 |
| WS2812 灯环 | 40 颗 LED(或其他数量,代码里改一行) | ×1 |
| 跳线 | 公对母 / 公对公,按实际需求 | 若干 |
元件引脚说明
WS2812 灯环通常有以下 4 个引脚:
| 引脚标注 | 说明 |
|---|---|
| VCC / 5V | 电源正极,接 5V |
| GND | 电源负极,接 GND |
| DIN / Data In | 数据输入,接 ESP32-S3 GPIO |
| DOUT / Data Out | 数据输出,多个灯环级联时使用,本项目不接 |
⚠️ 部分灯环只标
+、-、Data,对应关系一样,别被吓到。
接线方式
| WS2812 灯环引脚 | ESP32-S3 |
|---|---|
| VCC / 5V | 5V(开发板 5V 引脚或外部 5V) |
| GND | GND |
| DIN | GPIO40 |
💡 建议接完之后逐一核对一遍,能省掉 80% 的排错时间。特别注意 VCC 别接 3.3V——灯会亮,但颜色会偏、亮度打折,白白浪费你的调试时间。
需要安装的库
在 Arduino IDE 库管理器里搜索 FastLED,作者是 Daniel Garcia,安装最新版本(本文测试版本:v3.10.3)。
安装路径:工具 → 管理库 → 搜索 FastLED → 安装
完整代码
/*
* ESP32-S3 WS2812 彩虹流光旋转环
* FastLED 非阻塞版 —— 不卡 loop(),方便后续加按键、传感器等功能
*/
#include <FastLED.h>
// ===== 根据你的实际情况修改这里 =====
#define LED_PIN 40 // 数据线接的 GPIO 引脚
#define NUM_LEDS 40 // 灯环上的灯珠数量
#define BRIGHTNESS 204 // 全局亮度,范围 0(全灭)~ 255(全亮)
// ====================================
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB // WS2812 的颜色顺序是 GRB,不是 RGB,别搞反了
CRGB leds[NUM_LEDS]; // 每颗 LED 的颜色数组
uint8_t gHue = 0; // 彩虹起始色相,每帧递增实现"旋转"效果
void setup() {
// 第一步:给硬件 1 秒启动时间,避免上电瞬间电流冲击导致 LED 闪烁
delay(1000);
// 第二步:初始化 FastLED,告诉它用哪个引脚、哪种灯、多少颗
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
.setCorrection(TypicalLEDStrip); // 自动校正色温,让白色看起来更白
// 第三步:设置全局亮度(改这里比改 RGB 数值省事)
FastLED.setBrightness(BRIGHTNESS);
}
void loop() {
// 第四步:用彩虹渐变填满整个灯环
// gHue 是起始色相,255/NUM_LEDS 是每颗 LED 之间的色相间隔
fill_rainbow(leds, NUM_LEDS, gHue, 255 / NUM_LEDS);
// 第五步:把颜色数据推送到灯环
FastLED.show();
// 第六步:每 10ms 色相 +1,数值越小旋转越快,越大越慢
EVERY_N_MILLISECONDS(10) {
gHue++;
}
}
代码说明
| 关键行 | 干了什么 |
|---|---|
fill_rainbow(...) | FastLED 内置函数,自动计算彩虹渐变颜色并填入数组,不用手写 HSV 计算 |
FastLED.show() | 把 leds[] 数组里的颜色数据通过 GPIO40 发送出去,调用这行之前灯不会变 |
EVERY_N_MILLISECONDS(10) | FastLED 内置的非阻塞定时器,等效于”每 10ms 执行一次”,不会卡住 loop() |
gHue++ | 每次色相 +1,下一帧 fill_rainbow 的起始色就偏移了,看起来就像在旋转 |
setCorrection(TypicalLEDStrip) | 自动校正 LED 色温,让混色后的白色不偏绿,适合 WS2812 |
想改旋转速度:调
EVERY_N_MILLISECONDS(10)里的数字,10 → 5 转快一倍,10 → 20 转慢一半。
常见问题排查
别慌,90% 的问题就出在这几个地方:
问题 1:上电后灯完全不亮
- 检查 DIN 是否接到了
GPIO40(代码里LED_PIN定义的引脚) - 确认 VCC 接的是 5V 而不是 3.3V
- 检查 GND 是否连通——GND 没共地,数据信号根本发不出去
问题 2:只有部分灯亮,或者颜色乱闪
- 大概率是供电不足。40 颗 LED 全亮白色时电流高达 2.4A,USB 口的 500mA 撑不住,建议用外部 5V 2A 以上电源
问题 3:颜色怪怪的,明明叫红色显示出来是绿色
COLOR_ORDER定义错了。WS2812B 是 GRB 顺序,把代码里的GRB改成RGB试试,或者反过来
问题 4:编译报错 FastLED.h: No such file
- 库没装上。重新打开库管理器,确认 FastLED 状态显示”已安装”,然后重启 Arduino IDE
问题 5:烧录没问题但灯一直不动
- 检查
NUM_LEDS是否和你的灯环实际灯珠数量一致,数量不对会导致显示异常
FAQ
Q:WS2812 和 WS2812B 有什么区别,代码能通用吗?
A:WS2812B 是 WS2812 的升级版,封装更小、时序略有调整,但 FastLED 对两者都支持。LED_TYPE 填 WS2812B 即可,无需修改其他代码。
Q:我的灯环只有 12/16/24 颗,代码怎么改?
A:只改一行:#define NUM_LEDS 24,换成你的实际灯珠数量,其他不用动。
Q:GPIO40 可以换成其他引脚吗?
A:可以,ESP32-S3 大部分 GPIO 都能用(避开 0、3、45、46 等启动相关引脚)。改 #define LED_PIN 40 里的数字,接线也对应换到那个引脚。
Q:能同时驱动多个灯环吗?
A:可以。每个灯环接一个独立 GPIO,在代码里 addLeds 多调用一次,分配不同的 leds[] 数组段即可。
Q:灯环需要独立供电吗? A:如果灯珠数量 ≤ 8 颗、亮度不开满,开发板 5V 引脚可以带动。超过 8 颗或需要全亮白色,强烈建议外接 5V 2A 以上电源,并让外部电源 GND 和开发板 GND 共地。
Q:EVERY_N_MILLISECONDS 是什么,为什么不直接用 delay()?
A:EVERY_N_MILLISECONDS 是 FastLED 内置的非阻塞定时器,loop() 正常跑,只是每隔指定时间执行一次里面的代码。用 delay() 的话整个程序会卡在那里,没法同时处理按键、串口等其他事情。
Q:彩虹旋转方向能反过来吗?
A:能,把 gHue++ 改成 gHue-- 就反向旋转了。
延伸玩法
- 加按键控制切换特效(呼吸灯 / 跑马灯 / 彩虹流光随时切)
- 接麦克风模块,做音频响应 LED 频谱效果
- 多个灯环级联,DIN 接第一个的 DOUT,实现更长的灯带效果
- 接 OLED 屏幕,显示当前特效名称和亮度数值