提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
本文章主要讲述了简易频率计的设计。
一、简易频率测量法
常用频率测量法:频率测量法、周期测量法、等精度测量法。
周期测量法是先测量出被测信号的周期 T,然后根据频率 f=1/T 求出被测信号的频率。
频率测量法是在时间 t 内对被测信号的脉冲数 N 进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。
但是上述两种方法都会产生±1 个基准时钟误差或被测时钟的误差,在实际应用中有一定的局限性。
根据测量原理,很容易发现周期测量法适合于低频信号测量,频率测量法适合于高频信号测量,但二者都不能兼顾高低频率同样精度的测量要求。
二、等精度测量法
等精度测量的一个最大特点是测量的实际门控时间不是一个固定值,而是一个与被测信号有关的值,刚好是被测信号的整数倍。在计数允许时间内,同时对基准时钟和被测信号进行计数,再通过数学公式推导得到被测信号的频率。由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l 周期误差,但是会产生对基准时钟±1 周期的误差。
1.原理时序图

首先将软件闸门同步到被测时钟信号,求出实际闸门期间被测时钟信号的打拍次数X;然后引入标准时钟信号fs,将软件闸门同步到标准时钟信号,求出在该范围下标准时钟信号的实际计数Y。最后,被测信号freq = X * Ffx / Y。
2.整体模块设计

3.被测时钟信号计算模块设计

4.被测时钟信号计算模块波形设计

5.被测时钟信号计算模块设计(freq_meter_calc)
module freq_meter_calc(
input sys_clk,
input sys_rst_n,
input clk_test,
output reg [31:0] freq
);
assign sys_rst = ~sys_rst_n;
parameter CNT_GATE_S_MAX = 27'd74_999_999; // =1.5s/20ns
parameter GATE_RISE_MAX = 27'd12_499_999; // =0.25s/20ns
parameter CLK_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 ;
reg [47:0] cnt_clk_test_reg ;
reg [47:0] cnt_clk_stand ;
reg gate_a_stand_reg ;
reg [47:0] cnt_clk_stand_reg;
reg calc_flag ;
reg [63:0] freq_reg ;
reg calc_flag_reg ;
wire gate_a_fall_t ;
wire clk_stand ;
wire gate_a_fall_s ;
//软件闸门计数器
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst)
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 posedge sys_rst)
if(sys_rst)
gate_s <= 1'b0;
else if((cnt_gate_s > GATE_RISE_MAX )
&& (cnt_gate_s <= CNT_GATE_S_MAX - GATE_RISE_MAX ))
gate_s <= 1'b1;
else
gate_s <= 1'b0;
//同步在测试时钟下的软件闸门
always@(posedge clk_test or posedge sys_rst)
if(sys_rst)
gate_a <= 1'b0;
else
gate_a <= gate_s;
//在测试时钟下软件闸门进行的计数
always@(posedge clk_test or posedge sys_rst)
if(sys_rst)
cnt_clk_test <= 48'b0;
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;
//在测试时钟下的软件闸门时序打一拍
always@(posedge clk_test or posedge sys_rst)
if(sys_rst)
gate_a_test_reg <= 1'b0;
else
gate_a_test_reg <= gate_a;
//在系统时钟下的软件闸门下降沿
assign gate_a_fall_t = ((gate_a_test_reg == 1'b1) && (gate_a == 1'b0))
? 1'b1 : 1'b0;
//在测试时钟下软件闸门进行的计数存入寄存器
always@(posedge clk_test or posedge sys_rst)
if(sys_rst)
cnt_clk_test_reg <= 48'b0;
else if(gate_a_fall_t == 1'b1)
cnt_clk_test_reg <= cnt_clk_test;
//(同步在测试时钟下的软件闸门)实际软件闸门在100MHz时钟下的计数
always@(posedge clk_stand or posedge sys_rst)
if(sys_rst)
cnt_clk_stand <= 48'b0;
else if(gate_a == 1'b0)
cnt_clk_stand <= 48'b0;
else if(gate_a == 1'b1)
cnt_clk_stand <= cnt_clk_stand + 1'b1;
//同步在100MHz时钟下的软件闸门
always@(posedge clk_stand or posedge sys_rst)
if(sys_rst)
gate_a_stand_reg <= 1'b0;
else
gate_a_stand_reg <= gate_a;
//gate_a在100MHz时钟下的软件闸门下降沿
assign gate_a_fall_s = ((gate_a_stand_reg == 1'b1) && (gate_a == 1'b0))
? 1'b1 : 1'b0;
//在100MHz时钟下软件闸门进行的计数存入寄存器
always@(posedge clk_stand or posedge sys_rst)
if(sys_rst)
cnt_clk_stand_reg <= 48'b0;
else if(gate_a_fall_s == 1'b1)
cnt_clk_stand_reg <= cnt_clk_stand;
//计算完成标志
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst)
calc_flag <= 1'b0;
else if(cnt_gate_s == CNT_GATE_S_MAX)
calc_flag <= 1'b1;
else
calc_flag <= 1'b0;
//计算freq_req fs=X*fs/Y
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst)
freq_reg <= 64'd0;
else if(calc_flag == 1'b1)
freq_reg <= CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg;
//计算完成标志再打一拍
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst)
calc_flag_reg <= 1'd0;
else
calc_flag_reg <= calc_flag;
//(LK_STAND_FREQ * cnt_clk_test_reg)位宽增加,所以设置中间变量freq_reg
// 做完除法位宽减小,将计算值的低32位赋予freq
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst)
freq <= 32'd0;
else if(calc_flag_reg == 1'b1)
freq <= freq_reg[31:0];
//连接IP生成100MHz时钟
clk_stand clk_stand_inst(
.clk_out1 (clk_stand ),
.reset (sys_rst ),
.clk_in1 (sys_clk ));
endmodule
这里用vivado生成100MHz时钟IP
6.整体设计

顶层模块设计需要生成一个测试时钟的IP,这里频率设置如下图所示

将计算的结果用晶码管进行显示(连接seg_dynamic模块)
顶层文件设计如下:
module freq_meter(
input sys_clk ,
input sys_rst_n ,
input clk_test ,
output clk_out ,
output [5:0] sel ,
output [7:0] seg
);
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)
);
clk_test clk_test_inst(
.clk_out1 (clk_out ),
.reset (~sys_rst_n ),
.clk_in1 (sys_clk )
);
seg_dynamic seg_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 ),
.sel (sel ),
.seg (seg )
);
endmodule
5502

被折叠的 条评论
为什么被折叠?



