简易频率计的设计与验证

1.原理

频率测量法缺点:时间T确定,但不能保证被测时钟信号在测量时间T内的时钟周期是整数倍。N出现误差那么 结果也会出现误差,而且被测信号的频率越小,T不变,N的个数就会变小,而误差是不变的。N越小误差对测量的结果影响是越大的。反之,被测信号的频率越大,T不变,N约大,那么正负1个时钟周期的影响较小。

周期测量法直接测上升沿的一个时钟周期

缺点:如果被测时钟信号的频率较低,测量时钟信号的上升沿是比较容易的,如果被测信号的频率很高,那么就需要用很高的计时器测量微小的时间差。所以周期测量法在高频时往往不能满足精度要求。但是比较适合测量低频。但是用周期测量法测量频率也是可以的,可以测量多个时钟炸藕其的时间,比如求100个时钟周期所持续的时间,T/100就等于单个的时钟周期,然后求出频率,可以稍微提高精度。

TX与软件闸门会出现正负1个时钟周期的误差,实际闸门没有误差,标准时钟信号的频率是已知的,在实际闸门的有效期内,对标准时钟信号进行计数,计数也会有1个周期的误差,与频率测量法的成因是一致的。

等精度测量法消除了被测时钟信号正负1个时钟周期的误差,但是会产生对标准时钟信号正负1个时钟周期的误差。(消除被测时钟信号+-1的误差,产生可控制的标准时钟误差)

减小误差的两种方式:

(1)增加软件闸门的时间:实际闸门也会增加,标准时钟信号的的计数也会增加,而+-1的误差是不变的,因此误差对Y的影响也缩小了。其他值不变对被测新年好的影响也会变小。可以缩小频率测量值的误差。

(2)提高标准时钟信号的频率:实际测量时间TX不变,频率增加,Y值也会增加,误差不变,对Y值得营销变小,对实际被测信号频率检测得误差也会变小。

以上两种方式得原理都是提高Y值。

因为时钟IP核生成的频率是HZ,数码管的数据位可能会溢出,首先将测得得频率除以1000,单位就变成了KHZ,然后再把小数点放到第3位,单位就又扩大了1000倍,现在的单位是MHZ。

软件闸门是1S,但是计数器不能只计1S,要计1.5s。因为前0.25s是被测时钟稳定的时间,中间1S是测试时间,最后0.25s是计算频率的时间。

1.5s=1500ms=1500_000us=1500_000_000ns

1500_000_000/20=75,000,000=0100011110000110100011000000(27位)

0.25s=250ms=250_000us=250_000_000ns

250_000_000/20=12,500,000

1s=1000ms=1000_000us=1000_000_000ns

1000_000_000/20=50_000_000

clk_stand的时钟是100MHZ

2.代码

以上是被检测信号的时钟频率,实际产生的是右边小数点位很多的值

仿真对了,但是上板错误要打开在线逻辑分析仪。

然后全编译

默认0.9999等于0,FPGA中都是整数,出现小数默认为0。

做出以上修改,先乘后除

因为数码管显示除以了1000.数码管最多显示999_999,所以s是999_999_999,而位宽只有32位宽,因此位宽是不够的。

需要57位位宽,以防万一增加到64位。

将在线调试关闭,在线调试会使用芯片的资源。再次进行全编译,再次下载程序

最终波形图

2.1  freq_meter_calc.v

module freq_meter_calc(	
	input wire		sys_clk		,
	input wire		sys_rst_n	,
	input wire		clk_test		,
	
	output reg[31:0]freq   			//因为6个数码管,最夿999-?999,迌且除以亿1000,所以是30位位宽,以防万一定义32位宽

);

parameter CNT_GATE_S_MAX  =27'd74_999_999,
		  CNT_RISE_MAX    =27'd12_499_999,
		  CNT_STAND_FREQ  =27'd100_000_000;

reg  [26:0]cnt_gate_s;
reg gate_s;
reg gate_a; 
reg [47:0]cnt_clk_test; //没有说为仿么要定义这么夿
reg gate_a_test_reg;
wire gate_a_fall_t;
reg [47:0]cnt_clk_test_reg;
wire clk_stand;
reg [47:0]cnt_clk_stand;
reg gate_a_stand_reg;
wire gate_a_fall_s;
reg [47:0]cnt_clk_stand_reg;
reg calc_flag;
reg [63:0]freq_reg;
reg calc_flag_reg;


assign gate_a_fall_t=((gate_a==1'b0)&&(gate_a_test_reg==1'b1)) ? 1'b1 : 1'b0; 

assign gate_a_fall_s=((gate_a==1'b0)&&(gate_a_stand_reg==1'b1))?1'b1:1'b0;


always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_gate_s<=27'd0;
	else if(cnt_gate_s==CNT_GATE_S_MAX)
		cnt_gate_s<=27'd0;
	else 
		cnt_gate_s<=cnt_gate_s+1'b1;
		
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;
		  
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		gate_a<=1'b0;
	else
		gate_a<=gate_s;
		
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_test<=48'd0;
	else if(gate_a==1'b0)
		cnt_clk_test<=48'b0;
	else if(gate_a==1'b1)
		cnt_clk_test<=cnt_clk_test+1'b1;
	else
		cnt_clk_test<=cnt_clk_test;


always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)		
		gate_a_test_reg<=1'b0;
	else if(gate_a==1'b1)
		gate_a_test_reg<=gate_a;
	else
		gate_a_test_reg<=1'b0;
		
	
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)	
		cnt_clk_test_reg<=48'b0;
	else if(gate_a_fall_t==1'b1)
		cnt_clk_test_reg<=cnt_clk_test;
	else
		cnt_clk_test_reg<=cnt_clk_test_reg;


always@(posedge clk_stand or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_stand<=48'd0;
	else if(gate_a==1'b0)
		cnt_clk_stand<=48'd0;
	else if(gate_a==1'b1)
		cnt_clk_stand<=cnt_clk_stand+1'b1;
	else
		cnt_clk_stand<=cnt_clk_stand;
		
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;//这里我原来写错了
  	
		
always@(posedge clk_stand or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_stand_reg<=48'd0;
	else if(gate_a_fall_s==1'b1)
		cnt_clk_stand_reg<=cnt_clk_stand;
	else
		cnt_clk_stand_reg<=cnt_clk_stand_reg;

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)
		calc_flag<=1'b1;
	else
		calc_flag<=1'b0;
		
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<=(CNT_STAND_FREQ*cnt_clk_test_reg/cnt_clk_stand_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;
		//滞后calc_flag丿个时钟周期,已经完成了计箿
		

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		freq<=32'd0;
	else if(calc_flag_reg==1'b1)
		freq<=freq_reg[31:0];


		
clk_stand clk_stand_inst
(
    .c0(clk_stand),     // output c0
	
    .reset(~sys_rst_n), // input reset
    .inclk0(sys_clk)
);      // input inclk0


// clk_stand clk_stand_inst
// (	.areset	(~sys_rst_n),
	// .inclk0 (sys_clk),
	// .c0		(clk_stand)
// );


endmodule

2.2  freq_meter.v

module freq_meter(
	input wire 			sys_clk		,
	input wire 			sys_rst_n	,
	input wire 			clk_test	,
	
	output wire 		clk_out		,
	output wire 		ds			,
	output wire 		oe			,
	output wire 		shcp		,
	output wire			stcp		
);

wire [31:0]freq;



freq_meter_calc freq_meter_calc_inst(	
	.sys_clk	(sys_clk)	,
	.sys_rst_n	(sys_rst_n),
	.clk_test	(clk_test)	,
	
	.freq   	(freq)		
);


seg_595_dynamic seg_595_dynamic_inst(
	.sys_clk		(sys_clk)	,
	.sys_rst_n		(sys_rst_n),
	.data			(freq/1000),
	.point			(6'b001_000),
	.sign			(1'b0),
	.seg_en			(1'b1),
	
	.ds				(ds	),
	.oe				(oe	),
	.shcp			(shcp),
	.stcp		    (stcp)
);


clk_test clk_test_inst
   (
    .c0(clk_out),     // output c0
   
   .reset(~sys_rst_n), // input reset
   .inclk0(sys_clk));      // input inclk0



// clk_test clk_test_inst
// (
	// .areset	(~sys_rst_n),
	// .inclk0 (sys_clk),
	// .c0		(clk_out)
// );

endmodule

2.3  tb_freq_meter.v

`timescale 1ns/1ns
module tb_freq_meter();

reg sys_clk;
reg sys_rst_n;
reg clk_test;

initial 
	begin
		sys_clk=1'b1;
		sys_rst_n<=1'b0;
		clk_test<=1'b1;
		#20
		sys_rst_n<=1'b1;
	end
	
always #10 sys_clk=~sys_clk;
always #100 clk_test=~clk_test;  //涓?涓椂閽熷懆鏈熷氨鏄?200ns=0.2us=0.0002ms=0.000_0002s,鎵?浠ラ鐜囩瓑浜?1/0.0000002=	5,000,000hz=5MHZ	

defparam freq_meter_inst.freq_meter_calc_inst.CNT_GATE_S_MAX=74_9;
defparam freq_meter_inst.freq_meter_calc_inst.CNT_RISE_MAX=12_4;


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

	.clk_out	(clk_out	)	,
	.ds			(ds			),
	.oe			(oe			),
	.shcp		(shcp		),
	.stcp		(stcp		)
);


endmodule

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值