首页 / 资讯中心 / 文章详情

Verilog FPGA数字频率计设计:10Hz~10MHz闸门与时序解析

Verilog FPGA数字频率计设计:10Hz~10MHz闸门与时序解析 ★ FEATURED ARTICLE
简介这份资料围绕基于Verilog的数字频率计课程设计面向电子、通信及FPGA入门学习者提供从原理梳理到代码仿真的完整参考。内容以实验任务要求、技术指标和目录安排开篇覆盖分频器、门控电路、计数器、锁存与译码显示、顶层电路等模块的设计与仿真并说明10Hz10MHz测量范围、6位数码管以kHz显示、1S/0.1S/0.01S闸门选择、复位按钮以及闸门和溢出指示等要求的实现思路。报告还包含Verilog HDL简介、测频原理框图、ISE仿真流程、ELB实验板验证、误差分析与实验总结结构较完整。压缩包共1个doc文档约412KB文档虽为单文件但章节分明、便于检索适合作为数字频率计课设报告模板和模块化代码仿真参考。已有707人学习读者可据此对照顶层组织、分模块验证方法和报告写法完成课程设计或查漏补缺。1. 一块实验板上的10Hz10MHz这份Verilog频率计资源能直接复现吗数字频率计这套资源核心不是“把脉冲数一遍”那么简单。它给的是基于Verilog的FPGA课程设计完整包分频器、门控电路、六位BCD计数器、锁存译码扫描显示、顶层连线再加一份带原理框图和误差分析的报告。测量范围标到10Hz10MHz三个带锁按键切1s、0.1s、0.01s闸门两只LED分别指示闸门开闭和计数器溢出。我第一眼关注的不是计数器代码而是gate、latch、clear三路信号的先后关系。频率计读数乱跳十有八九不是计数器写错而是闸门关断、数据锁存、计数器清零挤在同一拍。这份资源适合谁正在做FPGA课程设计、想跑通“仿真—综合—引脚—下载—实测”闭环的人也适合已经写过计数器、但对跨时钟域和显示扫描没把握的初学者。报告里的实测表和误差分析值得看代码里的时序骨架需要按下面几章重新捋一遍再上板。2. 从时基到闸门先把1s/0.1s/0.01s的时序骨架搭对2.1 测频公式与三个闸门时间的换算数字频率计的底层公式很朴素在已知闸门时间T内数到N个被测脉冲被测频率就是fxN/T。1s闸门数到1000个脉冲读数就是1000Hz0.1s闸门数到100个脉冲换算回去也是1000Hz。区别在分辨率和低端适用性1s闸门的分辨率是1Hz0.1s是10Hz0.01s是100Hz。10Hz信号在0.01s闸门里理论上只进来0.1个脉冲读出来不是0就是100Hz所以低端必须用长闸门。闸门时间1ms节拍计数理论分辨率典型适用频段显示换算1s10001Hz10Hz1MHz计数N直接按kHz定位小数点0.1s10010Hz100Hz10MHz计数N乘10后按kHz显示0.01s10100Hz1kHz10MHz计数N乘100后按kHz显示这里先埋一个后面会展开的坑原报告写“6只数码管以kHz为单位显示”但1s闸门测10MHz会数到10,000,0006位BCD最大只到999999。要么把计数器扩到8位BCD、显示只取高6位要么固定1位小数、把量程重新标定。复现前先把显示格式定死不然后面仿真波形全对上板读数却对不上表。2.2 分频器用计数器把系统时钟切成时基时基模块的任务是把板载时钟切成1ms、10ms、100ms、1s四个使能脉冲。注意这里输出的是单时钟宽度的使能不是占空比50%的分频时钟。拿分频时钟直接驱动门控状态机综合工具会报gated clock跨模块后时序也难收敛。常见做法是全局只用一个系统时钟其他节拍全做使能。module tick_gen #( parameter integer CLK_HZ 24_000_000 // 板载时钟按实际晶振改 )( input wire clk, input wire rst_n, output reg en_1k, // 每1ms一个时钟宽脉冲 output reg en_100, // 每10ms一个 output reg en_10, // 每100ms一个 output reg en_1 // 每1s一个 ); localparam integer C1K CLK_HZ / 1000; localparam integer C100 CLK_HZ / 100; localparam integer C10 CLK_HZ / 10; localparam integer C1 CLK_HZ; reg [31:0] cnt_1k, cnt_100, cnt_10, cnt_1; always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt_1k 0; en_1k 1b0; end else if (cnt_1k C1K-1) begin cnt_1k 0; en_1k 1b1; end else begin cnt_1k cnt_1k 1b1; en_1k 1b0; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt_100 0; en_100 1b0; end else if (cnt_100 C100-1) begin cnt_100 0; en_100 1b1; end else begin cnt_100 cnt_100 1b1; en_100 1b0; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt_10 0; en_10 1b0; end else if (cnt_10 C10-1) begin cnt_10 0; en_10 1b1; end else begin cnt_10 cnt_10 1b1; en_10 1b0; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt_1 0; en_1 1b0; end else if (cnt_1 C1-1) begin cnt_1 0; en_1 1b1; end else begin cnt_1 cnt_1 1b1; en_1 1b0; end end endmodule这段代码的关键参数是CLK_HZ。原报告按24MHz写分频计数1s对应24,000,00010Hz对应2,400,000100Hz对应240,0001kHz对应24,000。换板子只改这一个参数四个使能会跟着变。计数器位宽给32位是留余量综合工具会自动裁掉高位如果手动缩位至少保证能装下CLK_HZ-1。en_1k同时给门控状态机和显示扫描用en_1给需要绝对秒节拍的校验逻辑用。2.3 门控电路gate、latch、clear三路信号怎么排门控电路决定一次测量什么时候开始、什么时候停、什么时候把数送进锁存器、什么时候把计数器清掉。原报告用gate的边沿推一个小计数器数到第9拍拉gate_out1第11拍拉latch第13拍拉clear。这个思路能跑但gate本身来自分频器边沿上容易叠毛刺状态机容易跑飞。我一般把它改成1kHz节拍驱动的四状态机窗口长度按档位选1000、100、10个1ms节拍。module gate_ctrl ( input wire clk, input wire rst_n, input wire en_1k, // 1ms节拍 input wire [1:0] sel, // 001s, 010.1s, 100.01s output reg gate, // 计数窗口高有效 output reg latch, // 窗口结束后锁存 output reg clear // 锁存后清零计数器 ); localparam S_IDLE 2d0; localparam S_COUNT 2d1; localparam S_LATCH 2d2; localparam S_CLEAR 2d3; reg [1:0] state; reg [15:0] div_cnt; wire [15:0] win_len (sel 2d0) ? 16d1000 : (sel 2d1) ? 16d100 : 16d10; always (posedge clk or negedge rst_n) begin if (!rst_n) begin state S_IDLE; gate 1b0; latch 1b0; clear 1b0; div_cnt 0; end else begin latch 1b0; clear 1b0; case (state) S_IDLE: begin gate 1b1; div_cnt 0; state S_COUNT; end S_COUNT: begin if (en_1k) begin if (div_cnt win_len - 1) begin gate 1b0; state S_LATCH; end else begin div_cnt div_cnt 1b1; end end end S_LATCH: begin latch 1b1; state S_CLEAR; end S_CLEAR: begin clear 1b1; state S_IDLE; end default: state S_IDLE; endcase end end endmodulegate高电平期间计数器对被测信号计数窗口结束先把gate拉低下一拍latch拉高把计数器当前值送进显示锁存器再下一拍clear拉高把计数器清回全零。这样显示值会一直保留到下一次latch符合“记忆显示”的要求。sel在窗口中途变化会改变win_len所以实际板上要在S_IDLE时把按键值打一拍锁住避免切档时窗口被截短。latch和clear都是单时钟宽脉冲后面计数器模块要对它们做两级同步不能直接拿异步信号去清零10MHz域。3. 六位BCD计数与扫描显示让10MHz读数稳定不跳3.1 计数器六位BCD级联与溢出标志计数器要在gate为高时对sig_in的上升沿计数计数结果按BCD逐位进位。被测信号可能到10MHz而gate、clear来自1kHz域必须先在sig_in域打两拍再使用。否则clear和计数脉冲撞在一起会出现“清了又进一位”的玄学读数。module bcd_counter6 ( input wire clk_in, // 被测信号 input wire rst_n, input wire gate, // 来自门控异步 input wire clear, // 来自门控异步 output reg [3:0] d0,d1,d2,d3,d4,d5, output reg overflow ); reg gate_s1, gate_s2; reg clear_s1, clear_s2; // 跨时钟域两级同步降低亚稳态概率 always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin gate_s1 0; gate_s2 0; clear_s1 0; clear_s2 0; end else begin gate_s1 gate; gate_s2 gate_s1; clear_s1 clear; clear_s2 clear_s1; end end wire en gate_s2 ~clear_s2; always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin d00; d10; d20; d30; d40; d50; overflow0; end else if (clear_s2) begin d00; d10; d20; d30; d40; d50; overflow0; end else if (en) begin if (d0 ! 4d9) d0 d0 1b1; else begin d0 0; if (d1 ! 4d9) d1 d1 1b1; else begin d1 0; if (d2 ! 4d9) d2 d2 1b1; else begin d2 0; if (d3 ! 4d9) d3 d3 1b1; else begin d3 0; if (d4 ! 4d9) d4 d4 1b1; else begin d4 0; if (d5 ! 4d9) d5 d5 1b1; else begin d5 0; overflow 1b1; end end end end end end end end endmoduled0是最低位d5是最高位。overflow在六位全9后再来一个脉冲置1clear到来时清掉。这里保留六位BCD是为了和原报告代码对齐如果坚持1s闸门测10MHz要把它扩成八位BCD显示模块只取高六位或做小数点移位。六位BCD直接测10MHz会溢出这是原设计里最容易被忽略的位数矛盾仿真时拿10MHz信号一跑就能看到。3.2 锁存与小数点kHz单位下小数点放哪一位锁存模块只在latch脉冲到来时更新q0q5其他时间保持旧值。显示扫描一直读q0q5所以读数不会在计数过程中乱跳。小数点由档位sel决定1s档把小数点放在从右数第3位后表示kHz0.1s档右移一位0.01s档再右移一位。实际板上六位数码管的位置要跟段码表对齐不能只看代码里的scan编号。档位sel闸门时间计数含义小数点位置显示示例001sN Hz右起第3位后001.000 kHz010.1sN×10 Hz右起第2位后010.000 kHz100.01sN×100 Hz右起第1位后100.000 kHzmodule data_latch ( input wire clk, input wire rst_n, input wire latch, input wire [3:0] d0,d1,d2,d3,d4,d5, output reg [3:0] q0,q1,q2,q3,q4,q5 ); always (posedge clk or negedge rst_n) begin if (!rst_n) begin q00; q10; q20; q30; q40; q50; end else if (latch) begin q0d0; q1d1; q2d2; q3d3; q4d4; q5d5; end end endmodulelatch是1kHz域的单拍脉冲clk是系统时钟这里仍然建议把latch在clk域打一拍再用避免综合后脉冲太窄。q0q5送到扫描模块扫描模块只负责位选和段码不参与计数显示刷新和测量窗口彻底解耦。原报告里小数点由ff和se比较产生思路一样但ff在切档时可能和se不同步上板会看到小数点闪一下。稳妥做法是把sel也锁存到窗口边界显示端只用锁存后的sel。3.3 动态扫描译码1kHz位选与共阳极段码六位数码管用动态扫描1kHz节拍依次选通一位每位亮1ms六位一轮6ms刷新率约166Hz肉眼看不到闪烁。段码按共阳极接法低电平点亮。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站