1. LED流水灯控制
任务目标
在FPGA开发板上驱动8个LED实现循环流水灯效果,通过本案例掌握Verilog基本时序逻辑设计方法,包括时钟分频、计数器与移位寄存器的使用。
硬件需求
- FPGA开发板(以Xilinx Artix-7为例,其他系列只需调整引脚约束)
- 板载50MHz系统时钟
- 8个LED,低电平有效(若为高电平有效,修改代码中LED初始值即可)
- 复位按键(低电平复位)
核心代码
module led_waterfall(
input clk, // 50MHz系统时钟
input rst_n, // 低电平复位
output reg [7:0] led // 8位LED输出
);
// 分频计数器:50MHz时钟分频至约2Hz(周期0.5s)
reg [24:0] cnt;
parameter CNT_MAX = 25'd24_999_999; // 0.5s计数上限
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 25'd0;
else if (cnt == CNT_MAX)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
end
// 移位寄存器:每0.5s左移一位,实现流水效果
wire tick = (cnt == CNT_MAX);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
led <= 8'b1111_1110; // 初始点亮LED0(低电平有效)
else if (tick) begin
if (led[7] == 1'b0) // 已流到最左端,重新开始
led <= 8'b1111_1110;
else
led <= {led[6:0], 1'b1}; // 左移一位,低位补1(熄灭)
end
end
endmodule
引脚约束(XDC示例)
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN C12 [get_ports rst_n]
set_property PACKAGE_PIN F6 [get_ports {led[0]}]
set_property PACKAGE_PIN G6 [get_ports {led[1]}]
set_property PACKAGE_PIN H6 [get_ports {led[2]}]
set_property PACKAGE_PIN H5 [get_ports {led[3]}]
set_property PACKAGE_PIN J5 [get_ports {led[4]}]
set_property PACKAGE_PIN K5 [get_ports {led[5]}]
set_property PACKAGE_PIN L5 [get_ports {led[6]}]
set_property PACKAGE_PIN L6 [get_ports {led[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[*]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
运行与验证
- 综合与实现:在Vivado中新建工程,添加上述Verilog源码与XDC约束文件,运行综合、实现并生成比特流。
- 下载验证:将比特流下载至FPGA开发板,按下复位键释放后观察LED状态。
- 通过标准:LED0先点亮约0.5秒,随后LED1点亮(LED0熄灭),依次左移循环;当LED7点亮后下一个状态回到LED0,形成连续流水效果。若LED流动方向相反,检查移位方向或引脚顺序。
常见问题
- LED全灭或全亮:检查复位极性是否与代码一致(本设计为低电平复位),以及LED有效电平是否与约束匹配。
- 流水速度异常:确认系统时钟频率是否为50MHz,若为其他频率需相应调整
CNT_MAX参数。 - 仿真验证:可在Testbench中缩短
CNT_MAX(如设为25'd4)以加速仿真观察波形,确认led信号按预期移位。