FPGA实战:用D触发器设计流水灯(Xilinx Vivado全流程指南)
第一次在Vivado中成功点亮流水灯的那个深夜,我盯着开发板上规律跳动的LED,突然理解了数字电路的美感——原来那些抽象的时序逻辑概念,真的能化作肉眼可见的光影流动。本文将带你用最基础的D触发器搭建8位流水灯,过程中你会看到理论公式如何变成实际电路,以及如何通过Vivado工具链完成从代码到比特流的完整实现。
1. 项目规划与硬件原理
开发板上的LED阵列就像FPGA工程师的"Hello World",但用纯D触发器实现流水灯远比直接调用PLL模块更有教学意义。我们选用Xilinx Artix-7系列FPGA作为目标器件,其内置的SLICE中的FF(Flip-Flop)资源将直接对应我们的D触发器设计。
1.1 流水灯核心逻辑
传统教科书中的D触发器特性表:
| CLK | D | Q(t+1) | 说明 |
|---|---|---|---|
| ↑ | 0 | 0 | 上升沿锁存低电平 |
| ↑ | 1 | 1 | 上升沿锁存高电平 |
| 其他 | X | Q(t) | 保持当前状态 |
将8个D触发器串联,每个触发器的Q输出连接下一个的D输入,就构成了移位寄存器。在100MHz时钟驱动下,我们需要额外的分频电路来降低LED变化速度:
// 时钟分频模块示例
reg [23:0] counter;
always @(posedge clk) begin
counter <= counter + 1;
end
wire led_clock = counter[23]; // 约0.75Hz
1.2 硬件连接方案
以Basys3开发板为例,LED引脚分配如下:
| FPGA管脚 | 开发板LED | 寄存器位 |
|---|---|---|
| U16 | LED0 | reg[0] |
| E19 | LED1 | reg[1] |
| ... | ... | ... |
| M14 | LED7 | reg[7] |
提示:实际开发中务必查阅对应开发板的原理图,不同型号的FPGA管脚映射可能差异很大
2. Vivado开发环境搭建
2.1 工程创建关键步骤
- 启动Vivado选择"Create Project"
- 指定工程路径时避免中文目录
- 选择正确的器件型号(如xc7a35tcpg236-1)
- 添加新Verilog源文件时勾选"Add to Design Sources"
# 示例Tcl脚本创建工程
create_project -force led_project /vivado_projects/led_demo
set_property board_part digilentinc.com:basys3:part0:1.2 [current_project]
2.2 必须的约束文件
创建XDC文件定义时钟和LED管脚:
## 时钟约束
create_clock -period 10.000 -name clk [get_ports clk]
## LED管脚约束
set_property PACKAGE_PIN U16 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[*]}]
3. Verilog实现细节
3.1 D触发器行为级建模
最简D触发器模块代码:
module d_ff(
input clk,
input d,
output reg q
);
always @(posedge clk) begin
q <= d; // 非阻塞赋值确保时序正确
end
endmodule
扩展为8位移位寄存器:
module shift_reg(
input clk,
input rst,
input en,
output [7:0] led
);
reg [7:0] regs;
always @(posedge clk or posedge rst) begin
if(rst) regs <= 8'b0000_0001;
else if(en) regs <= {regs[6:0], regs[7]};
end
assign led = regs;
endmodule
3.2 常见问题调试
- 现象:LED全亮不流动
- 检查时钟是否接入
- 用SignalTap抓取regs信号
- 现象:LED流动速度过快
- 调整分频计数器位宽
- 确认约束文件中时钟频率正确
4. 进阶优化方向
4.1 资源利用率对比
| 实现方案 | LUT | FF | 功耗(mW) |
|---|---|---|---|
| 基础D触发器 | 8 | 8 | 12 |
| Xilinx SRL16E | 1 | 0 | 8 |
注意:实际项目中应权衡代码可读性与资源利用率
4.2 动态调速实现
添加PWM控制亮度:
// 亮度调节示例
reg [3:0] pwm_counter;
always @(posedge clk) begin
pwm_counter <= pwm_counter + 1;
end
assign led_out = (pwm_counter < brightness) ? led : 0;
开发板上的物理按键可以连接至brightness寄存器,实现交互式亮度调节。这种设计思路同样适用于电机控制等实际应用场景。
475



被折叠的 条评论
为什么被折叠?



