)
从拨码开关到LED闪烁在Quartus II里用Verilog玩转数控分频器附完整代码当你第一次接触FPGA时最令人兴奋的莫过于看到自己写的代码能直接控制硬件产生可视化的效果。本文将带你用最直观的方式——通过拨码开关控制LED闪烁频率来体验数字电路设计的魅力。无需复杂理论只需跟着步骤操作你就能在开发板上看到即时反馈这种所见即所得的学习方式特别适合初学者快速入门。1. 准备工作与环境搭建在开始之前我们需要准备好以下硬件和软件硬件需求FPGA开发板如Altera Cyclone系列USB-Blaster下载器带拨码开关和LED的扩展板软件安装Quartus II 13.0或更高版本对应的FPGA器件支持包安装Quartus II时建议选择典型安装并包含所有必要的组件。安装完成后首次启动时会提示选择许可证文件对于学习用途可以使用免费的Web Edition版本。提示确保你的开发板与Quartus II支持的FPGA型号匹配否则可能无法正确烧录程序。2. 项目创建与基本设置启动Quartus II后按照以下步骤创建新项目点击File → New Project Wizard设置项目名称和存储路径避免使用中文路径选择目标FPGA器件型号需与开发板一致添加新的Verilog HDL文件在器件选择页面需要特别注意以下几个参数参数建议值说明FamilyCyclone IV E常见入门级FPGA系列DeviceEP4CE6E22C8典型入门型号Package144-pin TQFP常见封装类型创建完成后我们需要设置未使用引脚的状态避免损坏芯片set_global_assignment -name RESERVE_ALL_UNUSED_PINS AS INPUT TRI-STATED3. Verilog代码实现数控分频数控分频器的核心思想是通过计数实现频率分割。下面我们将分两个模块实现功能。3.1 时钟预分频模块首先创建一个将50MHz时钟分频到2Hz的模块module clock_divider( input clk_50M, // 50MHz输入时钟 output reg clk_2H // 2Hz输出时钟 ); reg [25:0] counter 0; always (posedge clk_50M) begin if(counter 12500000) begin clk_2H ~clk_2H; counter 0; end else begin counter counter 1; end end endmodule3.2 数控分频核心模块接下来是实现可调分频比的模块通过4位拨码开关控制module adjustable_divider( input clk_2H, // 2Hz输入时钟 input [3:0] sw_in, // 拨码开关输入 output reg led_out // LED输出 ); reg [3:0] counter 0; wire [3:0] div_factor sw_in 1; // 分频系数输入值1 always (posedge clk_2H) begin if(counter (div_factor 1) - 1) begin led_out 1b1; counter counter 1; end else if(counter div_factor - 1) begin led_out 1b0; counter 0; end else begin counter counter 1; end end endmodule这段代码实现了以下功能拨码开关输入值1作为实际分频系数输出占空比为50%的方波分频范围1-16分频对应拨码开关0000-11114. 顶层模块设计与引脚分配将两个模块连接起来形成完整的系统module top_level( input clk_50M, input [3:0] sw, output led ); wire clk_2H; clock_divider div_inst( .clk_50M(clk_50M), .clk_2H(clk_2H) ); adjustable_divider adj_div_inst( .clk_2H(clk_2H), .sw_in(sw), .led_out(led) ); endmodule完成代码编写后需要进行引脚分配。根据开发板原理图典型分配如下信号名FPGA引脚开发板对应功能clk_50MPIN_2350MHz晶振sw[0]PIN_45拨码开关1sw[1]PIN_46拨码开关2sw[2]PIN_47拨码开关3sw[3]PIN_48拨码开关4ledPIN_87用户LED1在Quartus II中可以通过Assignment Editor图形化界面分配引脚也可以直接编辑QSF文件set_location_assignment PIN_23 -to clk_50M set_location_assignment PIN_45 -to sw[0] set_location_assignment PIN_46 -to sw[1] set_location_assignment PIN_47 -to sw[2] set_location_assignment PIN_48 -to sw[3] set_location_assignment PIN_87 -to led5. 编译下载与效果验证完成所有设计后按照以下步骤操作点击Processing → Start Compilation进行全编译连接开发板打开电源点击Tools → Programmer打开烧录工具添加生成的SOF文件勾选Program/Configure选项点击Start开始烧录烧录成功后你可以尝试以下操作将拨码开关全部置00000LED以最快速度闪烁2Hz将拨码开关置为0001LED闪烁频率降为1Hz将拨码开关置为1111LED约每8秒闪烁一次实际效果对照表拨码开关值分频系数输出频率LED闪烁周期000012Hz0.5秒000121Hz1秒001030.67Hz1.5秒............1111160.125Hz8秒6. 常见问题排查在实际操作中可能会遇到以下问题LED完全不亮检查开发板供电是否正常确认引脚分配是否正确检查代码中LED输出是否被正确驱动LED常亮或不闪烁可能是时钟信号未正确连接检查拨码开关输入是否被正确读取使用SignalTap II逻辑分析仪抓取内部信号闪烁频率不正确确认时钟源频率设置正确检查计数器位宽是否足够验证分频计算逻辑是否正确调试技巧逐步验证每个模块的功能使用Quartus II自带的仿真工具进行功能验证在代码中添加调试输出信号7. 扩展与优化掌握了基本功能后可以尝试以下扩展增加分频范围改用更多位宽的拨码开关输入改进用户界面添加七段数码管显示当前分频系数支持奇数分频修改代码实现50%占空比的奇数分频添加按键控制用按键切换不同的分频模式一个支持奇数分频的改进版本module universal_divider( input clk, input [3:0] div_factor, output reg clk_out ); reg [3:0] cnt_p, cnt_n; reg clk_p, clk_n; always (posedge clk) begin if(cnt_p div_factor - 1) cnt_p 0; else cnt_p cnt_p 1; if(cnt_p (div_factor 1)) clk_p 1b1; else clk_p 1b0; end always (negedge clk) begin if(cnt_n div_factor - 1) cnt_n 0; else cnt_n cnt_n 1; if(cnt_n (div_factor 1)) clk_n 1b1; else clk_n 1b0; end assign clk_out (div_factor[0]) ? (clk_p | clk_n) : clk_p; endmodule这个改进版模块可以自动识别奇数/偶数分频并始终保持50%的占空比输出。