1. LED闪烁控制
任务目标
设计一个基于时钟分频的LED闪烁电路,将开发板上的50MHz系统时钟分频为1Hz信号,驱动LED以1Hz频率(即每0.5秒翻转一次状态)闪烁。
环境与依赖
- 硬件平台:任意搭载50MHz时钟源的FPGA开发板(如Altera DE系列、Xilinx Artix-7系列)
- 开发工具:Quartus II / Vivado / ModelSim(任选其一)
- 目标器件:支持Verilog-2001标准的FPGA芯片
核心原理
50MHz时钟周期为20ns。要产生1Hz信号,需要计数25,000,000个时钟周期(0.5秒)后翻转一次输出。使用一个26位计数器(最大计数值2^26-1 = 67,108,863 > 25,000,000)即可满足需求。当计数器计满25,000,000-1时清零并翻转LED输出。
完整代码
module led_blink (
input clk, // 50MHz 系统时钟
input rst_n, // 低电平复位
output reg led // LED输出
);
// 计数器位宽:2^26 = 67,108,864 > 25,000,000
reg [25:0] cnt;
// 分频参数:50MHz / 2 / 1Hz = 25,000,000
localparam CNT_MAX = 26'd25_000_000 - 1'b1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 26'd0;
led <= 1'b0;
end
else if (cnt == CNT_MAX) begin
cnt <= 26'd0;
led <= ~led; // 翻转LED状态
end
else begin
cnt <= cnt + 1'b1;
end
end
endmodule
仿真测试代码(可选)
为快速验证逻辑正确性,可缩短计数参数进行仿真。以下testbench将CNT_MAX临时改为4(即每5个时钟周期翻转一次),便于观察波形:
module led_blink_tb;
reg clk = 0;
reg rst_n = 0;
wire led;
// 实例化被测模块(仿真时需将CNT_MAX改为4)
led_blink uut (
.clk(clk),
.rst_n(rst_n),
.led(led)
);
always #10 clk = ~clk; // 50MHz时钟
initial begin
#20 rst_n = 1; // 释放复位
#200 $finish; // 仿真200ns
end
initial begin
$monitor("Time=%0t led=%b", $time, led);
end
endmodule
运行与验证
- 综合与烧录:在Quartus/Vivado中新建工程,将led_blink.v设为顶层文件,绑定引脚(clk接50MHz晶振引脚,rst_n接按键,led接板载LED),编译后下载到FPGA。
- 硬件验证:按下复位键释放后,观察LED是否以约1Hz频率(每秒亮灭各一次)闪烁。可用秒表计时10次闪烁,耗时约10秒即通过。
- 仿真验证:若使用testbench,需将代码中
CNT_MAX临时改为26'd4(即每5个时钟周期翻转),运行仿真后观察led信号每50ns翻转一次(5周期×10ns),波形呈方波即逻辑正确。验证后务必改回25,000,000。
预期仿真输出
当CNT_MAX=4时,led信号在0-50ns为低电平,50-100ns为高电平,之后每50ns翻转一次,占空比50%的方波。
常见问题
- LED不闪烁:检查rst_n是否释放(高电平有效工作);确认引脚绑定正确;若LED常亮或常灭,检查计数器是否溢出——确保cnt位宽足够(26位)。
- 闪烁频率偏差:确认系统时钟是否为精确50MHz。若为其他频率(如27MHz、100MHz),需按公式
CNT_MAX = 时钟频率/2/目标频率 - 1重新计算。