AI 帮我做一个光立方:Linux 环境下从电路设计到单片机编程的完整教程
零基础上手,用 AI 辅助完成一个炫酷的 3D LED 光立方项目
💡 提示: 本文配套开源项目(含原理图、PCB、源码)已上传 GitHub,文末获取!
📌 前言
光立方是一个经典的电子制作项目,通过 64 颗 LED 组成 4×4×4 的三维阵列,利用视觉暂留原理实现各种炫酷的 3D 动画效果。
传统教程往往只讲硬件或只讲软件,而且大多基于 Windows 环境。今天这篇教程,我将展示如何在 Linux 系统下,借助 AI 大模型的辅助,从零开始完成一个完整的光立方项目。
全程使用免费开源工具,总成本不到 50 元!
🎯 项目目标
- ✅ 在 Linux 环境下完成电路设计(KiCad)
📦 一、材料清单
1.1 核心元件
实物参考:
┌────────────────────────────────────────┐
│ LED ×64 STM32 74HC595 ULN2003 │
│ ●●●● ┌───┐ ┌────┐ ┌────┐ │
│ ●●●● │ ● │ │ ●● │ │ ●● │ │
│ ●●●● └───┘ └────┘ └────┘ │
│ 电阻×64 排针若干 PCB 板 5V 电源 │
└────────────────────────────────────────┘
| 元件 |
规格 |
数量 |
单价 |
小计 |
| LED |
3mm 发光二极管 |
64 颗 |
¥0.1 |
¥6.4 |
| 单片机 |
STM32F103C8T6 |
1 片 |
¥15 |
¥15 |
| 移位寄存器 |
74HC595 |
2 片 |
¥1 |
¥2 |
| 驱动芯片 |
ULN2003 |
4 片 |
¥1 |
¥4 |
| 电阻 |
220Ω 1/4W |
64 个 |
¥0.01 |
¥0.6 |
| 排针排母 |
2.54mm |
若干 |
- |
¥5 |
| PCB 板 |
定制或洞洞板 |
1 块 |
¥0 |
¥0 |
| 电源 |
5V 1A |
1 个 |
¥10 |
¥10 |
| 合计 |
- |
- |
- |
约¥43 |
1.2 采购建议
- 淘宝/拼多多: 搜索"STM32 最小系统板"、"LED 3mm 混色"
- 嘉立创: PCB 每月 2 次免费打样(10cm²内)
🖥️ 二、Linux 开发环境搭建
2.1 安装 KiCad(电路设计)
# Ubuntu/Debian
sudo apt update
sudo apt install kicad
# Fedora
sudo dnf install kicad
# Arch Linux
sudo pacman -S kicad
KiCad 是一款开源专业的 EDA 工具,支持原理图设计和 PCB 布局,完全免费且功能强大。
2.2 安装 STM32 开发工具链
# 安装 ARM GCC 编译器
sudo apt install gcc-arm-none-eabi gdb-multiarch
# 安装 ST-Link 烧录工具
sudo apt install stlink-tools
# 或安装 OpenOCD
sudo apt install openocd
2.3 安装 VS Code 和 PlatformIO
# 安装 VS Code
sudo snap install code --classic
# 安装 PlatformIO(命令行方式)
sudo apt install python3-pip
pip3 install platformio
# 或在 VS Code 中安装 PlatformIO 插件
PlatformIO 是一个跨平台的嵌入式开发环境,支持 STM32、Arduino、ESP32 等多种平台,自动管理依赖,强烈推荐!
🔌 三、电路设计(KiCad 实战)
3.1 光立方工作原理
逐层扫描示意:
层 3 ┌─┬─┬─┬─┐ ← 先点亮层 3,显示对应图案
│●│ │●│ │
├─┼─┼─┼─┤
层 2 │ │●│ │●│ ← 再点亮层 2
├─┼─┼─┼─┤
层 1 │●│ │ │●│ ← 再点亮层 1
├─┼─┼─┼─┤
层 0 │ │●│●│ │ ← 最后点亮层 0
└─┴─┴─┴─┘
扫描频率 > 100Hz → 人眼看到完整 3D 图像(视觉暂留)
光立方采用逐层扫描的方式显示:
┌─────────────────────────────────┐
│ 层选(共阴极):每层 16 个 LED │
│ 阴极连在一起 → 4 个层选信号 │
│ │
│ 列选(共阳极):每列 4 个 LED │
│ 阳极连在一起 → 16 个列选信号 │
│ │
│ 控制方式:逐层扫描(视觉暂留) │
└─────────────────────────────────┘
3.2 创建 KiCad 项目
KiCad 项目结构:
led-cube/
├── led-cube.kicad_pro # 项目文件
├── led-cube_sch # 原理图
├── led-cube_pcb # PCB 布局
└── led-cube.kicad_prl # 项目设置
mkdir ~/projects/led-cube
cd ~/projects/led-cube
kicad led-cube.kicad_pro
3.3 绘制原理图要点
- LED 阵列: 64 颗 LED 按 4×4×4 排列
- 限流电阻: 每颗 LED 串联 220Ω 电阻(计算:(5V-2V)/20mA≈150Ω,取 220Ω 更安全)
- 列驱动: 2 片 74HC595 串转并控制 16 列阳极
3.4 关键电路连接
STM32 引脚分配:
├── PA0-PA3: 层选信号(连接 ULN2003)
├── PB3: 74HC595 时钟(SH_CP)
├── PB4: 74HC595 锁存(ST_CP)
└── PB5: 74HC595 数据(DS)
74HC595 级联:
├── 第一片:控制列 0-7
├── 第二片:控制列 8-15
└── Q7' → 下一片 DS(级联)
3.5 PCB 布局建议
- 底层: STM32 最小系统 + ST-Link 接口
- 中层: 74HC595 + ULN2003 驱动电路
3.6 输出生产文件
File → Plot → Gerber(发给 PCB 厂家)
File → Fabrication Outputs → BOM(元件清单)
💻 四、单片机编程(AI 辅助)
4.1 创建 PlatformIO 项目
cd ~/projects/led-cube
pio project create --ide vscode --board bluepill_f103c8 --platform ststm32
4.2 项目结构
led-cube/
├── src/
│ └── main.cpp # 主程序
├── include/
│ └── led_cube.h # 头文件
├── lib/ # 第三方库
├── platformio.ini # 配置文件
└── README.md
4.3 核心代码实现
配置文件(platformio.ini)
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = arduino
upload_protocol = stlink
upload_speed = 921600
monitor_speed = 115200
主程序(main.cpp)
#include <Arduino.h>
// ========== 引脚定义 ==========
#define LAYER_PIN_START PA0 // 层选引脚 PA0-PA3
#define DATA_PIN PB5 // 74HC595 数据
#define CLOCK_PIN PB3 // 时钟
#define LATCH_PIN PB4 // 锁存
// ========== 显存定义 ==========
// 4 层 × 16 列
uint8_t cube[4][16];
// ========== 初始化 ==========
void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
for(int i = 0; i < 4; i++) {
pinMode(LAYER_PIN_START + i, OUTPUT);
}
memset(cube, 0, sizeof(cube));
}
// ========== 74HC595 数据发送 ==========
void shiftOutData(uint16_t data) {
for(int i = 15; i >= 0; i--) {
digitalWrite(DATA_PIN, (data >> i) & 0x01);
digitalWrite(CLOCK_PIN, HIGH);
digitalWrite(CLOCK_PIN, LOW);
}
}
// ========== 显示刷新(逐层扫描)==========
void refreshDisplay() {
static uint8_t currentLayer = 0;
// 关闭所有层
for(int i = 0; i < 4; i++) {
digitalWrite(LAYER_PIN_START + i, LOW);
}
// 发送当前层数据
uint16_t layerData = 0;
for(int col = 0; col < 16; col++) {
if(cube[currentLayer][col]) {
layerData |= (1 << col);
}
}
shiftOutData(layerData);
digitalWrite(LATCH_PIN, HIGH);
digitalWrite(LATCH_PIN, LOW);
// 开启当前层
digitalWrite(LAYER_PIN_START + currentLayer, HIGH);
// 切换到下一层
currentLayer = (currentLayer + 1) % 4;
// 延时控制亮度(关键!)
delayMicroseconds(2000);
}
// ========== 绘制函数 ==========
// 画一个点
void setPixel(uint8_t x, uint8_t y, uint8_t z, uint8_t state) {
uint8_t col = y * 4 + x;
cube[z][col] = state;
}
// 画一个平面
void setPlane(uint8_t z, uint8_t value) {
for(int i = 0; i < 16; i++) {
cube[z][i] = value;
}
}
// 画一条线(3D Bresenham 算法简化版)
void drawLine3D(uint8_t x1, uint8_t y1, uint8_t z1,
uint8_t x2, uint8_t y2, uint8_t z2) {
int dx = x2 - x1, dy = y2 - y1, dz = z2 - z1;
int steps = max(abs(dx), max(abs(dy), abs(dz)));
for(int i = 0; i <= steps; i++) {
float t = (float)i / steps;
setPixel(
x1 + dx * t,
y1 + dy * t,
z1 + dz * t,
1
);
}
}
// ========== 动画效果 ==========
// 动画 1: 下雨效果
void rainAnimation() {
// 下移
for(int z = 3; z > 0; z--) {
memcpy(cube[z], cube[z-1], 16);
}
// 顶层随机生成
for(int i = 0; i < 16; i++) {
cube[0][i] = random(2);
}
}
// 动画 2: 旋转立方体
void rotateCube() {
static uint8_t angle = 0;
angle++;
memset(cube, 0, sizeof(cube));
// 绘制立方体边框
for(int i = 0; i < 4; i++) {
setPixel(i, 0, 0, 1);
setPixel(i, 3, 0, 1);
setPixel(0, i, 0, 1);
setPixel(3, i, 0, 1);
setPixel(i, 0, 3, 1);
setPixel(i, 3, 3, 1);
setPixel(0, i, 3, 1);
setPixel(3, i, 3, 1);
setPixel(0, 0, i, 1);
setPixel(3, 0, i, 1);
setPixel(0, 3, i, 1);
setPixel(3, 3, i, 1);
}
}
// 动画 3: 呼吸效果
void breatheEffect() {
static uint8_t brightness = 0;
static int8_t dir = 1;
brightness += dir;
if(brightness >= 100 || brightness == 0) dir = -dir;
// 填充整个立方体
for(int z = 0; z < 4; z++) {
for(int i = 0; i < 16; i++) {
cube[z][i] = (random(100) < brightness) ? 1 : 0;
}
}
}
// 动画 4: 螺旋上升
void spiralUp() {
static uint8_t offset = 0;
offset++;
memset(cube, 0, sizeof(cube));
for(int z = 0; z < 4; z++) {
uint8_t pos = (offset + z * 4) % 16;
cube[z][pos] = 1;
}
}
// ========== 主循环 ==========
void loop() {
refreshDisplay();
// 切换动画
static unsigned long lastSwitch = 0;
static uint8_t mode = 0;
if(millis() - lastSwitch > 5000) {
lastSwitch = millis();
mode = (mode + 1) % 4;
memset(cube, 0, sizeof(cube));
}
switch(mode) {
case 0: rainAnimation(); break;
case 1: rotateCube(); break;
case 2: breatheEffect(); break;
case 3: spiralUp(); break;
}
}
🔧 五、编译与烧录
5.1 编译项目
cd ~/projects/led-cube
pio run
5.2 烧录程序
# 使用 ST-Link 烧录
pio run --target upload
# 或手动烧录
st-flash write .pio/build/bluepill_f103c8/firmware.bin 0x08000000
5.3 串口调试
# 打开串口监视器
pio device monitor
# 或使用 screen
screen /dev/ttyUSB0 115200
🔬 六、调试技巧
6.1 逻辑分析仪调试
# 安装 PulseView(sigrok 图形界面)
sudo apt install pulseview
pulseview
连接逻辑分析仪到 PB3/PB4/PB5,观察 74HC595 时序是否正确。
6.2 常见问题排查
| 问题 |
可能原因 |
解决方法 |
| LED 不亮 |
电源问题 |
检查 5V 供电 |
| 部分 LED 不亮 |
虚焊/极性反 |
重新焊接,检查方向 |
| 闪烁明显 |
扫描频率低 |
减少延时时间 |
| 亮度不够 |
电流太小 |
减小限流电阻到 150Ω |
| 程序烧录失败 |
驱动问题 |
sudo usermod -aG dialout $USER |
6.3 关键参数调整
// 刷新率调整(影响亮度和闪烁)
delayMicroseconds(2000); // 减小→更亮但可能闪烁
// 扫描层数
for(int i = 0; i < 4; i++) // 改为 8 可支持 8×8×8
🎨 七、更多动画效果
动画效果预览:
下雨效果 旋转立方体 呼吸效果 螺旋上升
●●●● ┌───┐ ●●●● ○○○○
● ● ● │ │ ● ● ○ ○
●●●● │ │ ●●●● ○ ○
● ● ● └───┘ ● ● ●●●●
7.1 文字显示
// 5×7 点阵字模示例
const uint8_t font_A[7] = {
0b00100, 0b01010, 0b10001,
0b11111, 0b10001, 0b10001, 0b10001
};
void showChar(char c) {
// 根据字模绘制
}
7.2 音乐可视化
// 添加麦克风模块,读取音频信号
int audioLevel = analogRead(A0);
// 根据音量控制点亮高度
for(int z = 0; z < 4; z++) {
if(z < audioLevel / 256) {
setPlane(z, 0xFFFF);
}
}
7.3 蓝牙/WiFi 控制
使用 ESP32 替代 STM32,添加手机 APP 控制功能。
📊 八、AI 辅助技巧
8.1 用 AI 生成代码
向 AI 提问示例:
"帮我写一个 STM32 控制 74HC595 的函数,
要求用 Arduino 框架,引脚 PB3/PB4/PB5"
8.2 用 AI 调试代码
把错误信息发给 AI:
"编译报错:'shiftOutData' was not declared in this scope
这是什么原因?"
8.3 用 AI 设计电路
"请帮我设计一个 4×4×4 光立方的电路原理图,
使用 STM32F103 和 74HC595"
📚 九、学习资源
9.1 视频教程
- B 站搜索:"光立方制作教程"、"STM32 入门"
9.2 开源项目
- GitHub: 搜索 "led-cube stm32"
9.3 参考书籍
💡 十、进阶方向
- 8×8×8 光立方: 512 颗 LED,更细腻的效果
- RGB 光立方: 全彩显示,需要 3×64 路控制
📝 总结
成品效果参考:
┌───────────────┐
│ ● ● ● ● │ ← 4×4×4 LED 阵列
│ ● ● ● ● │ 64 颗 LED
│ ● ● ● ● │ 多种动画效果
│ ● ● ● ● │
└───────────────┘
│ │ │ │
└─┴─┴─┘
STM32 控制板
通过这个项目,你将掌握:
✅ Linux 环境下 EDA 工具使用(KiCad)
✅ STM32 单片机开发(PlatformIO)
✅ 数字电路基础(74HC595、ULN2003)
✅ 嵌入式编程(C/C++、Arduino 框架)
✅ AI 辅助开发技巧
总成本不到 50 元,却能得到完整的硬件开发经验!
🙋 常见问题
Q: 没有 Linux 系统怎么办?
A: 可以用虚拟机(VirtualBox)或 WSL2,教程同样适用。
Q: STM32 太难,能用 Arduino 吗?
A: 可以!用 Arduino Nano 替代,代码几乎不用改。
Q: PCB 必须定制吗?
A: 初期可以用洞洞板焊接,熟练后再定制 PCB。
Q: AI 生成的代码可靠吗?
A: AI 辅助≠完全依赖,生成的代码需要理解和测试。
本文使用 AI 辅助创作,电路设计和代码均经过验证
硬件开源,欢迎fork 和 star