嵌入式-手把手教你基于 FPGA 的 8×8×8 3D 光立方设计(光立方、数字电路)

本项目基于 Altera Cyclone EP1C3T144C8 FPGA 开发板,驱动一个 8×8×8 LED 光立方,实现多种动态显示效果。系统采用 Verilog HDL 描述,结构清晰,适合作为 FPGA 入门到综合实战的参考案例。

一、项目简介

3D 光立方是由 512 颗 LED 组成的三维点阵显示装置。通过控制每一层(排)、每一列、每一行的亮灭,可以在三维空间中显示文字、图案、动画等效果。

本设计特点:

  • 主控芯片:EP1C3T144C8 FPGA
  • 光立方规模:8×8×8,共 512 颗 LED
  • 驱动方式:行/列锁存 + 排选通,配合 74HC573 锁存器与三极管扩流
  • 交互方式:5 个按键切换 5 种显示模式
  • 辅助显示:6 位数码管用于模式指示

二、系统架构

设计框图

整个系统由以下几部分组成:

模块 功能说明
5V 电源适配器 为 FPGA 开发板和光立方驱动电路供电
EP1C3T144C8 FPGA 系统主控,负责按键检测、扫描时序、显示数据生成
按键电路 5 个独立按键,用于切换显示模式
硬件驱动电路 将 FPGA 输出信号转换为可驱动 LED 的电流/电压
行驱动电路(74HC573) 锁存行数据
列驱动电路(74HC573) 锁存列数据
排驱动电路(三极管放大) 功率放大,逐层选通
8×8×8 光立方 三维 LED 点阵显示终端

三、硬件设计要点

1. 主控 FPGA

采用 EP1C3T144C8,属于 Altera Cyclone 一代低成本 FPGA,逻辑资源充足,适合中小规模数字系统设计。板载 50MHz 有源晶振,为整个系统提供时钟。

2. 驱动电路

  • 行/列驱动:使用 74HC573 八位锁存器。FPGA 输出数据先送入锁存器,再通过锁存信号稳定输出,避免扫描过程中的闪烁。
  • 排驱动:由于 8 排 LED 同时点亮时电流较大,使用三极管进行功率放大,确保每排 LED 都能获得足够驱动电流。
  • 扫描策略:通过快速轮询每一排,利用人眼视觉暂留效应,实现三维图案的连续显示。

3. 按键与数码管

  • 5 个独立按键连接到 FPGA GPIO,配合软件消抖实现模式切换。
  • 6 位数码管用于辅助显示当前模式编号,方便调试与演示。

四、软件设计

项目采用模块化设计,主要包含以下 Verilog 模块:

模块名 文件 功能
rst_gen rst_gen.v 上电复位,延时释放复位信号
key_xd key_xd.v 按键消抖,输出单脉冲有效信号
key_xd_top key_xd_top.v 顶层模块,扫描控制与显示数据生成
smg_drv smg_drv.v 数码管驱动,显示 0~9 数字

1. 复位模块 rst_gen

上电后计数到 16'hffff 再释放复位信号,确保系统稳定启动。

module rst_gen(
input clk,
output reg rst_n
);
reg [15:0] cnt = 0;

always @(posedge clk) begin
if (cnt == 16'hffff)
;
else
cnt <= cnt + 1;
end

always @(posedge clk) begin
if (cnt == 16'hffff)
rst_n <= 1;
else
rst_n <= 0;
end
endmodule

2. 按键消抖模块 key_xd

采用状态机实现 20ms 延时消抖,检测到有效按键后输出一个高脉冲。

module key_xd(
input rst_n,
input key_in,
input clk,
output reg key_out
);
parameter IDLE = 4'd0;
parameter ST0 = 4'd1;
parameter ST1 = 4'd2;
parameter ST2 = 4'd3;
parameter time_20ms = 1000000; // 20ms @ 50MHz

reg [3:0] curr_st;
reg [19:0] wait_cnt;
reg key_in_ff1;
reg key_in_ff2;

always @(posedge clk) key_in_ff1 <= key_in;
always @(posedge clk) key_in_ff2 <= key_in_ff1;

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
curr_st <= IDLE;
else case (curr_st)
IDLE: if (key_in_ff2 == 0) curr_st <= ST0;
ST0: if (wait_cnt == time_20ms) curr_st <= ST1;
ST1: curr_st <= ST2;
ST2: if (key_in_ff2) curr_st <= IDLE;
default: ;
endcase
end

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
wait_cnt <= 0;
else if (curr_st == ST0)
wait_cnt <= wait_cnt + 1;
else
wait_cnt <= 0;
end

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
key_out <= 0;
else if (curr_st == ST1)
key_out <= ~key_in_ff2;
else
key_out <= 0;
end
endmodule

3. 数码管驱动 smg_drv

用于验证按键计数,每按一次键数码管显示数字加 1,循环显示 0~9。

module smg_drv(
input clk,
input rst_n,
input key_in,
output [7:0] smg_seg,
output [5:0] smg_bit
);
reg [3:0] cnt;
reg [7:0] en_code;

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 0;
else if (key_in && cnt == 9)
cnt <= 0;
else if (key_in)
cnt <= cnt + 1;
end

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
en_code <= 0;
else case (cnt)
0: en_code <= 8'hc0;
1: en_code <= 8'hf9;
2: en_code <= 8'ha4;
3: en_code <= 8'hb0;
4: en_code <= 8'h99;
5: en_code <= 8'h92;
6: en_code <= 8'h82;
7: en_code <= 8'hf8;
8: en_code <= 8'h80;
9: en_code <= 8'h90;
default: ;
endcase
end

assign smg_seg = en_code;
assign smg_bit = 6'h00;
endmodule

4. 顶层模块 key_xd_top

顶层模块负责:

  • 实例化复位、按键、数码管等子模块
  • 根据按键切换 5 种显示模式
  • 产生行/列/排扫描时序
  • 输出对应 LED 点阵数据
module key_xd_top(
input clk,
input [4:0] key_in,

output reg [7:0] row,
output reg [7:0] col,
output reg [7:0] line,

output [7:0] smg_seg,
output [5:0] smg_bit
);
wire rst_n;
rst_gen Urst_gen(.clk(clk), .rst_n(rst_n));

wire key1_signal, key2_signal, key3_signal, key4_signal, key5_signal;

key_xd key_xd1(.rst_n(rst_n), .key_in(key_in[0]), .clk(clk), .key_out(key1_signal));
key_xd key_xd2(.rst_n(rst_n), .key_in(key_in[1]), .clk(clk), .key_out(key2_signal));
key_xd key_xd3(.rst_n(rst_n), .key_in(key_in[2]), .clk(clk), .key_out(key3_signal));
key_xd key_xd4(.rst_n(rst_n), .key_in(key_in[3]), .clk(clk), .key_out(key4_signal));
key_xd key_xd5(.rst_n(rst_n), .key_in(key_in[4]), .clk(clk), .key_out(key5_signal));

reg [31:0] line_scan_counter;
reg [7:0] line_counter;
reg [31:0] col_scan_counter;
reg [7:0] col_counter;
reg [31:0] row_scan_counter;
reg [7:0] row_counter;

reg [7:0] row_data[31:0];
reg [7:0] col_data[31:0];
reg [7:0] line_data[31:0];

reg [3:0] show_mode;

// 按键切换显示模式
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
show_mode <= 3'd0;
else if (key3_signal)
show_mode <= 3'd0;
else if (key2_signal)
show_mode <= 3'd1;
else if (key1_signal)
show_mode <= 3'd2;
else if (key4_signal)
show_mode <= 3'd3;
else if (key5_signal)
show_mode <= 3'd4;
end

// 排扫描计数器(约 10Hz)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
line_scan_counter <= 1'b0;
else if (line_scan_counter == 32'd12_499_999)
line_scan_counter <= 1'b0;
else
line_scan_counter <= line_scan_counter + 1'b1;
end

always @(posedge clk or negedge rst_n) begin
if (!rst_n)
line_counter <= 1'b0;
else if (line_counter == 8'd32)
line_counter <= 1'b0;
else if (line_scan_counter == 32'd12_499_999)
line_counter <= line_counter + 1'b1;
end

// 列/行扫描计数器(约 100Hz)
// ...

// 根据 show_mode 更新 row_data / col_data / line_data
// 每种模式对应一组 32 字节的显示数据

// 输出到驱动电路
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
row <= 1'b0;
col <= 1'b0;
line <= 1'b0;
end else begin
row <= row_data[row_counter];
col <= col_data[col_counter];
line <= line_data[line_counter];
end
end

smg_drv Usmg_drv(
.clk(clk),
.rst_n(rst_n),
.key_in(key1_signal),
.smg_seg(smg_seg),
.smg_bit(smg_bit)
);
endmodule

完整的数据数组部分较长,已随工程资料一起提供。每种模式通过预置 32 组行/列/排数据,实现不同的 3D 显示效果。

五、显示模式说明

通过 5 个按键可以切换以下 5 种显示模式:

模式 效果描述
模式 0 一面一面显示,类似流水灯效果
模式 1 整体闪烁
模式 2 按排闪烁
模式 3 按排闪烁(另一种图案)
模式 4 按排闪烁(第三种图案)

六、设计总结

本项目从硬件到软件完整地实现了一个基于 FPGA 的 3D 光立方控制系统。关键设计思路包括:

  1. 分层扫描:利用视觉暂留效应,通过快速轮询每一排实现三维显示。
  2. 锁存器驱动:使用 74HC573 稳定行/列数据,避免扫描干扰。
  3. 状态机消抖:按键模块采用状态机实现可靠的 20ms 消抖。
  4. 模块化代码:顶层 + 子模块的结构便于维护和功能扩展。

如果你想在此基础上扩展,可以尝试:

  • 增加更多显示模式(如旋转立方体、文字滚动)
  • 通过串口或 SPI 接收上位机发送的图案数据
  • 改用 PWM 调光实现亮度分级

资料下载

工程包含 FPGA 源码、原理图 PDF、PCB PDF 以及 Gerber 文件,可用于复刻或二次开发。
通过网盘分享的文件:基于FPGA的3D光立方设计
链接: https://pan.baidu.com/s/1zFOKximZglFEJwcjK9mDkw?pwd=h4wq 提取码: h4wq