文章目录

  • 前言
  • 一、等精度测量法
  • 二、频率计算模块设计
    • 1.波形图分析
    • 2.RTL代码
  • 三、数码管显示模块设计
    • 1.数码管之二进制转8421BCD码部分
    • 2.数码管显示部分
  • 四、顶层代码设计
    • 1.RTL代码
    • 2.RTL视图
    • 3.仿真测试模块
  • 五、上板验证
  • 总结

前言

频率测量在电子设计领域和测量领域经常被使用,本篇文章将使用基于等精度测量的方法设计一个建议频率计,计算出输入信号的频率并显示在数码管上。


一、等精度测量法

原理:等精度测量法是在实际门控信号下,同时对标准时钟和被测时钟的时钟周期进行计数,再通过公式计算得到被测信号的时钟频率。

误差分析:结合原理和原理图得知,被测时钟信号的时钟频率fx的相对误差与被测时钟信号无关;增大软件闸门的有效范围或者提高标准时钟信号的频率fs,可以减小误差,提高测量精度。
计算方法:分别对实际闸门下被测时钟信号和标准时钟信号的周期数进行计数。
设实际闸门下被测时钟信号周期数为X,设被测信号时钟周期为Tx,它的时钟频率fx=1/Tx,由此:XTx=X/fx=Tx。
设实际闸门下标准时钟信号周期数为Y,设被测信号时钟周期为Ts,它的时钟频率fs=1/Ts,由此:Y
Ts=X/fs=Ts。
等式变换得到被测时钟信号频率计算公式:fx=Xfs/Y

二、频率计算模块设计

1.波形图分析


注:图片摘自《FPGA Verilog开发实战指南》
通过波形图的设计可以起到事半功倍的效果。

  • clk_stand:标准时钟,通过PLL IP核产生。
  • 软件闸门gate_s:gate_s,设计一个总长度为1.5s,前低电平长度为0.25s,高电平长度为2s,后低电平长度为0.25s的软件闸门。
  • 闸门计数器cnt_gate_s:闸门需要时间控制,所以必须使用到计数器,因为开发板自带晶振是50MHz的,所以由低电平到达高电平的时间计数值为CNT_RISE_MAX=28’d12_499_999,总长度计数值为CNT_GATE_S_MAX=28’d74_999_999,所以有效时间计数值为CNT_GATE_S_MAX-CNT_RISE_MAX
  • gate_a:软件闸门需要与系统时钟进行同步处理,用一级寄存器gate_a实现
  • gate_a_stand:将软件闸门与标准时钟同步,可以产生下降沿信号gate_a_fall_s
  • gate_a_fall_s:标准时钟周期计数停止标志位
  • cnt_clk_stand:标准时钟周期计数器
  • cnt_clk_stand_reg:标准时钟计数值寄存器
  • gate_a_test:将软件闸门与待测时钟同步,可产生下降沿信号gate_a_fall_t
  • gate_a_fall_t:待测时钟周期计数停止标志位
  • cnt_clk_test:待测时钟周期计数器
  • cnt_clk_test_reg:待测时钟计数值寄存器
  • calc_flag:开始计算待测信号频率标志位,在闸门计数器记满时产生一个脉冲
  • freq_reg:频率计数值寄存器
  • calc_flag_reg:将calc_flag信号延迟一拍,此时频率计算已经结束,可以产生输出标志。
  • freq:输出频率计算值

2.RTL代码

module freq_meter_calc
#(parameter CNT_RISE_MAX=28'd12_499_999,parameter CNT_GATE_S_MAX=28'd74_999_999,parameter CLK_STAND_FREQ=28'd100_000_000
)
(input wire clk,input wire rst_n,input wire clk_test,output reg [33:0]freq
);reg [27:0]cnt_gate_s;reg gate_s;reg gate_a;reg gate_a_stand;wire gate_a_fall_s;reg [47:0]cnt_clk_stand;reg [47:0]cnt_clk_stand_reg;reg gate_a_test;wire gate_a_fall_t;reg [47:0]cnt_clk_test;reg [47:0]cnt_clk_test_reg;reg calc_flag;reg [63:0]freq_reg;reg calc_flag_reg;wire clk_stand;clk_stand_pll clk_stand_pll0(.areset(~rst_n),.inclk0(clk),.c0(clk_stand));//闸门计数器always @(posedge clk or negedge rst_n)if(!rst_n)cnt_gate_s<=1'b0;else if(cnt_gate_s==CNT_GATE_S_MAX)cnt_gate_s<=1'b0;else cnt_gate_s<=cnt_gate_s+1'b1;//闸门控制,always @(posedge clk or negedge rst_n)if(!rst_n)gate_s<=1'b0;else if((cnt_gate_s>=CNT_RISE_MAX) && cnt_gate_s<=(CNT_GATE_S_MAX-CNT_RISE_MAX))gate_s<=1'b1;else gate_s<=1'b0;//将闸门打一拍,与时钟同步always @(posedge clk or negedge rst_n)if(!rst_n)gate_a<=1'b0;else gate_a<=gate_s;//将标准时钟闸门再打一拍,以便生成标志信号gate_a_fall_salways @(posedge clk_stand or negedge rst_n)if(!rst_n)gate_a_stand<=1'b0;else gate_a_stand<=gate_a;//标准频率计数截止信号assign gate_a_fall_s=(gate_a_stand && !gate_a) ? 1'b1:1'b0;//标准时钟频率计数器always @(posedge clk_stand or negedge rst_n)if(!rst_n)cnt_clk_stand<=1'b0;else if(!gate_a)cnt_clk_stand<=1'b0;else if(gate_a)cnt_clk_stand<=cnt_clk_stand+1'b1;//标准时钟频率周期个数寄存器always @(posedge clk_stand or negedge rst_n)if(!rst_n)cnt_clk_stand_reg<=1'b0;else if(gate_a_fall_s)cnt_clk_stand_reg<=cnt_clk_stand;//将待测时钟打一拍,以便生成gate_a_fall_talways @(posedge clk_test or negedge rst_n)if(!rst_n)gate_a_test<=1'b0;else gate_a_test<=gate_a;//待测时钟计数截止信号assign gate_a_fall_t=(gate_a_test && !gate_a) ? 1'b1:1'b0;//待测时钟频率计数器always @(posedge clk_test or negedge rst_n)if(!rst_n)cnt_clk_test<=1'b0;else if(!gate_a)cnt_clk_test<=1'b0;else if(gate_a)cnt_clk_test<=cnt_clk_test+1'b1;//待测时钟频率周期个数寄存器always @(posedge clk_test or negedge rst_n)if(!rst_n)cnt_clk_test_reg<=1'b0;else if(gate_a_fall_t)cnt_clk_test_reg<=cnt_clk_test;//频率计算标志信号always @(posedge clk or negedge rst_n)if(!rst_n)calc_flag<=1'b0;else if(cnt_gate_s==CNT_GATE_S_MAX)calc_flag<=1'b1;elsecalc_flag<=1'b0;//待测时钟频率计算always @(posedge clk or negedge rst_n)if(!rst_n)freq_reg<=1'b0;else if(calc_flag)freq_reg<=(CLK_STAND_FREQ*cnt_clk_test_reg/cnt_clk_stand_reg);//将计算标志信号打一拍,不然freq输出的是计算之前的值always @(posedge clk or negedge rst_n)if(!rst_n)calc_flag_reg<=1'b0;else calc_flag_reg<=calc_flag;//频率值输出always @(posedge clk or negedge rst_n)if(!rst_n)freq<=1'b0;else if(calc_flag_reg)freq<=freq_reg[33:0];endmodule

三、数码管显示模块设计

因为数码管部分代码不是本次的重点,所以只给出代码,不给出设计过程

1.数码管之二进制转8421BCD码部分

module bcd_8421(input wire clk,input wire rst_n,input wire [19:0]data,output reg [3:0]unit,output reg [3:0]ten,output reg [3:0]hun,output reg [3:0]tho,output reg [3:0]t_tho,output reg [3:0]h_hun);reg [4:0]cnt_shift;reg [43:0]data_shift;reg shift_flag;always @(posedge clk or negedge rst_n)if(!rst_n)cnt_shift<=1'b0;else if(cnt_shift==5'd21 && shift_flag)cnt_shift<=1'b0;else if(shift_flag)cnt_shift<=cnt_shift+1'b1;elsecnt_shift<=cnt_shift;always @(posedge clk or negedge rst_n)if(!rst_n)data_shift<=1'b0;else if(!cnt_shift)data_shift<={24'd0,data};else if(cnt_shift<=20 && (!shift_flag))begindata_shift[23:20]<=(data_shift[23:20]>4)? (data_shift[23:20]+2'd3):(data_shift[23:20]);data_shift[27:24]<=(data_shift[27:24]>4)? (data_shift[27:24]+2'd3):(data_shift[27:24]);data_shift[31:28]<=(data_shift[31:28]>4)? (data_shift[31:28]+2'd3):(data_shift[31:28]);data_shift[35:32]<=(data_shift[35:32]>4)? (data_shift[35:32]+2'd3):(data_shift[35:32]);data_shift[39:36]<=(data_shift[39:36]>4)? (data_shift[39:36]+2'd3):(data_shift[39:36]);data_shift[43:40]<=(data_shift[43:40]>4)? (data_shift[43:40]+2'd3):(data_shift[43:40]);endelse if(cnt_shift<=5'd20 && shift_flag)data_shift<=data_shift<<1;elsedata_shift<=data_shift;always @(posedge clk or negedge rst_n)if(!rst_n)shift_flag<=1'b0;elseshift_flag<=~shift_flag;always @(posedge clk or negedge rst_n)if(!rst_n)beginunit<=1'b0;ten<=1'b0;hun<=1'b0;tho<=1'b0;t_tho<=1'b0;h_hun<=1'b0;endelse if(cnt_shift==5'd21)beginunit<=data_shift[23:20];ten<=data_shift[27:24];hun<=data_shift[31:28];tho<=data_shift[35:32];t_tho<=data_shift[39:36];h_hun<=data_shift[43:40];endendmodule

2.数码管显示部分

module seg
#(parameter CNT_MAX=16'd49999 //49999
)
(input wire clk,input wire rst_n,input wire [5:0]point,input wire [19:0]data,input wire seg_en,input wire sign,output reg [5:0]sel,output reg [7:0]seg);wire [3:0]unit;wire [3:0]ten;wire [3:0]hun;wire [3:0]tho;wire [3:0]t_tho;wire [3:0]h_hun;bcd_8421 bcd_8421(.clk(clk),.rst_n(rst_n),.data(data),.unit(unit),.ten(ten),.hun(hun),.tho(tho),.t_tho(t_tho),.h_hun(h_hun));reg [23:0]data_reg;reg [15:0]cnt_1ms;reg flag_1ms;reg [2:0]cnt_sel;reg [5:0]sel_reg;reg [3:0]data_disp;reg dot_disp;//控制数码管显示always @(posedge clk or negedge rst_n)if(!rst_n)data_reg<=1'b0;//若显示的十万位为非零数据或需要显示小数点,六个数码管全显示else if(h_hun || point[5])data_reg<={h_hun,t_tho,tho,hun,ten,unit};//若显示的万位数为非零数据或需要显示小数点,数值显示在5个数码管上else if((t_tho || point[4]) && sign)//显示负号data_reg<={4'd10,t_tho,tho,hun,ten,unit};//定义4'd10为显示负号else if((t_tho || point[4]) && !sign)data_reg<={4'd11,t_tho,tho,hun,ten,unit};//定义4‘d11为不显示//若显示的千位数为非零数据或需要显示小数点,数值显示在4个数码管上else if((tho || point[3]) && sign)data_reg<={4'd11,4'd10,tho,hun,ten,unit};else if((tho || point[3]) && !sign)data_reg<={4'd11,4'd11,tho,hun,ten,unit};//若显示的百位数为非零数据或需要显示小数点,数值显示在3个数码管上else if((hun || point[2]) && sign)data_reg<={4'd11,4'd11,4'd10,hun,ten,unit};else if((hun || point[2]) && !sign)data_reg<={4'd11,4'd11,4'd11,hun,ten,unit};//若显示的十位数为非零数据或需要显示小数点,数值显示在2个数码管上else if((ten || point[2]) && sign)data_reg<={4'd11,4'd11,4'd11,4'd10,ten,unit};else if((ten || point[2]) && !sign)data_reg<={4'd11,4'd11,4'd11,4'd11,ten,unit};//若显示的个位数为非零数据或需要显示小数点,数值显示在1个数码管上else if((unit || point[1]) && sign)data_reg<={4'd11,4'd11,4'd11,4'd11,4'd10,unit};else data_reg<={4'd11,4'd11,4'd11,4'd11,4'd11,unit};//计数器计数1msalways @(posedge clk or negedge rst_n)if(!rst_n)cnt_1ms<=1'b0;else if(cnt_1ms==CNT_MAX)cnt_1ms<=1'b0;else cnt_1ms<=cnt_1ms+1'b1;//计数标志位always @(posedge clk or negedge rst_n)if(!rst_n)flag_1ms<=1'b0;else if(cnt_1ms==CNT_MAX-1'b1)flag_1ms<=1'b1;elseflag_1ms<=1'b0;//cnt_sel:从0到5的循环,用于选择当前显示的数码管always @(posedge clk or negedge rst_n)if(!rst_n)cnt_sel<=1'b0;else if(cnt_sel==3'b101 && flag_1ms)cnt_sel<=1'b0;else if(flag_1ms)cnt_sel<=cnt_sel+1'b1;elsecnt_sel<=cnt_sel;//数码管位选信号寄存器always @(posedge clk or negedge rst_n)if(!rst_n)sel_reg<=6'b000_000;else if(!cnt_sel && flag_1ms)sel_reg<=6'b000_001;else if(flag_1ms)sel_reg<=sel_reg<<1;elsesel_reg<=sel_reg;//控制数码管的位选信号,使六个数码管轮流显示always @(posedge clk or negedge rst_n)if(!rst_n)data_disp<=1'b0;else if(seg_en && flag_1ms)case(cnt_sel)3'd0:data_disp<=data_reg[3:0];3'd1:data_disp<=data_reg[7:4];3'd2:data_disp<=data_reg[11:8];3'd3:data_disp<=data_reg[15:12];3'd4:data_disp<=data_reg[19:16];3'd5:data_disp<=data_reg[23:20];default:data_disp<=1'b0;endcaseelsedata_disp<=data_disp;//dot_disp:小数点低电平点亮,需对小数点有效信号取反always @(posedge clk or negedge rst_n)if(!rst_n)dot_disp<=1'b1;else if(flag_1ms)dot_disp<=~point[cnt_sel];elsedot_disp<=dot_disp;//控制数码管段选信号,显示数字always @(posedge clk or negedge rst_n)if(!rst_n)seg<=8'b1111_1111;elsecase(data_disp)4'd0:seg<={dot_disp,7'b100_0000};4'd1:seg<={dot_disp,7'b111_1001};4'd2:seg<={dot_disp,7'b010_0100};4'd3:seg<={dot_disp,7'b011_0000};4'd4:seg<={dot_disp,7'b001_1001};4'd5:seg<={dot_disp,7'b001_0010};4'd6:seg<={dot_disp,7'b000_0010};4'd7:seg<={dot_disp,7'b111_1000};4'd8:seg<={dot_disp,7'b000_0000};4'd9:seg<={dot_disp,7'b001_0000};4'd10:seg<=8'b1011_1111;4'd11:seg<=8'b1111_1111;default:seg<=8'b1100_0000;endcase//sel:数码管位选信号赋值always @(posedge clk or negedge rst_n)if(!rst_n)sel<=6'b000_000;elsesel<=~sel_reg;
endmodule

四、顶层代码设计

顶层代码中包含三个部分:待测时钟输出模块,待测时钟频率计算模块,数码管显示模块
其中待测时钟输出模块我们直接用PLL产生的100MHz,也可以在PLL中再添加新的时钟信号来输出。

1.RTL代码

module freq_meter_top(input wire clk,input wire rst_n,input wire clk_test,output wire clk_out,output wire [5:0]sel,output wire [7:0]seg
);wire [33:0]freq;clk_stand_pll clk_stand_pll0(.areset(~rst_n),.inclk0(clk),.c0(clk_out));seg seg0(.clk(clk),.rst_n(rst_n),.point(6'b001000),.data(freq/1000),.seg_en(1'b1),.sign(1'b0),.sel(sel),.seg(seg));freq_meter_calc freq_meter_calc0(.clk(clk),.rst_n(rst_n),.clk_test(clk_test),.freq(freq));endmodule

2.RTL视图

3.仿真测试模块

`timescale 1ns/1ns
`define clk_period 20module freq_meter_top_tb;reg clk;reg rst_n;reg clk_test;wire clk_out;wire [5:0]sel;wire [7:0]seg;freq_meter_top freq_meter_top0(.clk(clk),.rst_n(rst_n),.clk_test(clk_test),.clk_out(clk_out),.sel(sel),.seg(seg));initial clk=1'b1;always #(`clk_period/2) clk=~clk;initial clk_test=1'b1;always #100 clk_test=~clk_test;initial beginrst_n=1'b0;#(`clk_period*20+1);rst_n=1'b1;enddefparam freq_meter_top0.freq_meter_calc0.CNT_GATE_S_MAX=240;defparam freq_meter_top0.freq_meter_calc0.CNT_RISE_MAX=40;endmodule

仿真波形图:

仿真激励文件中我们设计了一个5MHz的待测信号输入,可以看到计数值freq输出为4968944hz,与5MHz有些许误差,不过这足以证明我们的实验已经成功了,下面就可以开始分配引脚、布局布线、烧录开发板了

五、上板验证


我们设数码管的单位是MHz,可以看到,我们输入100MHz时,输出就是100MHz,验证成功。

总结

频率计的设计相对于前面的设计是复杂了很多的,但是也可以很大程度的锻炼能力,同时设计中的一些细节问题,比如对应不同时钟上升沿的计数值需要注意。每个开发板上的数码管配置都不一定相同,所以在调用数码管的时候,如果发现无法正常显示,可以 查看一下自己数码管的配置,再对代码进行修改。

FPGA之简易频率计的设计相关推荐

  1. FPGA之简易DDS信号发生器设计

    文章目录 前言 一.DDS信号发生器 1.DDS是什么 2.DDS工作原理 二.模块代码 1.调用rom模块储存波形图 2.按键控制模块 2.按键消抖模块 3.DDS生成模块 4.顶层模块 5.RTL ...

  2. FPGA—简易频率计(附代码)

    目录 1. 内容概要 2. 理论学习 3. 实操 3.1 整体设计 3.2 频率计算模块 3.2.1 模块框图 3.2.2  波形图绘制 3.2.3  RTL代码 3.3 顶层模块 3.4 仿真验证 ...

  3. 基于FPGA的简易DDS信号发生器的设计与验证

    基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...

  4. 基于FPGA的简易DDS信号发生器的设计(一)

    写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...

  5. 基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)

    基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板 目录 主要架构 1.计数模块 2.数码显示模块 3.控制信号模块 4.分频模块 例化模块 上板测试图 附:74HC595移位寄存 ...

  6. 利用UltraScale和UltraScale+FPGA和MPSOC加速DSP设计生产力

    利用UltraScale和UltraScale+FPGA和MPSOC加速DSP设计生产力 Accelerating DSP Design Productivity with UltraScale an ...

  7. 基于FPGA的SPI FLASH控制器设计

    1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...

  8. 【FPGA】FIFO的Verilog设计之同步FIFO的设计

    这个同步FIFO的设计方法是调用异步读写双端口RAM来实现的. 关于异步读写双端口RAM的设计,前面博文已经讲到过了:[FPGA]双端口RAM的设计(异步读写) 此时使用双端口RAM来设计FIFO,可 ...

  9. 【FPGA】ROM/EPROM的设计(使用case的方式初始化)

    上篇博文:[FPGA]ROM/EPROM的设计(使用加载文件的方式初始化),提到了这篇博文中要用的方式初始化ROM,在代码中用case语句的方式,给一个地址,给一个数据. 很容易,通过异步的方式来给出 ...

最新文章

  1. 看懂 ,学会 .NET 事件的正确姿势
  2. Java集合(一)、什么是Java集合?
  3. 操作系统内存管理之 内部碎片vs外部碎片
  4. android构建过程
  5. 基础知识---汇编学习笔记
  6. 四十九、深入了解两个并发接口Callable和Runnable的区别
  7. 快速傅里叶变换(FFT)相关内容汇总
  8. 静态类 c# 1614532739
  9. mysql的主主复制模型
  10. ffplay.exe操作方式
  11. 拓端tecdat|用R语言用Nelson Siegel和线性插值模型对债券价格和收益率建模
  12. Install/RemoveoftheServiceDenied!
  13. xlinx ISE的程序下载
  14. matlab r2008a下载,Matlab+R2008a下载地址及安装教程
  15. excel查找空值快捷键_Excel快捷键查询
  16. windows server2019共享选项中网络发现无法启用
  17. 数据分析【实践】——教育行业指标体系搭建和生命周期维护
  18. 【学渣告诉你】到底神马是傅里叶级数!!!!!!
  19. 美国华盛顿州立大学计算机排名,2020年华盛顿州立大学排名TFE Times美国最佳计算机科学硕士专业排名第38...
  20. rviz显示矩形框BoundingBox

热门文章

  1. 千里马 android framework之MotionEvent.ACTION_CANCEL怎么产生-讨厌的android触摸面试题
  2. c语言程序设计教程刘三满答案,清华大学出版社-图书详情-《C语言程序设计教程》...
  3. android 录像静音,Android – 静音麦克风录制视频时
  4. matlab中simple函数怎么用,matlab里simple函数
  5. Struts2 学习记录(2)
  6. 选择“正激”还是“反激”?这份宝典请收好~
  7. linux DSA 开发(一)
  8. 湖北大学计算机系2020录取分数线,2020湖北大学本科投档录取分数线
  9. 亚马逊爆款的流量密码原来这么简单 六个步骤打造爆款
  10. 湖南省第六届大学生计算机程序设计竞赛---弟弟的作业