Arduino 发光爱心相框 DIY:TLC5940 驱动 32 灯珠动画教程
项目简介
这款 Arduino 爱心相框平时是普通相框,拨动背部开关瞬间变身浪漫灯光秀。32 颗红色 LED 排成爱心,由两片 TLC5940 16 通道 LED 驱动芯片配合 Arduino Nano 控制,内置 9 种灯光动画模式,是情人节、生日、纪念日的绝佳手作礼物。
相框前期准备
- 准备 18×13cm 普通相框一只,裁剪同尺寸纤维板作底板。
- 绘制 32 颗 LED 爱心排布图,打印贴于纤维板,按位钻孔(建议 5mm 钻头)。
- 插入 LED 时统一朝向:长脚(阳极)朝外,便于后续并联焊接。
- 焊接完成后,用 5V 经 220Ω 电阻逐个测试 LED 是否正常发光。


电路原理图
核心元件:Arduino Nano + 2× TLC5940。TLC5940 提供 16 通道 12bit PWM 恒流驱动,两片级联共控 32 通道。去耦电容(1µF + 0.1µF)靠近芯片电源引脚放置。

元件清单
- Arduino Nano
- 超高亮红色 LED ×32
- TLC5940 LED 驱动芯片 ×2
- 2kΩ 电阻 ×2(TLC5940 电流设定)
- 1µF 及 0.1µF 去耦电容各 2
- 拨动开关、DC 电源插座
- 5V/1A 以上电源适配器
电路板组装与调试
- 万用板焊接 IC 座、排针、电容、电阻,预留电源、信号排针。
- 接线繁多,建议分色导线并逐根对照原理图核对。
- 焊接完成前上传测试代码,确认 32 通道全亮无误后再封装。


Arduino 代码详解
使用 Alex Leone 的 Tlc5940 库,需修改库文件夹下 tlc_config.h 中 NUM_TLCS 为 2。代码采用状态机结构,9 个阶段循环播放不同灯光秀:
- Stage 1:随机点亮 8 颗 LED
- Stage 2:逐颗顺序点亮全亮
- Stage 3:全亮闪烁 7 次
- Stage 4:两端向中间汇聚/展开
- Stage 5:跑马灯式单点移动
- Stage 6:整体呼吸渐变
- Stage 7:奇偶交替闪烁
- Stage 8:双向流星拖尾
- Stage 9:单向流星拖尾后全亮定格
/* LED Heart Photo Frame - Arduino Project
* 作者:Dejan Nedelkovski, www.HowToMechatronics.com
* TLC5940 库:Alex Leone, https://code.google.com/archive/p/tlc5940arduino/
* 需修改 tlc_config.h 中 NUM_TLCS = 2
*/
#include "Tlc5940.h"
int stage = 0;
int randomNumber;
int count = 0;
int brightness = 3500;
int brightUp = 50;
int dir = 1;
void setup() {
Tlc.init();
}
void loop() {
switch (stage) {
// Stage 1: 随机点亮
case 0:
randomNumber = random(0, 32);
Tlc.set(randomNumber, 4095);
delay(1500);
Tlc.update();
if (count >= 8) { stage = 1; count = 0; } else { count++; }
break;
// Stage 2: 顺序全亮
case 1:
delay(75);
for (int i = 31; i >= 0; i--) {
Tlc.set(i, 4095); delay(100); Tlc.update();
}
delay(500); Tlc.clear(); Tlc.update(); stage = 2; delay(500);
break;
// Stage 3: 全亮闪烁
case 2:
for (int i = 0; i <= 31; i++) Tlc.set(i, 4095);
Tlc.update(); delay(500);
Tlc.clear(); Tlc.update(); delay(350);
if (count > 6) { stage = 3; count = 0; } else { count++; }
break;
// Stage 4: 两端汇聚
case 3:
for (int i = 0; i <= 15; i++) {
Tlc.set(i, 4095); Tlc.set(31-i, 4095); Tlc.update(); delay(70);
}
delay(50);
for (int i = 15; i >= 0; i--) {
Tlc.set(i, 0); Tlc.set(31-i, 0); Tlc.update(); delay(70);
}
for (int i = 15; i >= 0; i--) {
Tlc.set(i, 4095); Tlc.set(31-i, 4095); Tlc.update(); delay(70);
}
for (int i = 0; i <= 15; i++) {
Tlc.set(i, 0); Tlc.set(31-i, 0); Tlc.update(); delay(70);
}
delay(50); Tlc.clear(); Tlc.update(); delay(100);
if (count > 1) { stage = 4; count = 0; } else { count++; }
break;
// Stage 5: 跑马灯
case 4:
for (int i = 15; i >= count; i--) {
Tlc.set(32-i, 4095); Tlc.update(); delay(5);
Tlc.set(32-i-1, 0); Tlc.update(); delay(5);
Tlc.set(i, 4095); Tlc.update(); delay(5);
Tlc.set(i+1, 0); Tlc.update(); delay(50);
}
if (count > 15) { Tlc.set(16, 4095); Tlc.update(); delay(2000); stage = 5; count = 0; }
else { count++; }
break;
// Stage 6: 呼吸渐变
case 5:
for (int i = 0; i <= 31; i++) { Tlc.set(i, brightness); Tlc.update(); }
brightness += brightUp;
if (brightness >= 3500) { brightUp = -50; count++; }
if (brightness <= 150) { brightUp = 50; }
if (count > 6) { stage = 6; count = 0; brightness = 3500; Tlc.clear(); Tlc.update(); }
delay(40);
break;
// Stage 7: 奇偶交替
case 6:
for (int i = 0; i <= 30; i+=2) { Tlc.set(i, 4095); Tlc.set(i+1, 0); } Tlc.update(); delay(500);
for (int i = 0; i <= 30; i+=2) { Tlc.set(i, 0); Tlc.set(i+1, 4095); } Tlc.update(); delay(500);
if (count > 20) { stage = 7; count = 0; } else { count++; }
break;
// Stage 8: 双向流星
case 7:
for (int i = 31; i >= 16; i--) {
Tlc.clear(); Tlc.update(); delay(2);
Tlc.set(i, 4095); Tlc.set(i+1, 2000); Tlc.set(i+2, 1000); Tlc.set(i+3, 500);
Tlc.set(i+4, 300); Tlc.set(i+5, 200); Tlc.set(i+6, 100); Tlc.set(i+7, 50); Tlc.set(i+8, 0);
Tlc.set(i-16, 4095); Tlc.set(i-15, 2000); Tlc.set(i-14, 1000); Tlc.set(i-13, 500);
Tlc.set(i-12, 300); Tlc.set(i-11, 200); Tlc.set(i-10, 100); Tlc.set(i-9, 50); Tlc.set(i-8, 0);
Tlc.update(); delay(50);
}
if (count > 8) {
for (int i = 31; i >= 0; i--) { Tlc.set(i, 4095); Tlc.update(); delay(50); }
stage = 8; count = 0;
} else { count++; }
break;
// Stage 9: 单向流星后全亮
case 8:
for (int i = 31; i >= 0; i--) {
Tlc.set(i+8, 4095); Tlc.set(i+7, 2000); Tlc.set(i+6, 1000); Tlc.set(i+5, 500);
Tlc.set(i+4, 300); Tlc.set(i+3, 200); Tlc.set(i+2, 100); Tlc.set(i+1, 50); Tlc.set(i, 0);
Tlc.update(); delay(50);
}
for (int i = 31; i >= 0; i--) { Tlc.set(i, 4095); } Tlc.update(); delay(10);
if (count > 8) { delay(8000); Tlc.clear(); Tlc.update(); stage = 0; count = 0; }
else { count++; }
break;
}
}
封装与完成
- 热熔胶固定 LED 于纤维板背面。
- 用 4 块纤维板搭建电子仓盒盖,热熔胶粘合。
- 接通开关与电源插座导线,放入相片,整体固定于相框。


项目完工!可自行修改代码增加更多动画模式。疑问欢迎评论区交流。
制造工艺
- 自制LUMAZOID:基于Arduino的音乐可视化灯光控制器
- Arduino 红外心率传感器 DIY:低成本高精度,串口绘图器实时波形
- Arduino 音频频率检测:基于 FFT 测量最响亮声音峰值
- Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
- Arduino 井字棋游戏:MAX7219 点阵屏 + 纸板外壳 DIY
- Arduino DIY 电压表:Nokia 5110 屏幕显示,手把手教学
- 从零构建智能 Arduino 四足机器人:完整指南
- 使用 SparkFun 7 段数码管构建可靠的 Arduino 倒计时器
- Arduino RGB LED调色器:三电位器混色入门项目
- DIY Arduino 电子波疗设备 - 基于拉德尼克疗法的 EMR 治疗仪
- 自制 Arduino 遥控保时捷赛车:从改装底盘到手机 App 控制全攻略
- Arduino Nano 与 WS2812 灯带打造 1D 乒乓球游戏——分步 DIY 教程