FPGA等精度测频

频率测量在电子设计和测量领域中经常用到,因此对频率测量方法的研究在实际工程应用中具有重要意义。常用的频率测量方法有两种:频率测量法周期测量法。频率测量法是在时间t内对被测信号的脉冲数N进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。周期测量法是先测量出被测信号的周期T,然后根据频率f=1/T求出被测信号的频率。但是上述两种方法都会产生±1个被测脉冲的误差,在实际应用中有一定的局限性。根据测量原理,很容易发现频率测量法适合于高频信号测量,周期测量法适合于低频信号测量,但二者都不能兼顾高低频率同样精度的测量要求。
1 等精度测量原理
等精度测量的一个最大特点是测量的实际门控时间不是一个固定值,而是一个与被测信号有关的值,刚好是被测信号的整数倍。在计数允许时间内,同时对标准信号和被测信号进行计数,再通过数学公式推导得到被测信号的频率。由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l周期误差,但是会产生对标准信号±1周期的误差。等精度测量原理如图1所示。
在这里插入图片描述
从以上叙述的等精度的测量原理可以很容易得出如下结论:首先,被测信号频率fx的相对误差与被测信号的频率无关;其次,增大测量时间段“软件闸门”或提高“标频”f0,可以减小相对误差,提高测量精度;最后,由于一般提供标准频率f0的石英晶振稳定性很高,所以标准信号的相对误差很小,可忽略。假设标准信号的频率为100 MHz,只要实际闸门时间大于或等于1s,就可使测量的最大相对误差小于或等于10-8,即精度达到1/100 MHz。
2等精度测量实现
等精度测频的原理图如图2所示。图中,预置软件闸门信号GATE是由FPGA的定时模块产生,GATE的时间宽度对测频精度的影响较少,故可以在较大的范围内选择。这里选择预置闸门信号的长度为1s。图中的CNT1和CNT2是2个可控的32位高速计数器,CNT1_ENA和CNT2_ENA分别是其计数使能端,基准频率信号f0从CNT1_CLK输入,待测信号fx从CNT2的时钟输入端CONT2_CLK输入,并将fx接到D触发器的clk端。测量时,由FPGA的定时模块产生预置的GATE信号,在GATE为高电平,并且fx的上升沿时,启动2个计数器,分别对被测信号和基准信号计数,关闭计数闸门必须满足,GATE为低电平,且在fx的上升沿。若在一次实际闸门时间Tx中,计数器对被测信号的计数值为Nx,对标准信号的计数值为N0,而标准信号的频率为f0,则被测信号的频率为fx,则fx=(N0/Ns)f0。图2中的所有功能都在FPGA端实现。
在这里插入图片描述

module cymometer 
    (   
        input                 clk_fs ,    
        input                 rst_n  ,            
        input                 clk_fx ,//		待测信息
		
        output   reg [63:0]   data_fx   //输出频率   
);
 
localparam	 CLK_FS	   = 26'd50_000_000;           
localparam   GATE_TIME = 16'd100;    //门控时间,越大误差越小,但测量时间也会变长    
 
//reg define
reg                	gate        ;           
reg                	gate_fs     ;           
reg                	gate_fs_r   ;          
reg                	gate_fs_d0  ;          
reg                	gate_fs_d1  ;           
reg                	gate_fx_d0  ;          
reg                	gate_fx_d1  ;           
reg    [15:0]   	gate_cnt    ;          
reg    [31:0]   	fs_cnt      ;           
reg    [31:0]   	fs_cnt_temp ;           
reg    [31:0]   	fx_cnt      ;           
reg    [31:0]   	fx_cnt_temp ;           
 
//wire define
wire               neg_gate_fs;            
wire               neg_gate_fx;            
 
assign neg_gate_fs = gate_fs_d1 & (~gate_fs_d0);
assign neg_gate_fx = gate_fx_d1 & (~gate_fx_d0);
 
 
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate_cnt <= 16'd0; 
    else if(gate_cnt == GATE_TIME + 5)
        gate_cnt <= 16'd0;
    else
        gate_cnt <= gate_cnt + 1'b1;
end
 
 
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate <= 1'b0;
    else if(gate_cnt < 5)
        gate <= 1'b0;     
    else if(gate_cnt < GATE_TIME + 5)
        gate <= 1'b1;
    else if(gate_cnt <= GATE_TIME + 5)
        gate <= 1'b0;
    else 
        gate <= 1'b0;
end
 
 
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        gate_fs_r <= 1'b0;
        gate_fs   <= 1'b0;
    end
    else begin
        gate_fs_r <= gate;
        gate_fs   <= gate_fs_r;
    end
end
 
 
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        gate_fx_d0 <= 1'b0;
        gate_fx_d1 <= 1'b0;
    end
    else begin
        gate_fx_d0 <= gate;
        gate_fx_d1 <= gate_fx_d0;
    end
end
 
 
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        gate_fs_d0 <= 1'b0;
        gate_fs_d1 <= 1'b0;
    end
    else begin
        gate_fs_d0 <= gate_fs;
        gate_fs_d1 <= gate_fs_d0;
    end
end
 
 
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        fx_cnt_temp <= 0;
        fx_cnt <= 0;
    end
    else if(gate)
        fx_cnt_temp <= fx_cnt_temp + 1'b1;
    else if(neg_gate_fx) begin
        fx_cnt_temp <= 0;
        fx_cnt   <= fx_cnt_temp;
    end
end
 
 
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        fs_cnt_temp <= 0;
        fs_cnt <= 0;
    end
    else if(gate_fs)
        fs_cnt_temp <= fs_cnt_temp + 1'b1;
    else if(neg_gate_fs) begin
        fs_cnt_temp <= 0;
        fs_cnt <= fs_cnt_temp;
    end
end
 
 
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        data_fx <= 0;
    end
    else if(gate_fs == 1'b0)
        data_fx <= (CLK_FS * fx_cnt ) / fs_cnt;
end
 
endmodule 
  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炼金怪z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值