WS2812B灯带项目
刷B站偶然间看到了用电脑控制WS2812B显示各种图案,对此非常感兴趣,于是通过查资料,AI等实现了本项目,项目化驱动学习。
项目概述 本项目基于ESP32的实现智能WS2812B RGB灯带控制,主要是通过该项目学习电路,单片机等相关知识
设计思路分析
硬件架构设计思路 安全第一的设计理念
· 采用电平转换器解决3.3V ESP32与5V WS2812B的通信兼容性问题 · 通过220Ω电阻保护数据信号线,防止电流冲击 · 严格的共地(GND)设计,确保信号稳定性 · 外部独立供电方案,避免USB供电不足和潜在风险
模块化连接策略
· 电源模块:5V5A外部电源 → 定制线 → 灯带供电 · 控制模块:ESP32 → 电平转换 → 灯带数据控制 · 信号调理:串联电阻优化信号质量 · 灵活扩展:面包板设计便于调试和扩展
软件架构设计思路 分层式程序设计
· 底层驱动层:FastLED库提供硬件抽象 · 核心逻辑层:模式管理和动画算法 · 用户交互层:串口命令解析和反馈 · 效果展示层:多种预设灯光模式
状态机设计模式
· 定义8种独立灯光模式,每种模式有专属的状态管理 · 统一的模式切换接口,支持热切换 · 参数持久化设计,保持用户设置
材料准备 WS2812B灯带1条(30灯珠,品牌:btf lighting)
ESP32(WROOM-32E,品牌:源地工作室)
三种杜邦线若干(共对共,母对母,共对母)
面包板
3.3v 5v电平逻辑转换器
5V5A DC电源(内正外负)
特殊定制线(一端DC插座,内正外负,一端分为两正负:裸线正负+杜邦公头正负)
快速接线端子
220R电阻x1
一根USB-A to USB-C 数据线
电路连接 电路连接遵循 共地(GND) 原则,并且注意单片机供电不得 同时接入多个外部电源输入,否则极有可能烧毁电脑主板 ,并且在没有连接好的情况下,绝对不可 以接电源,否则可能触电!
graph TD
A[开始连接WS2812电路] --> B[材料准备]
B --> C[电源部分连接]
B --> D[面包板线路布置]
B --> E[信号线路连接]
C --> C1[5V5A DC电源]
C1 --> C2[连接定制线<br>DC插座端]
C2 --> C3[定制线裸线端<br>通过快速接线端子<br>连接灯带电源正负]
D --> D1[定制线杜邦头<br>连接面包板正负轨道]
D1 --> D2[正轨道引线到<br>逻辑转换器HV VCC]
D1 --> D3[负轨道三根线分别连接:]
D3 --> D4[ESP32GND]
D3 --> D5[逻辑转换器LV GND]
D3 --> D6[逻辑转换器HV GND]
E --> E1[ESP32 GPIO4<br>连接逻辑转换器A1通道]
E1 --> E2[逻辑转换器B1通道<br>串联220R电阻]
E2 --> E3[连接到灯带数据端<br>3pin中间引脚]
E --> E4[ESP32 USB连接电脑<br>供电和数据通讯]
E4 --> E5[ESP32 3.3V输出<br>连接逻辑转换器LV VCC]
C3 --> F[电路连接完成]
E3 --> F
E5 --> F
F --> G[开始编程控制]
%% 样式定义
classDef power fill:#f9f,stroke:#333,stroke-width:2px;
classDef logic fill:#ccf,stroke:#333,stroke-width:2px;
classDef signal fill:#9f9,stroke:#333,stroke-width:2px;
classDef complete fill:#ff9,stroke:#333,stroke-width:3px;
class C1,C2,C3 power;
class D2,D5,D6,E5 logic;
class E1,E2,E3 signal;
class F complete;
补充 如果你考虑不接电脑,那么可以 拔掉 USB与电脑相接的线后,然后在从电源轨道引出一根公对母杜邦线和ESP32的5V的GPIO相连接.
程序烧录 烧录方法 我采用Arduino IDE进行本项目程序编写与烧录
去Arduino IDE官网下载最新的IDE
在File-preference中下滑找到语言选项,选择中文(据说此功能仅限2.x版本)
在文件-首选项中下滑在下面的项目链接,添加:
1 https:// jihulab.com/esp-mirror/ espressif/arduino-esp32/ -/raw/g h-pages/package_esp32_index_cn.json
这个链接是乐鑫官方文档中提供的镜像版本,更多内容可以参考文档 ,切换该文档可以有效解决安装工具链和库的时候无法访问github无法安装的问题。
在工具-开发板-开发板管理器顶部输入esp32,找到由 Espressif Systems 提供的 ESP32 项目。建议安装最新版,如果你用的上面的链接,可能还会有-cn版本,建议安装此版本。
选择开发板:点击 工具 (Tools) > 开发板 (Board)。在弹出的列表中,找到 ESP32 Arduino 分类。这里有很多具体的型号。如果您不确定,一个通用且安全的选择是 ESP32 Dev Module。
选择端口:将您的 ESP32 通过 USB 线连接到电脑。点击 工具 (Tools) > 端口 (Port)。选择一个新出现的端口。在 Windows 上通常是 COMx(如 COM3),在 Mac 上是 /dev/cu.usbmodem...。
7.然后写入你的代码,然后点击验证,如果编译通过了,然后再点上传即可。(首次编译可能较慢)
然后重新上电或者摁复位键,ESP32就会开始工作,你的灯带就会亮起来~哦耶 代码分享: 针对30个灯珠并使用GPIO4,WS2812控制代码。这个代码包含多种灯光模式,可以通过串口命令切换。
硬件连接
WS2812 灯带 ESP32 开发板 VCC (5V) 5V 引脚 GND GND 引脚 DIN (数据线) GPIO 4
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 #include <FastLED.h> #define LED_PIN 4 #define NUM_LEDS 30 #define BRIGHTNESS 100 #define LED_TYPE WS2812 #define COLOR_ORDER GRB CRGB leds[NUM_LEDS];#define MODE_RAINBOW 0 #define MODE_THEATER 1 #define MODE_CONFETTI 2 #define MODE_SOLID 3 #define MODE_BREATH 4 #define MODE_RAIN 5 #define MODE_FIRE 6 #define MODE_COMET 7 #define NUM_MODES 8 uint8_t currentMode = MODE_RAINBOW;uint8_t gHue = 0 ; uint8_t currentBrightness = BRIGHTNESS; CRGB solidColor = CRGB::Blue; void setup () { Serial.begin (115200 ); delay (1000 ); Serial.println ("=== ESP32 WS2812 控制器 ===" ); Serial.println ("连接信息:" ); Serial.println ("- GPIO: 4" ); Serial.println ("- 灯珠数量: 30" ); Serial.println ("- 当前模式: 彩虹" ); Serial.println (); Serial.println ("串口命令:" ); Serial.println ("0-7: 切换模式 (0=彩虹, 1=跑马灯, 2=五彩纸屑, 3=纯色, 4=呼吸, 5=下雨, 6=火焰, 7=彗星)" ); Serial.println ("b100: 设置亮度为100" ); Serial.println ("r/g/b: 纯色模式切换颜色" ); Serial.println ("----------------------------" ); FastLED.addLeds <LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection (TypicalLEDStrip); FastLED.setBrightness (currentBrightness); startupAnimation (); }void loop () { checkSerialCommands (); switch (currentMode) { case MODE_RAINBOW: rainbow (); break ; case MODE_THEATER: theaterChase (); break ; case MODE_CONFETTI: confetti (); break ; case MODE_SOLID: solid (); break ; case MODE_BREATH: breath (); break ; case MODE_RAIN: rain (); break ; case MODE_FIRE: fire (); break ; case MODE_COMET: comet (); break ; } FastLED.show (); }void rainbow () { fill_rainbow (leds, NUM_LEDS, gHue, 7 ); EVERY_N_MILLISECONDS (20 ) { gHue++; } }void theaterChase () { static uint8_t j = 0 ; fill_solid (leds, NUM_LEDS, CRGB::Black); for (int i = 0 ; i < NUM_LEDS; i = i + 3 ) { leds[(i + j) % NUM_LEDS] = CHSV (gHue, 255 , 255 ); } EVERY_N_MILLISECONDS (100 ) { j = (j + 1 ) % 3 ; gHue++; } }void confetti () { fadeToBlackBy (leds, NUM_LEDS, 10 ); int pos = random16 (NUM_LEDS); leds[pos] += CHSV (gHue + random8 (64 ), 200 , 255 ); EVERY_N_MILLISECONDS (30 ) { gHue++; } }void solid () { fill_solid (leds, NUM_LEDS, solidColor); }void breath () { uint8_t breath = (exp (sin (millis () / 2000.0 * PI)) - 0.36787944 ) * 108.0 ; fill_solid (leds, NUM_LEDS, CHSV (gHue, 255 , breath)); EVERY_N_SECONDS (10 ) { gHue += 32 ; } }void rain () { for (int i = 0 ; i < NUM_LEDS - 1 ; i++) { leds[i] = leds[i + 1 ]; leds[i].fadeToBlackBy (20 ); } if (random8 () < 50 ) { leds[NUM_LEDS - 1 ] = CHSV (160 , 200 , 255 ); } else { leds[NUM_LEDS - 1 ] = CRGB::Black; } delay (50 ); }void fire () { for (int i = 0 ; i < NUM_LEDS; i++) { int temperature = map (i, 0 , NUM_LEDS - 1 , 255 , 0 ); temperature = qsub8 (temperature, random8 (0 , 80 )); if (temperature > 200 ) { leds[i] = CRGB (255 , 255 , 255 ); } else if (temperature > 150 ) { leds[i] = CRGB (255 , 255 , 0 ); } else if (temperature > 100 ) { leds[i] = CRGB (255 , 100 , 0 ); } else { leds[i] = CRGB (255 , 0 , 0 ); } leds[i].nscale8_video (temperature); } for (int i = 0 ; i < 3 ; i++) { int flicker = random8 (NUM_LEDS / 3 ); leds[flicker] += CRGB (50 , 25 , 0 ); } delay (30 ); }void comet () { static int cometPosition = 0 ; fadeToBlackBy (leds, NUM_LEDS, 30 ); leds[cometPosition] = CHSV (gHue, 255 , 255 ); for (int i = 1 ; i < 8 ; i++) { int pos = cometPosition - i; if (pos >= 0 ) { leds[pos] = CHSV (gHue, 255 , 255 - (i * 32 )); } } EVERY_N_MILLISECONDS (50 ) { cometPosition = (cometPosition + 1 ) % NUM_LEDS; if (cometPosition == 0 ) { gHue += 32 ; } } }void startupAnimation () { for (int i = 0 ; i <= NUM_LEDS / 2 ; i++) { int left = (NUM_LEDS / 2 ) - i; int right = (NUM_LEDS / 2 ) + i; if (left >= 0 ) leds[left] = CRGB::Green; if (right < NUM_LEDS) leds[right] = CRGB::Green; FastLED.show (); delay (30 ); } for (int i = 0 ; i < NUM_LEDS; i++) { leds[i] = CHSV (i * 8 , 255 , 255 ); FastLED.show (); delay (20 ); } fill_solid (leds, NUM_LEDS, CRGB::Black); FastLED.show (); delay (500 ); }void checkSerialCommands () { if (Serial.available () > 0 ) { String command = Serial.readString (); command.trim (); if (command.length () > 0 ) { char cmd = command.charAt (0 ); if (cmd >= '0' && cmd <= '7' ) { uint8_t newMode = cmd - '0' ; if (newMode != currentMode) { currentMode = newMode; Serial.print ("切换到模式: " ); Serial.println (newMode); printModeName (newMode); } } else if (cmd == 'b' || cmd == 'B' ) { int brightnessValue = command.substring (1 ).toInt (); if (brightnessValue >= 0 && brightnessValue <= 255 ) { currentBrightness = brightnessValue; FastLED.setBrightness (currentBrightness); Serial.print ("亮度设置为: " ); Serial.println (currentBrightness); } } else if (currentMode == MODE_SOLID) { switch (cmd) { case 'r' : case 'R' : solidColor = CRGB::Red; Serial.println ("颜色: 红色" ); break ; case 'g' : case 'G' : solidColor = CRGB::Green; Serial.println ("颜色: 绿色" ); break ; case 'b' : case 'B' : solidColor = CRGB::Blue; Serial.println ("颜色: 蓝色" ); break ; case 'w' : case 'W' : solidColor = CRGB::White; Serial.println ("颜色: 白色" ); break ; case 'y' : case 'Y' : solidColor = CRGB::Yellow; Serial.println ("颜色: 黄色" ); break ; case 'p' : case 'P' : solidColor = CRGB::Purple; Serial.println ("颜色: 紫色" ); break ; } } } } }void printModeName (uint8_t mode) { switch (mode) { case MODE_RAINBOW: Serial.println ("彩虹循环" ); break ; case MODE_THEATER: Serial.println ("跑马灯" ); break ; case MODE_CONFETTI: Serial.println ("五彩纸屑" ); break ; case MODE_SOLID: Serial.println ("纯色" ); break ; case MODE_BREATH: Serial.println ("呼吸灯" ); break ; case MODE_RAIN: Serial.println ("下雨效果" ); break ; case MODE_FIRE: Serial.println ("火焰效果" ); break ; case MODE_COMET: Serial.println ("彗星效果" ); break ; } }
使用说明
上传代码 · 确保已正确安装 ESP32 开发板和 FastLED 库 · 选择正确的开发板(如 ESP32 Dev Module)和端口 · 点击上传
串口控制命令 打开串口监视器(波特率115200),发送以下命令:
模式切换:
· 0 - 彩虹循环 · 1 - 跑马灯 · 2 - 五彩纸屑 · 3 - 纯色模式 · 4 - 呼吸灯 · 5 - 下雨效果 · 6 - 火焰效果 · 7 - 彗星效果
亮度控制:
· b50 - 设置亮度为50 · b150 - 设置亮度为150 · b255 - 设置亮度为255(最亮)
纯色模式颜色切换:
· r - 红色 · g - 绿色 · b - 蓝色 · w - 白色 · y - 黄色 · p - 紫色
电源注意事项 30个WS2812灯珠全白最亮时功耗约 30 × 0.06A × 5V = 9W,建议使用外部5V电源供电,并将外部电源的GND与ESP32的GND连接。
这个代码提供了丰富的灯光效果和完整的控制功能,您可以通过串口实时切换模式和调整参数。
写在最后 本文篇用于记录本次WS2812B项目经过,如有不妥,请见谅。