从50MHz到LED闪烁:我的第一个FPGA项目之Quartus II数控分频器实战记录

张开发
2026/4/16 14:45:40 15 分钟阅读

分享文章

从50MHz到LED闪烁:我的第一个FPGA项目之Quartus II数控分频器实战记录
从50MHz到LED闪烁我的第一个FPGA项目之Quartus II数控分频器实战记录第一次接触FPGA开发板时那块印着Altera标志的小板子安静地躺在防静电袋里就像个等待被唤醒的电子精灵。作为刚入门的新手我决定从最基础的LED闪烁实验开始没想到这个看似简单的项目背后竟藏着从50MHz高频时钟到肉眼可见的LED闪烁这样奇妙的信号转换之旅。本文将完整记录如何通过Quartus II软件实现数控分频器的全过程包括PLL配置、Verilog编码、管脚分配等关键步骤以及那些只有实操过才会知道的坑点。1. 硬件准备与环境搭建我的开发板搭载的是Cyclone IV系列FPGA芯片板载一颗50MHz的有源晶振。在开始编码前需要先准备好以下硬件和软件环境硬件清单FPGA开发板带50MHz晶振和用户LEDUSB-Blaster下载器杜邦线若干用于拨码开关连接软件安装# Quartus II Prime Lite Edition下载命令示例Linux wget https://download.altera.com/akdlm/software/acdsinst/20.1std/720/ib_tar/Quartus-lite-20.1.0.720-linux.tar tar -xvf Quartus-lite-20.1.0.720-linux.tar ./setup.sh注意安装时务必选择与开发板匹配的器件系列支持包。我第一次安装时漏选了Cyclone IV支持导致后续无法识别器件。安装完成后新建工程时需要特别注意三个关键设置工程目录不要包含中文或空格器件型号必须精确匹配我的板子是EP4CE6E22C8仿真工具选择None初学者可暂不涉及仿真2. 时钟树构建从50MHz到2HzFPGA设计中最关键的就是时钟信号的处理。板载的50MHz时钟对于LED闪烁来说太高频了需要经过多级分频2.1 PLL锁相环配置Quartus内置的PLL IP核可以将输入时钟倍频或分频。通过Tools → IP Catalog打开IP核目录搜索ALTPLL// PLL参数配置示例 module pll_clk( input inclk0, // 50MHz输入 output c0 // 10MHz输出 ); altpll pll_inst( .inclk0(inclk0), .c0(c0), .areset(1b0), .locked() ); defparam pll_inst.clk0_divide_by 5; endmodule配置参数时容易踩的坑输入频率必须准确填写50MHz输出时钟使能选项要勾选锁定信号(locked)最好引出观察2.2 Verilog分频器设计将PLL输出的10MHz时钟分频到2Hz需要2500000分频系数。这里采用计数器实现module div_2hz( input clk_10m, // 10MHz输入 output reg clk_2hz // 2Hz输出 ); reg [23:0] counter; // 24位计数器 always (posedge clk_10m) begin if(counter 24d2_499_999) begin clk_2hz ~clk_2hz; counter 0; end else begin counter counter 1; end end endmodule调试心得初次编写时计数器位宽不足导致分频不准确。建议分频系数超过16位时使用32位寄存器。3. 数控分频核心实现有了2Hz的基础时钟接下来实现通过拨码开关控制的分频器。设计思路是用4位开关输入决定分频比开关状态分频比输出频率000121Hz001040.5Hz010080.25Hz1000160.125Hz核心代码如下module programmable_divider( input clk_2hz, input [3:0] sw, // 拨码开关输入 output reg led_out // LED输出 ); reg [3:0] counter; always (posedge clk_2hz) begin if(counter sw-1) begin led_out ~led_out; counter 0; end else begin counter counter 1; end end endmodule实际测试时发现两个问题开关全零时会导致死锁 → 添加默认值处理切换开关时输出抖动 → 增加时钟同步寄存器修正后的关键部分always (posedge clk_2hz) begin reg [3:0] sw_sync; sw_sync sw; // 时钟同步 if(sw_sync 0) sw_sync 4d1; // 默认分频比2 if(counter sw_sync-1) begin led_out ~led_out; counter 0; end else begin counter counter 1; end end4. 工程集成与调试4.1 顶层模块连接将各模块在Block Diagram中连接时需要注意信号命名一致性-------- --------- ------------------ | 50MHz |----| PLL |----| div_2hz | | 晶振 | | (10MHz) | | (2Hz基础时钟) | -------- --------- ------------------ | v --------------------- | programmable_divider| | (数控分频核心) | --------------------- | ------------------------------------ | | | v v v ------------ ------------ ------------ | 拨码开关 | | LED指示灯 | | 未用管脚 | | (SW[3:0]) | | (USER_LED) | | (三态设置) | ------------ ------------ ------------4.2 管脚分配技巧通过Assignment Editor分配管脚时新手常犯的错误混淆了原理图符号和实际管脚编号未设置未用管脚为三态输入漏掉电压等级配置正确的管脚分配表示例信号名称管脚编号备注CLK_50MPIN_E150MHz时钟输入SW[0]PIN_M1拨码开关位0SW[1]PIN_T8拨码开关位1USER_LEDPIN_A15用户LED在Assignments → Device → Device and Pin Options中选择Unused Pins为As input tri-stated核对I/O Bank电压与实际电路一致4.3 下载与调试生成sof文件后通过USB-Blaster下载时如果遇到No Hardware错误可按以下步骤排查检查JTAG连接器方向是否正确运行jtagconfig命令查看设备识别情况在Quartus中手动选择USB-Blaster驱动第一次成功看到LED按预期频率闪烁时那种成就感至今难忘。当拨动开关改变分频比LED的闪烁节奏随之变化的瞬间所有调试时的挫败感都化为了继续探索的动力。

更多文章