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