1. LED流水灯控制

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]

运行与验证

  1. 综合与实现:在Vivado中新建工程,添加上述Verilog源码与XDC约束文件,运行综合、实现并生成比特流。
  2. 下载验证:将比特流下载至FPGA开发板,按下复位键释放后观察LED状态。
  3. 通过标准:LED0先点亮约0.5秒,随后LED1点亮(LED0熄灭),依次左移循环;当LED7点亮后下一个状态回到LED0,形成连续流水效果。若LED流动方向相反,检查移位方向或引脚顺序。

常见问题

  • LED全灭或全亮:检查复位极性是否与代码一致(本设计为低电平复位),以及LED有效电平是否与约束匹配。
  • 流水速度异常:确认系统时钟频率是否为50MHz,若为其他频率需相应调整CNT_MAX参数。
  • 仿真验证:可在Testbench中缩短CNT_MAX(如设为25'd4)以加速仿真观察波形,确认led信号按预期移位。