1 简介
频率计又称为频率计数器,是一种专门对被测信号频率进行测量的电子测量仪器。
2 传统测量法
传统测量法有两种:周期测量法 和 频率测量法。
2.1 周期测量法
- 原理:先测出被测信号的周期 T T T,然后根据频率 f = 1 T f=\frac{1}{T} f=T1 求出被测信号的频率。
- 实现方法:数一个被测信号的周期内有多少个基准时钟,用基准时钟的总周期数来代替被测信号的周期
T
T
T。
误差:被测信号和基准时钟存在一定的错位 △ t △t △t。但假如被测信号的频率比较低,脉冲宽度很宽,当基准时钟频率很低,与被测时钟频率相差较大时,相对误差比较小。
周期测量法适合低频信号频率测量。
2.2 频率测量法
- 原理:在时间 t t t 内对被测信号的脉冲数 N N N 进行计数,然后求出单位时间的脉冲数即为被测信号的频率。
- 实现方法:在基准时钟的时间
t
t
t 内,数有多少个被测信号的脉冲。脉冲数除以
t
t
t 即为被测信号的频率。
误差:被测信号和基准时钟存在一定的错位。但假如被测信号的频率比较高,每个脉冲宽度很窄,当采样宽度足够宽时,误差就会比较小。
频率测量法适合高频信号频率测量。
3 等精度测量法
3.1 原理:
图中,
g
a
t
e
gate
gate 信号为门控信号,它的持续时间
G
a
t
e
Gate
Gate_
t
i
m
e
time
time 为整数倍的被测信号周期。
c
l
k
clk
clk _
f
x
f_x
fx为被测信号(公式中表示被测信号频率),
c
l
k
clk
clk _
f
s
f_s
fs为基准时钟(公式中表示基准时钟信号频率)。
由:
被
测
信
号
周
期
个
数
×
被
测
信
号
周
期
长
度
被测信号周期个数 × 被测信号周期长度
被测信号周期个数×被测信号周期长度
=
基
准
时
钟
周
期
个
数
×
基
准
时
钟
周
期
长
度
= 基准时钟周期个数 × 基准时钟周期长度
=基准时钟周期个数×基准时钟周期长度
=
G
a
t
e
= Gate
=Gate_
t
i
m
e
time
time
可以推导出最终被测信号频率的计算公式:
c l k clk clk _ f x fx fx = = = c l k − f s f s − c n t ⋅ \frac{clk-fs}{fs-cnt}· fs−cntclk−fs⋅ f x fx fx _ c n t cnt cnt
误差:只会差一个基准时钟周期。只要 G a t e Gate Gate_ t i m e time time 足够大,相对误差就可以忽略。
3.2 代码实现
顶层设计模块:
module top_cymometer(
//system clock
input sys_clk , // 时钟信号(系统时钟,50MHz)
input sys_rst_n, // 复位信号
input clk_fx , // 被测时钟
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)
);
endmodule
gate模块:产生周期是待测信号周期整数倍(代码中为5000倍)的门信号gate
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
endmodule
pexg模块:用来捕获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
cnt模块:用来计数,得到 f s fs fs _ c n t cnt cnt 和 f x fx fx _ c n t cnt cnt
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
RTL视图:
3.4 实际测量
按照DE0手册分配管脚
(注意:Quartus 18.1中没有DE0设备Cyclone III EP3C16F484,旧版Quartus 9.1中有,于是重新下载9.1版本。。)
分配管脚:
分配完成后,重新运行程序,然后将程序加载在开发板上。
将电脑、开发板和信号发生器连接:
100Hz:
500Hz:
1kHz:
signaltap结果:
10kHz:
1MHz:
出现了误差。