基于FPGA的数字等精度频率计


传统的测频法原理

直接计数单位时间内被测信号的脉冲数。

  • 在理想条件下:

门控时间=基准时钟的整数倍,门控时间=待测信号的整数倍,计数器检测上升沿

对照示意图,可得如下公式(1)(2):

(1)

(2)

得到待测时钟

(3)

其中CLK_FS为基准时钟,clk_fx待测信号,GATE_TIME门控时间,

       fs_cnt为单位时间内的基准时钟的个数,

       fx_cnt单位时间内的待测时钟的个数。

  • 实际条件下:

门控信号不等于待测信号的整数倍

在对待测信号的计数时会产生误差∆fx_cnt=±1

由公式(3)计算得到待测信号的误差,通过计算可以得到相对误差,因此测量低频信号会产生较大误差.


等精度频率计原理

测量相对误差与被测信号的大小无关,实现整个频段的等精度测量

由图可以看出门控信号是待测信号的整数倍,这样对于基准信号计数时产生误差,从而使门控时间产生误差:

最后被测时钟的误差:,

相对误差: ,相对误差与被测信号,只与被测信号的大小无关。


实验程序设计

  • RTL视图

由以下四个模块:gate,  pexg , CNT, seg_led。

模块gate的作用:通过待测信号生成周期是待测信号周期整数倍(5000)的闸门信号gate,以及一个与基准时钟同步的gate_fs信号。

模块pexg:捕获gate信号和gate_fs的下降沿。

模块CNT:用gate和gate_fs分别待测信号和基准时钟计数,得到fs_cntfx_cnt,并将计算待测信号的频率date_fx。

模块seg_led:用七段数码管显示测量值。

  • 代码实现

顶层模块top_cymometer:

module top_cymometer(
    //system clock
    input                  sys_clk  ,    // 时钟信号
    input                  sys_rst_n,    // 复位信号
//spi没有使用
//		input  CS_N,
//		input  SCLK,
//		output MISO,
    //cymometer interface
    input                  clk_fx   ,    // 被测时钟
//    output                 clk_out  ,    // 输出时钟
	output [7:0] led0,
	output [7:0] led1,
	output [7:0] led2,
	output [7:0] led3,
	output [63:0]data_fx
);

//parameter define
parameter    CLK_FS = 26'd50000000;      // 基准时钟频率值


gate//生成门控信号
(
        .clk_fs      (sys_clk  ),     // 基准时钟信号
        .rst_n       (sys_rst_n),  // 复位信号

        //cymometer interface
        .clk_fx      (clk_fx   ), //待测信号
		  .gate(gate ) , //门控信号
		  .gate_fs(gate_fs) // 同步到基准时钟的门控信号
		  );

pexg//边沿捕获
(
        .clk_fs      (sys_clk  ),     // 基准时钟信号
        .rst_n       (sys_rst_n),  // 复位信号

		  .gate(gate ) , //门控信号
		  .gate_fs(gate_fs), // 同步到基准时钟的门控信号
       .clk_fx      (clk_fx), //待测信号
		
		  .neg_gate_fs(neg_gate_fs),
		  .neg_gate_fx(neg_gate_fx)
		  );
		  
CNT  
    (
	 
	 //system clock
        .clk_fs      (sys_clk  ),     // 基准时钟信号
        .rst_n       (sys_rst_n),  // 复位信号

        //cymometer interface
        .clk_fx      (clk_fx   ), //待测信号
		  .gate(gate )  ,//门控信号
		  .gate_fs(gate_fs) ,// 同步到基准时钟的门控信号
		  .neg_gate_fs(neg_gate_fs),
		  .neg_gate_fx(neg_gate_fx),
        
		  .fs_cnt(fs_cnt)      ,          // 门控时间内基准时钟的计数值
		  .fx_cnt(fx_cnt)      ,           // 门控时间内被测时钟的计数值		
        .data_fx_temp(data_fx)  
);
//通过SPI模块实现与单片机通信
//spi(.clk(sys_clk),
//    .rst_n(sys_rst_n),              
//    .CS_N(CS_N),
//    .SCLK(SCLK),
//    .MOSI(MOSI),
//    .txd_data(data_fx),
//    .MISO  (MISO)
//	 );
//实现比较,最后调试是通过signaltap分析
//seg_led u_seg_led(
//    //module clock
//    .clk         (sys_clk  ),            // 数码管驱动模块的驱动时钟
//    .rst_n       (sys_rst_n),            // 复位信号
   //user interface
//    .data        (data_fx  ),            // 被测频率值
//   .seg_led0	(led0),
//	.seg_led1	(led1),
//	.seg_led2	(led2),
//	.seg_led3 	(led3)
//);
endmodule

gate模块:产生门控信号gate和同步到基准时钟下的门控信号gate_fs

module gate
(
        input                 clk_fs ,     // 基准时钟信号
        input                 rst_n   ,  // 复位信号

        //cymometer interface
        input                 clk_fx ,//待测信号
		  output		reg				gate , //门控信号
		  output    reg           gate_fs // 同步到基准时钟的门控信号
		  );
		  
localparam   GATE_TIME = 16'd5_000;        // 门控时间设置
reg    [15:0]   gate_cnt    ;           // 门控计数

reg             gate_fs_r   ;           // 用于同步gate信号的寄存器

//门控信号计数器,使用被测时钟计数
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate_cnt <= 16'd0; 
    else if(gate_cnt == GATE_TIME + 5'd20)
        gate_cnt <= 16'd0;
    else
        gate_cnt <= gate_cnt + 1'b1;
end
	  

//门控信号,拉高时间为GATE_TIME个实测时钟周期
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate <= 1'b0;
    else if(gate_cnt < 4'd10)
        gate <= 1'b0;     
    else if(gate_cnt < GATE_TIME + 4'd10)
        gate <= 1'b1;
    else if(gate_cnt <= GATE_TIME + 5'd20)
        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

pexg模块:边沿检测,得到的基准时钟下的gate的下降和待测时钟信号下gate的下降沿

module pexg
(
        input                 clk_fs ,     // 基准时钟信号
        input                 rst_n   ,  // 复位信号

 
        input                 clk_fx , 
			input gate,
			input gate_fs     ,  
		  output    neg_gate_fs,
		  output    neg_gate_fx
		  );
reg                gate_fs_d0  ;           // 用于采集基准时钟下gate下降沿
reg                gate_fs_d1  ;           // 
reg                gate_fx_d0  ;           // 用于采集被测时钟下gate下降沿
reg                gate_fx_d1  ;           // 		  
//wire define

//边沿检测,捕获信号下降沿
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) 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
endmodule

计数&计算模块

module CNT
   #(parameter    CLK_FS = 26'd50_000_000,// 基准时钟频率
	parameter  MAX       =  10'd64)  // 定义数据位宽        
    (   //system clock
        input                 clk_fs ,     // 时钟信号
        input                 rst_n   ,  // 复位信号

        //cymometer interface
        input                 clk_fx ,     // 待测信号
		input gate,       // 门控信号(与待测时钟同步)
		input gate_fs,    // 与基准时钟同步的门控信号
		input  neg_gate_fx,//
		input  neg_gate_fs,//
        
		output reg    [MAX-1:0]   fs_cnt      ,           //门控时间内基准时钟信号的个数 
		output reg    [MAX-1:0]   fx_cnt      ,          // 门控时间内待测信号的个数
		output reg  	[MAX-1:0]   data_fx_temp  // 待测信号的频率值
);


reg    [MAX-1:0]   fs_cnt_temp ;           // fs_cnt 计数
reg    [MAX-1:0]   fx_cnt_temp ;           // fx_cnt 计数

//门控时间内待测信号的计数,设置的为5000个,这里重新计数,只是用于检验信号是否正确
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt <= 32'd0;
    end
    else if(gate)begin
      fx_cnt_temp <= fx_cnt_temp + 1'b1;
    end   
    else if(neg_gate_fx) begin
        
        fx_cnt_temp <= 32'd0;
        fx_cnt <= fx_cnt_temp;
        
    end
end

//门控时间内基准时钟的计数
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= 32'd0;
    end
    else if(gate_fs)
        begin
        fs_cnt_temp <= fs_cnt_temp + 1'b1;
        end
    else if(neg_gate_fs) begin
        
        fs_cnt_temp <= 32'd0;
		fs_cnt <= fs_cnt_temp;
    end
end
//计算待测信号的频率值
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        data_fx_temp <= 64'd0;
    end
    else if(gate_fs == 1'b0)
			data_fx_temp <=CLK_FS*fx_cnt/fs_cnt;
end

endmodule

seg_led模块。

原本打算用FPGA上的7段数码管显示,所用的DE0实验板数码管个数不够,不便显示,没有使用,于是使用signaltap分析验证


调试验证

-待测频率 5MHz  5.0Vpp

测量结果:5,000,000Hz


-待测时钟 100KHz

Signaltap测量值:100001Hz

-待测时钟 100Hz

Signaltap测量值:100Hz

-待测时钟输入:123456Hz

Signaltap测量值:123457Hz


结论

当输入待测方波信号赋值(实验测量使用的是5.0Vpp),测量结果准确稳定,能够在全频段实现比较精确的测量。


补充

上述实验测试的信号源输入方式很不安全,当信号幅度5Vpp,偏移0mV,意味着信号是\pm2.5V的输出,而FPGA通常输入范围是0~3.3V,极限是-0.7V~4.0V

信号源输出的下限超出了FPGA允许的下限,是比较危险的,推荐的设置是输出3.3Vpp,偏移1.65V。

  • 18
    点赞
  • 184
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

juajua_Z

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

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

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

打赏作者

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

抵扣说明:

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

余额充值