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

这篇具有很好参考价值的文章主要介绍了FPGA—简易频率计(附代码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 内容概要

2. 理论学习

3. 实操

3.1 整体设计

3.2 频率计算模块

3.2.1 模块框图

3.2.2  波形图绘制

3.2.3  RTL代码

3.3 顶层模块

3.4 仿真验证

3.5 上板验证

4. 总结

1. 内容概要

       频率测量在电子设计领域和测量领域经常被使用,本文讲解等精度测量法的原理和实现方法,使用FPGA 设计并实现一个简易频率计。

2. 理论学习

      常用的频率测量方法有三种,计频法、计时法、等精度法。
      计频法:在时间 t 内对被测信号的脉冲数进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。由于时间 t 可能存在不是时钟周期N的整数倍,故存在误差。当频率越大时,误差就相对较小,计频法更适合测高频信号。

      计时法:在一个被测信号的周期内,测量基准时钟的个数,得到被测信号的周期,再将其转化为频率。当被测信号频率越小,多计或少计的那个不完整的基准时钟在整个被测信号周期中占比就更小,故更适合低频信号。

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

       由上面讲解知,计频法与计时法可能存在±1个脉冲的误差,而且不能适应时钟频率变化跨度大的检测,在应用上存在局限性。

       等精度测量法与上面两种不同,其最大的特点是软件闸的大小可以自己设定,在被测量时钟信号下同步这样就得到一个实际的闸门,软件闸门不一定等于实际闸门,它会出现正负1的时钟误差,不能确定软件闸门的是否是被测量时钟下的整数倍,但一定能确定实际闸门是被测时钟的整数倍。在实际门控时间内同时对被测信号和标准时钟信号进行时钟周期的计数,然后通过频率与时间的关系就可以计算出被测时钟频率。实际门控信号会产生对标准时钟信号±1时钟周期的误差,为了减小此误差将标准时钟频率设置极高以及增大软件阀门时钟信号时间,误差就会非常小,即使实际阀门无比接近实际计数范围。等精度测量原理示意图如下图。

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

等精度测量法求被测信号频率的计算方法:

    在实际阀门Tx下同时对被测信号和标准时钟信号进行时钟周期的计数分别设为X与Y。

    实际阀门Tx =(1/fs)* Y    Tx/X = fx ;只有fx一个未知量。  (Tfs表示一个被测时钟周期时间)

   =>  fx = (X * fs ) / Y

3. 实操

3.1 整体设计

 实验目标: 对输入的未知时钟信号做频率测量,并将测量结果显示在数码管上。

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

 整体实验框图

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

 工程各模块关系图

由图可知, 本实验工程包括 4 个子模块。

频率计算模块(freq_meter_calc)是实验工程的核心模块,它将输入的待检测信号利用等精度测量法进行计算,得出被测时钟信号时钟频率并输出;

被测时钟生成模块(clk_test_gen)使用PLL IP核产生某一频率的待检测时钟信号,之前文章有讲不详细说明;

数码管显示模块(seg_dynamic)接收频率计算模块输出的计算结果,并显示在数码管上,之前文章有讲不详细说明;

顶层模块(freq_meter)将上述 3 个子功能模块进行实例化,连接各自对应信号,外部输入时钟、复位和待检测信号,输出段选、位选和待检测数据。

3.2 频率计算模块

3.2.1 模块框图

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

       模块内部实例化一个时钟生成 IP 核,负责将 50MHz 系统时钟信号(sys_clk)倍频生成100MHz 标准时钟。为什么要使用 100MHz 时钟信号作为标志信号呢?增大“标准时钟信号”的频率 fs,可以减小误差,提高测量精度。

3.2.2  波形图绘制

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

3.2.3 RTL代码

代码分为四个部分:

step1: 按照原理生成软件闸门、实际闸门

step2:得到待测信号的周期数 X

step3:得到标准信号的周期数 Y

step4:  利用公式进行频率计算

`timescale  1ns/1ns

module  freq_meter_calc
(
    input   wire            sys_clk     ,   
    input   wire            sys_rst_n   ,   
    input   wire            clk_test    ,   //待检测时钟

    output  reg     [33:0]  freq            //待检测时钟频率

);
parameter   CNT_GATE_S_MAX  =   28'd37_499_999  ,   //软件闸门计数器计数最大值  1.5s
            CNT_RISE_MAX    =   28'd6_250_000   ;   //软件闸门拉高计数值,   1.25s
parameter   CLK_STAND_FREQ  =   28'd100_000_000 ;   //标准时钟时钟频率,    100Mhz

wire            clk_stand           ;   
wire            gate_a_flag_s       ;   
wire            gate_a_flag_t       ;   

reg     [27:0]  cnt_gate_s          ;   
reg             gate_s              ;   
reg             gate_a              ;   
reg             gate_a_test         ;   
reg             gate_a_stand        ;   
reg             gate_a_stand_reg    ;
reg             gate_a_test_reg     ;   
reg     [47:0]  cnt_clk_stand       ;   
reg     [47:0]  cnt_clk_stand_reg   ;   
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       ;

//step1:按照原理生成软件闸门、实际闸门
//cnt_gate_s:软件闸门计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_gate_s  <=  28'd0;
    else    if(cnt_gate_s == CNT_GATE_S_MAX)
        cnt_gate_s  <=  28'd0;
    else
        cnt_gate_s  <=  cnt_gate_s + 1'b1;
		
//gate_s:软件闸门
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        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;
		
//gate_a:实际闸门
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a  <=  1'b0;
    else
        gate_a  <=  gate_s;
		
//step2:得到待测信号的周期数 X
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_test  <=  1'b0;
    else
        gate_a_test  <=  gate_a;		
		
//gate_a_test:实际闸门打一拍(待检测时钟下)
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_test_reg <=  1'b0;
    else
        gate_a_test_reg <=  gate_a_test;	
		
//cnt_clk_test:待检测时钟周期计数器,计数实际闸门下待检测时钟周期数。  x++
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_test    <=  48'd0;
    else    if(gate_a_test == 1'b0)
        cnt_clk_test    <=  48'd0;
    else    if(gate_a_test == 1'b1)
        cnt_clk_test    <=  cnt_clk_test + 1'b1;
		
//gate_a_flag_t:实际闸门下降沿(待检测时钟下)
assign  gate_a_flag_t = ((gate_a_test_reg == 1'b1) && (gate_a_test == 1'b0))
                        ? 1'b1 : 1'b0;
						
//cnt_clk_test_reg:实际闸门下待检测时钟周期数,  x
always@(posedge clk_test or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_test_reg   <=  32'd0;
    else    if(gate_a_flag_t == 1'b1)
        cnt_clk_test_reg   <=  cnt_clk_test;	

//step3:得到标准信号的周期数 y		
//使用PLL ipcore生成100Mhz信号
clk_gen clk_gen_inst
(
    .RESET    (~sys_rst_n ),
    .CLK_IN1  (sys_clk    ),
     
    .CLK_OUT1 (clk_stand  )
);	

//gate_a_stand:实际闸门打一拍(标准时钟下)
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_stand    <=  1'b0;
    else
        gate_a_stand    <=  gate_a_test;
		
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gate_a_stand_reg    <=  1'b0;
    else
        gate_a_stand_reg    <=  gate_a_stand;
		
//gate_a_flag_s:实际闸门下降沿(标准时钟下)
assign  gate_a_flag_s = ((gate_a_stand_reg == 1'b1) && (gate_a_stand == 1'b0))
                        ? 1'b1 : 1'b0;
						
//cnt_clk_stand:标准时钟周期计数器,计数实际闸门下标准时钟周期数。  y++
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_stand   <=  48'd0;
    else    if(gate_a_stand == 1'b0)
        cnt_clk_stand   <=  48'd0;
    else    if(gate_a_stand == 1'b1)
        cnt_clk_stand   <=  cnt_clk_stand + 1'b1;
		
//cnt_clk_stand_reg:实际闸门下标志时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk_stand_reg   <=  32'd0;
    else    if(gate_a_flag_s == 1'b1)
        cnt_clk_stand_reg   <=  cnt_clk_stand;
		
//step4: 利用公式进行频率计算		
//calc_flag:待检测时钟时钟频率计算标志信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        calc_flag   <=  1'b0;
    else    if(cnt_gate_s == (CNT_GATE_S_MAX - 1'b1))
        calc_flag   <=  1'b1;
    else
        calc_flag   <=  1'b0;
		
//freq:待检测时钟信号时钟频率
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq_reg    <=  64'd0;
    else    if(calc_flag == 1'b1)
        freq_reg    <=  (CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg );    //   (100MHZ*X)/Y 

 //calc_flag_reg:待检测时钟频率输出标志信号
 always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        calc_flag_reg <= 1'b0;
    else
        calc_flag_reg <= calc_flag;

 //freq:待检测时钟信号时钟频率
 always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq <= 34'd0;
    else if(calc_flag_reg == 1'b1)
        freq <= freq_reg[33:0];	  

endmodule

       * 注意  freq_reg   <=  (CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg );此语句当中的公式 CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg  是一步步进行运算的,先进行的乘法运算需要较大的位宽所以  freq_reg 位宽为64位,后面除法运算结束位宽也会缩小,所以赋给freq的值位宽又为34。 

3.3 顶层模块

`timescale  1ns/1ns

module  freq_meter
(
    input   wire            sys_clk     ,   
    input   wire            sys_rst_n   ,   
    input   wire            clk_test    ,   //待检测时钟

    output  wire            clk_out     ,   //生成的待检测时钟
    output  wire    [5:0]   sel         ,   //数码管位选信号
    output  wire    [7:0]   seg             //数码管段选信号

);

wire    [33:0]  freq    ;   //计算得到的待检测信号时钟频率
wire            CLK_OUT1;   //PLL核输出时钟 
//使用PLL ip核生成待测信号
clk_test_gen    clk_test_gen_inst
(
    .RESET     (~sys_rst_n ),  //复位端口,高电平有效
    .CLK_IN1   (sys_clk    ),  //输入系统时钟

    .CLK_OUT1  (CLK_OUT1   )   //输出生成的待检测时钟信号
);
ODDR2
#(
    .DDR_ALIGNMENT ("NONE" ), 
    .INIT          (1'b0   ), 
    .SRTYPE        ("SYNC" )  
)
ODDR2_inst
(
    .Q  (clk_out    ), 
    .C0 (CLK_OUT1   ), 
    .C1 (~CLK_OUT1  ), 
    .CE (1'b1       ), 
    .D0 (1'b1       ), 
    .D1 (1'b0       ), 
    .R  (1'b0       ), 
    .S  (1'b0       )  
);

freq_meter_calc freq_meter_calc_inst
(
    .sys_clk    (sys_clk    ),  
    .sys_rst_n  (sys_rst_n  ),  
    .clk_test   (clk_test   ),   //待检测时钟

    .freq       (freq       )    //待检测时钟频率  
);

seg_dynamic     seg_dynamic_inst
(
    .sys_clk     (sys_clk    ), 
    .sys_rst_n   (sys_rst_n  ), 
    .data        (freq/1000  ), 
    .point       (6'b001000  ), 
    .seg_en      (1'b1       ), 
    .sign        (1'b0       ), 

    .sel         (sel        ), 
    .seg         (seg        ) 
);
endmodule

3.4 仿真验证

顶层仿真代码:

`timescale  1ns/1ns

module tb_freq_meter();

wire    [5:0]   sel         ;
wire    [7:0]   seg         ;

reg             sys_clk     ;
reg             sys_rst_n   ;
reg             clk_test    ;

initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        #200
        sys_rst_n  <=  1'b1;
        #500
        clk_test      =   1'b1;
    end

always  #10     sys_clk =   ~sys_clk    ;   //50MHz系统时钟
always  #100    clk_test=   ~clk_test    ;   //5MHz待检测时钟

//重定义软件闸门计数时间,缩短仿真时间
defparam freq_meter_inst.freq_meter_calc_inst.CNT_GATE_S_MAX    = 240   ;    //计时最长时间  240X20ns
defparam freq_meter_inst.freq_meter_calc_inst.CNT_RISE_MAX      = 40    ;    

freq_meter  freq_meter_inst
(
    .sys_clk     (sys_clk   ),   
    .sys_rst_n   (sys_rst_n ),   
    .clk_test    (clk_test  ),   

    .clk_out     (clk_out   ),   
    .sel         (sel       ),   
    .seg         (seg       )
);

endmodule

仿真结果:

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

3.5 上板验证

硬件要求:使用短路帽或导线连接 I/O 口 H18 和 H17

模拟输出的待测时钟信号的时钟频率为 250.555MHz。

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

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

   存在一点误差是正常的!

4. 总结

      *(1) 使用PLL IP核时因注意将BUFG关闭,否者会出现的报错。Port <sys_clk> has illegal connections. This port is connected to an input buffer and other compo

        原因是“clk”信号作为其他component的时钟,同时作为IPCore<CLOCK>的输入,故应当去掉一个。

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

*(2)理解等精度测量法,掌握如何计算待测时钟频率。

*(3)脉冲个数可以使用打两拍后生产一个标志位后进行结束。 

*(4) 注意哥模块间的连接

说明:

本人使用的是野火家Xilinx Spartan6系列开发板及配套教程,以下内容如有疑惑或错误欢迎评论区指出。

开发软件:ise14.7     仿真:modelsim 10.5 

如需上述资料私信或留下邮箱!文章来源地址https://www.toymoban.com/news/detail-484314.html

到了这里,关于FPGA—简易频率计(附代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的数字频率计的设计与实现

    基于FPGA的数字频率计的设计与实现 数字频率计是一种重要的电子测试仪器,它可以用来测量信号的频率和周期等参数,被广泛应用于科学研究、工程设计及生产制造等领域。本文将介绍一种基于FPGA的数字频率计的设计与实现方法,并给出相应的源代码。 一、设计原理 数字

    2024年01月23日
    浏览(23)
  • 孩子都能学会的FPGA:第二十五课——用FPGA实现频率计

    (原创声明:该文是 作者的原创 ,面向对象是 FPGA入门者 ,后续会有进阶的高级教程。宗旨是 让每个想做FPGA的人轻松入门 , 作者不光让大家知其然,还要让大家知其所以然 !每个工程作者都搭建了全自动化的仿真环境,只需要双击 top_tb.bat 文件就可以完成整个的仿真(前

    2024年02月02日
    浏览(19)
  • 多功能频率计周期/脉宽/占空比/频率测量verilog,视频/代码

    名称:多功能频率计周期、脉宽、占空比、频率测量verilog 软件:Quartus 语言:Verilog 代码功能:    多功能频率计,可测量信号的周期、脉冲宽度、占空比、频率,语言为verilog,quartus软件设计仿真 代码下载: 多功能频率计周期、脉宽、占空比、频率测量verilog_Verilog/VHDL资源

    2024年02月06日
    浏览(20)
  • 等精度频率计verilog,quartus仿真视频,原理图,代码

    名称:等精度频率计设计verilog quartus仿真 软件:Quartus 语言:Verilog 要求: A:测量范围信号:方波     频率:100Hz~1MHz; B:测试误差:0.1%(全量程) C:时钟频率:50kHz D:预闸门时间:01s E:系统时钟频率:50MHz F:频率计算:保留1位小数 本代码下载:等精度频率计设计verilog,quartus仿真

    2024年02月07日
    浏览(39)
  • 数字频率计Verilog代码Quartus DE1-SoC开发板

    名称:数字频率计Verilog代码Quartus  DE1-SoC开发板(文末获取) 软件:Quartus 语言:Verilog 代码功能: 数字频率计    采用一个标准的基准时钟,在1s里对被测信号的脉冲数进行计数,即为信号频率利用等精度测量法可以测量1hz至99999999Hz信号频率 七段码管显示测量值 本代码已在

    2024年02月03日
    浏览(23)
  • 数字频率计

      电子技术应用实习 目录 1  实习目的、内容和要求 1 1.1 实习目的 1 1.2 实习内容 1 1.3 实习要求 1         1.3.1设计要求..................................................................................................................1 1.3.2实习任务要求 2 2  设计原理及软件简介 3 2.1设计原理 3 2.2M

    2023年04月18日
    浏览(15)
  • 基于51单片机的频率计

    前言:设计一个能产生固定频率的电路,然后经过单片机处理后显示该固定频率的系统。 1、指标以及功能要求 指标:该系统要能够产生一个31KHz的方波,进过单片机脉冲采集后能够在液晶上显示出该频率。要求:所用的知识要涉及到模拟电路知识和数字电路知识。 2、设计分

    2024年02月09日
    浏览(24)
  • VHDL实现数字频率计的设计

    当设计文件加载到目标器件后,拨动开关的K1,使其置为高电平,从输入输出观测模块的输入端输入一个频率大于1Hz的时钟信号,这时在数码管上显示这个时钟信号的频率值。如果使拨动开关置为低电平,数码管上显示的值为系统上的数字信号源的时钟频率。改变数字信号源

    2024年02月02日
    浏览(32)
  • 【单片机】STM32单片机频率计程序,外部脉冲计数程序,基于脉冲计数的频率计程序,STM32F103

    两种方法用于在单片机中实现频率计的功能。 第一种方法是通过定时器来衡量信号的周期,然后将周期转换为频率。在这种方法中,你可以使用单片机的定时器模块来测量输入信号的周期,定时器会产生一个计数值,你可以根据这个计数值来推算出输入信号的周期,并通过简

    2024年02月11日
    浏览(23)
  • 基于51单片机数字频率计的设计与实现

    目录 第一章 系统原理与总体设计 1.1系统组成 1.2系统原理 1.3测量原理 1.4频率测量与总体设计 第二章 硬件电路设计 2.1硬件电路框图 2.2数字频率计原理图 2.3硬件电路设计 第三章 软件程序设计 3.1程序流程图 3.2显示电路程序设计 3.3 定时器初始化程序设计 3.4中断控制程序设计

    2024年02月08日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包