零知派ESP32--MCP4728 四通道炫彩呼吸灯控制器
项目概述
本项目利用 零知派ESP32 开发板 控制 MCP4728 四通道 DAC 芯片,驱动红、黄、白、绿四个 LED灯珠模块,实现 6 种动态灯光效果(波浪、追逐、扫描、频闪、随机、心跳)。同时,通过一个 240×240 TFT 彩屏 实时显示当前模式、速度以及随灯光律动的动态边框。两个独立按钮分别切换模式和调节速度,所有设置支持断电记忆,重启后自动恢复上次状态。
项目亮点
-
四通道独立 DAC 输出:MCP4728 提供真模拟电压,0~3.3V 平滑调节 LED 亮度,无 PWM 闪烁。
-
真·呼吸效果:基于正弦函数生成亮度曲线,LED 呼吸如流水般自然。
-
6 种酷炫效果:波浪、追逐、扫描、频闪、随机、心跳,一键切换。
-
屏幕动态边框:屏幕四周的彩色边框会实时跟随 LED 亮度与颜色变化,慢速模式下灯光即使熄灭边框也保留微光,视觉连贯无抖动。
-
断电记忆:自动保存当前模式和速度,重启即恢复。
项目难点及解决方案
-
难点1:MCP4728 的 I2C 通信和库兼容性问题
解决方案:使用 Adafruit MCP4728 库,并采用正确的通道枚举类型(MCP4728_channel_t),避免类型转换错误。 -
难点2:屏幕边框闪烁和抖动
解决方案:通过“智能绘制”策略,取消全局清屏,直接覆盖绘制,慢速模式下即使 LED 熄灭也保持极暗颜色,彻底消除闪烁感。 -
难点3:按键抖动导致误触发
解决方案:采用稳健的软件去抖算法,确保每次按下只响应一次。
一、硬件系统部分
1.1 硬件清单
| 序号 | 元件 | 数量 | 说明 |
|---|---|---|---|
| 1 | 零知派ESP32 开发板 | 1 | 主控制器 |
| 2 | 零知派ESP32扩展板 | 1 | 有屏幕专用接口,带按键 |
| 3 | MCP4728 模块(四通道 DAC) | 1 | I2C 接口,输出模拟电压 |
| 4 | ST7789 240×240 TFT 显示屏 | 1 | SPI 接口,用于显示模式信息 |
| 5 | 零知派 LED灯珠模块(红、黄、白、绿) | 各1 | 用不同颜色展示效果 |
| 6 | 面包板 + 杜邦线 | 若干 | 连接电路 |
| 7 | USB 数据线 | 1 | 给 ESP32 供电及烧录程序 |
1.2 接线方案
| MCP4728 | 零知派ESP32扩展板 |
|---|---|
| VCC | 3.3V |
| GND | GND |
| SDA | GPIO21 |
| SCL | GPIO22 |
LED灯珠模块连接
将每个 LED灯珠模块的IN引脚连接到 MCP4728 的对应输出通道,GND引脚阴极接 ESP32的GND。
-
VOUT_A → 红色 LED → GND
-
VOUT_B → 黄色 LED → GND
-
VOUT_C → 白色 LED → GND
-
VOUT_D → 绿色 LED → GND
1.3 硬件连接图

1.4 实物连接图

二、软件架构设计
2.1 系统初始化
-
串口初始化:用于输出调试信息。
-
加载设置:从 ESP32 的 NVS(非易失性存储)读取上次保存的模式和速度。
-
屏幕初始化:配置 TFT_eSPI 库,显示启动画面。
-
I2C 总线初始化:检测 MCP4728 是否在线。
-
DAC 通道归零:所有 LED 初始为熄灭状态。
-
按钮引脚配置:设置为输入上拉。
2.2 主循环逻辑
-
按键扫描:检测两个按钮,触发模式/速度切换并保存设置。
-
灯光效果更新:根据当前模式调用对应函数,计算四个 DAC 值并写入 MCP4728。
-
屏幕边框绘制:根据四个 LED 的亮度值,实时更新屏幕边框颜色。
-
信息区刷新:只在模式或速度变化时更新屏幕中央的文字和图标。
-
串口状态输出:每秒一次,方便监控。
三、代码拆分讲解
3.1 断电记忆的实现
使用 ESP32 的 Preferences 库,将 currentMode 和 globalSpeed 写入 NVS 分区。在 setup() 中调用 loadSettings() 恢复,每次按钮改变时调用 saveSettings() 保存。
void saveSettings() {
prefs.begin("led_ctrl", false);
prefs.putUChar("mode", currentMode);
prefs.putFloat("speed", globalSpeed);
prefs.end();
}
3.2 呼吸效果的核心——正弦波生成
以波浪模式为例,四个 LED 的亮度曲线为:
float val = (sin(2*PI*cycle + phase[ch]) + 1) / 2;
cycle 是周期内进度,phase 数组提供 0°、90°、180°、270° 的相位偏移,使得四个灯错开亮暗。
3.3 屏幕无闪烁边框绘制
void drawSideSmart(...) {
if (brightness > 0) {
// 直接绘制彩色
tft.fillRect(x, y, w, h, color);
} else {
if (isSlow) {
// 慢速模式绘制极暗颜色,避免全黑造成视觉抖动
tft.fillRect(x, y, w, h, 极暗颜色);
} else {
tft.fillRect(x, y, w, h, TFT_BLACK);
}
}
}
此方法不再预先清除边框,而是直接覆盖,彻底消除闪烁。
四、操作过程及数据展示
4.1 操作步骤
-
硬件连接:正确连接所有模块。
-
编译与上传:在零知派中选择开发板“ESP32 ”,正确选择端口,编译并上传代码。

-
操作体验:
- 上电后屏幕显示启动画面,2秒后进入主界面,默认为“Wave”模式,速度1.0x。
- 短按扩展板GPIO12 按钮:模式依次循环(Wave→Chase→Scan→Strobe→Random→Heartbeat→Wave)。
- 短按扩展板GPIO27 按钮:速度在 0.5x → 1.0x → 1.5x 之间循环。
- 观察 LED 和屏幕边框同步变化,慢速模式边框平滑渐变,快速模式干脆利落。
- 断电后重新上电,模式和速度保持上次的状态。
预期现象:
-
波浪模式:四路 LED 依次明暗,像流动的波浪,屏幕四边框颜色也跟随流动。
-
追逐模式:一个高亮光点在四个 LED 间跳跃,其余灯有拖尾效果。
-
频闪模式:红+白一组、黄+绿一组交替爆闪。
-
心跳模式:所有 LED 同步连续两次快速脉冲后熄灭,模拟心跳。
4.2 视频演示
零知派ESP32--MCP4728 四通道炫彩呼吸灯控制器
五、技术原理
5.1 工作原理
-
MCP4728:内部集成四个 12 位 DAC,通过 I2C 接收数据,输出 0~VDD 的模拟电压。本项目中 VDD 接 3.3V,因此输出电压范围 0~3.3V,对应 DAC 值 0~4095。
-
LED 亮度控制:DAC 输出通过限流电阻直接驱动 LED,电压越高亮度越亮。12 位分辨率可提供 4096 级亮度,远超人眼识别极限,实现极致平滑。
-
屏幕显示:TFT 屏通过 SPI 通信接收像素数据,我们利用
TFT_eSPI库在屏幕上绘制文字、图形,并根据ledBrightness数组实时更新边框矩形颜色。
5.2 工作模式配置
六种模式的核心算法:
-
Wave:
sin(2π·t/T + φ)产生正弦波。 -
Chase:亮点位置
pos = (t/T)*4,其余通道亮度按decay^距离衰减。 -
Scan:三角波
pos = 2t/T(上升段)和2(1 - t/T)(下降段),两组 LED 反向变化。 -
Strobe:取模运算
(t/100ms) % 2产生交替开关。 -
Random:定时器触发
random(0,4096)产生随机亮度。 -
Heartbeat:自定义波形:
sin(π·t/0.1T)快速脉冲,二次稍弱。
六、使用MCP4728模块的好处
| 对比项 | 使用 MCP4728 | ESP32 直接 PWM 输出 |
|---|---|---|
| 通道数 | 4 路,可同时输出 | 通常 16 路 LEDC,但需占用 4 个 GPIO |
| 输出类型 | 真实模拟电压,0~3.3V 平滑连续 | PWM 方波,需滤波才能变为平滑电压,或利用人眼暂留,但摄影时会看到频闪 |
| LED 电流驱动 | DAC 输出电流有限(约15mA),可直驱小功率 LED | GPIO 输出电流可配置,但驱动能力类似,仍需限流电阻 |
| 分辨率 | 12 位(4096 级)真模拟 | 10~16 位 PWM,但有效位数受频率和滤波限制 |
| 亮度平滑度 | 极其平滑,无任何闪烁 | 低频 PWM 可能有闪烁,高频会降低分辨率,滤波复杂 |
| 接线复杂度 | I2C 两根线 + 电源,GPIO 占用少 | 需要 4 个 GPIO,独立控制 |
| 扩展性 | I2C 总线可挂多个 DAC,节省引脚 | 占用 GPIO 较多 |
| 库支持 | Adafruit 库简洁易用 | ESP32 LEDC 库需自行配置通道、频率、分辨率 |
总结使用MCP4728 的好处:
-
真模拟输出:绝对平滑,肉眼和相机均无频闪,适合摄影、氛围灯等对画质要求高的场景。
-
芯片集成度高:四通道一片搞定,节省空间和 GPIO。
-
驱动简单:I2C 通信,无需考虑 PWM 频率、分辨率折衷,代码更简洁。
-
可靠性:DAC 输出为稳定直流,不受 CPU 负载影响,而软件 PWM 可能会因中断导致抖动。
七、常见问题指引
Q1:串口提示 "MCP4728 init failed!"
可能原因:
I2C 接线错误或地址不对。
解决方法:
检查 SDA→GPIO21, SCL→GPIO22, VCC→3.3V, GND→GND;确保模块 A0 引脚电平与代码默认地址 0x60 匹配。
Q2:LED 不亮或亮度极低
可能原因:
LED 极性接反、蓝色/绿色 LED 正向电压过高。
解决方法:
检查 LED 正负极;红色/黄色 LED 更易驱动。
Q3:断电后模式不记忆
可能原因:
代码中未调用 saveSettings() 或 NVS 分区损坏。
解决方法:
确保 saveSettings() 在每次按钮动作时被调用;可尝试擦除 ESP32 闪存后重新烧录。
更多推荐


所有评论(0)