介绍:频率测量在电子设计领域和测量领域经常被使用,相较于传统的模拟频率计,数字频率计具有更高的测量精度、更广的测量范围以及更强的抗干扰能力。
原理:运用等精度测量法进行测量,被测时钟信号的时钟频率fx的相对误差与被测时钟信号无关;增大“软件闸门”的有效范围或者提高“标准时钟信号”的时钟频率fs,可以减小误差,提高测量精度。
运用:对实际闸门下被测时钟信号和标准时钟信号的时钟周期进行计数。
实际闸门下被测时钟信号周期数为,设被测信号时钟周期为
,它的时钟频率
,由此可得等式:
(实际闸门)。
实际闸门下标准时钟信号周期数为,设被测信号时钟周期为
,它的时钟频率
,由此可得等式:
(实际闸门)。
其次,将两等式结合得到只包含各自时钟周期计数和时钟频率的等式:(实际闸门),等式变换,得到被测时钟信号时钟频率计算公式:
。
示意图如下
实验目的:用数码管显示被测信号的频率与占空比
(本实验频率测量参考了野火的简易频率计的设计与验证)
链接:1. 简易频率计的设计与验证 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Mini开发板 文档 (embedfire.com)
模块框图:
signal_meas模块代码
module signal_meas
(
input wire clk_50Mhz , //输入工作时钟,频率50MHz
input wire clk100MHz , //输入标准时钟100MHz
input wire rst_n , //输入复位信号,低电平有效
input wire clk_in , //输入被测信号
output wire [26:0]data_F , //输出被测信号频率
output wire [26:0]data_T //输出被测信号占空比
);
parameter NUM_1S_MAX = 26'd49_999_999 ,
NUM_250MS_MAX =26'd12_499_999 ;
parameter BZ_clk_F = 26'd50_000_000 ;
parameter ZKB_T = 16'd100_00;
reg [27:0] num;
reg gate_r;
reg gate_s;
reg gate_s_bz;
reg gate_s_bz1;
reg gate_s_empty;
wire flag_gate_s;
wire flag_gate_s_bz;
reg [26:0] num_in_x;
reg [26:0] sum_in_x;
reg [26:0] num_50mhz_y;
reg [26:0] sum_50mhz_y;
reg clk_TB;
reg clk_TS;
wire flag_gate_s_empty;
reg [47:0] num_empty_x;
reg [47:0] sum_empty_x;
reg [47:0] num_empty_y;
reg [47:0] sum_empty_y;
reg [64:0] data_F_s ;
reg [164:0] data_T_s ;
assign data_F = data_F_s;
assign data_T = data_T_s;
//产生测量的数据刷新的内部触发信号
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
num <= 'd0;
end
else if(num == NUM_1S_MAX + NUM_250MS_MAX*2)begin
num <= 'd0;
end
else begin
num <= num + 'd1;
end
end
// 产生1S的软件闸门的信号
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
gate_r <= 1'd0;
end
else if(num <= NUM_1S_MAX)begin
gate_r <= 1'd1;
end
else begin
gate_r <= 1'd0;
end
end
//对软件闸门同步到实际闸门
always@( posedge clk_in or negedge rst_n) begin
if(rst_n == 1'b0)begin
gate_s <= 1'd0;
end
else begin
gate_s <= gate_r;
end
end
//计算实际闸门的clk_in电平周期个数
always@( posedge clk_in or negedge rst_n) begin
if(rst_n == 1'b0)begin
num_in_x <= 'd0;
end
else if(gate_s ==1'b1)begin
num_in_x <= num_in_x + 'd1;
end
else begin
num_in_x <= 'd0;
end
end
//产生gate_s闸门的clk_50Mhz的1个时钟周期的信号
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
gate_s_bz <= 1'b0;
end
else begin
gate_s_bz <= gate_s;
end
end
//产生1S实际闸门的clk_in电平周期个数提取标志信号
assign flag_gate_s = (~gate_s) & gate_s_bz;
//提取实际闸门的clk_in电平周期个数
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
sum_in_x <= 'd0;
end
else if(flag_gate_s) begin
sum_in_x <= num_in_x;
end
end
//计算实际闸门的clk_50Mhz电平周期个数
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
num_50mhz_y <= 'd0;
end
else if(gate_s_bz ==1'b1)begin
num_50mhz_y <= num_50mhz_y + 26'd1;
end
else begin
num_50mhz_y <= 'd0;
end
end
//产生gate_s_bz的clk_50Mhz的延时1个时钟周期的信号
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
gate_s_bz1 <= 1'd0;
end
else begin
gate_s_bz1 <= gate_s_bz;
end
end
//产生1S实际闸门的clk_50Mhz电平周期个数提取标志信号
assign flag_gate_s_bz = (~gate_s_bz) & gate_s_bz1;
//提取实际闸门的clk_50Mhz电平周期个数
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
sum_50mhz_y <= 'd0;
end
else if(flag_gate_s_bz) begin
sum_50mhz_y <= num_50mhz_y;
end
end
//进行被测量信号的频率测量
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
data_F_s <= 'd0;
end
else if((num > NUM_1S_MAX )&&(num < NUM_1S_MAX + NUM_250MS_MAX*2)) begin
data_F_s <= (BZ_clk_F*sum_in_x/sum_50mhz_y);
end
end
// measurement empty proportion ,测量占空比
// 将clk_in同步在clk100MHz的时钟下,提高测量精度
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
clk_TB <= 1'd0;
end
else begin
clk_TB <= clk_in;
end
end
//对clk_TB再次同步,防止亚稳态现象
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
clk_TS <= 1'd0;
end
else begin
clk_TS <= clk_TB;
end
end
//计算在闸门内的时间
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
num_empty_x <= 'd0;
end
else if(gate_s ==1'b1)begin
num_empty_x <= num_empty_x + 'd1;
end
else if(gate_s == 1'b0) begin
num_empty_x <= 'd0;
end
end
//计算在闸门内clk_TS高电平上的时间
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
num_empty_y <= 'd0;
end
else if((clk_TS ==1'b1)&&(gate_s == 1'b1))begin
num_empty_y <= num_empty_y + 'd1;
end
else if(gate_s == 1'b0) begin
num_empty_y <= 'd0;
end
end
//new
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
gate_s_empty <= 1'b0;
end
else begin
gate_s_empty <= gate_s;
end
end
//产生1S实际闸门的clk_TS电平周期个数提取标志信号
assign flag_gate_s_empty = (~gate_s) & gate_s_empty;
//提取计算在闸门内的时间
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
sum_empty_x <= 'd0;
end
else if(flag_gate_s_empty) begin
sum_empty_x <= num_empty_x;
end
end
//提取在闸门内clk_TS高电平上的时间
always@( posedge clk100MHz or negedge rst_n) begin
if(rst_n == 1'b0)begin
sum_empty_y <= 'd0;
end
else if(flag_gate_s_empty) begin
sum_empty_y <= num_empty_y;
end
end
//计算占空比
always@( posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0)begin
data_T_s <= 'd0;
end
else if((num > NUM_1S_MAX )&&(num < NUM_1S_MAX + NUM_250MS_MAX*2)) begin
data_T_s <= (ZKB_T*sum_empty_y/sum_empty_x);
end
end
endmodule
bcd_8421模块代码,见我的这一篇文章 :用FPGA设计8421BCD编码-优快云博客
smg模块代码,见我的这一篇文章 :用FPGA设计数码管-优快云博客
key_filter模块代码,见我的这一篇文章 :用FPGA设计软件按键消抖-优快云博客
signal_meas_top模块代码
`timescale 1ns/1ns
module signal_meas_top
(
input wire clk_50Mhz , //输入工作时钟,频率50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
input wire key_in , //按键输入信号
input wire clk_in , //输入被测信号
output wire clk20MHz , //输出测试信号
output reg [7:0] smg_reg , //输出单个数码管显示的数据信号
output reg [7:0] smg_rel //输出数码管选择信号
);
wire clk100MHz ;
wire locked ;
wire rst_n ;
wire key_flag ;
wire [26:0] data_F ;
wire [26:0] data_T ;
wire [31:0] bcd_data_F ;
wire [31:0] bcd_data_T ;
reg [31:0] bcd_data ;
assign rst_n = (sys_rst_n & locked);
reg led_flag_h ;
//把信号key_flag处理为电平反转信号
always@( posedge clk_50Mhz or negedge rst_n) begin
if (rst_n==1'b0) begin
led_flag_h <= 1'b0;
end
else if (key_flag == 1'b1) begin
led_flag_h <= ~led_flag_h;
end
else begin
led_flag_h <= led_flag_h;
end
end
always @(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
bcd_data <= 32'd0;
end
else if(led_flag_h == 1'b1) begin
bcd_data <= bcd_data_F;
end
else begin
bcd_data <= bcd_data_T;
end
end
clk_wiz_0 clk_wiz_0_inst
(
// Clock out ports
.clk_out1(clk100MHz),
.clk_out2(clk20MHz),
// Status and control signals
.reset(~sys_rst_n),
.locked(locked),
// Clock in ports
.clk_in1(clk_50Mhz)
);
signal_meas signal_meas_inst
(
.clk_50Mhz (clk_50Mhz ) ,
.clk100MHz (clk100MHz ) ,
.rst_n (rst_n ) ,
.clk_in (clk_in ) ,
.data_F (data_F ) ,
.data_T (data_T )
);
bcd_8421 bcd_8421_inst1
(
.clk_50Mhz (clk_50Mhz ) ,
.rst_n (rst_n ) ,
.data (data_T ) ,
.bcd_data (bcd_data_T)
);
bcd_8421 bcd_8421_inst2
(
.clk_50Mhz (clk_50Mhz ) ,
.rst_n (rst_n ) ,
.data (data_F ) ,
.bcd_data (bcd_data_F)
);
key_filter key_filter_inst
(
.clk_50Mhz (clk_50Mhz) , //系统时钟50Mhz
.rst_n (rst_n ) , //全局复位
.key_in (key_in ) , //按键输入信号
.key_flag (key_flag ) //key_flag为1时表示消抖后检测到按键被按下
//key_flag为0时表示没有检测到按键被按下
);
smg smg_inst
(
.clk_50Mhz (clk_50Mhz) , //系统时钟50Mhz
.rst_n (rst_n ) , //全局复位
.data_in (bcd_data ) , //输入信号
.point (8'd0 ) , //小数点显示,高电平有效
.smg_reg (smg_reg ) , //输出单个数码管显示的数据信号
.smg_rel (smg_rel ) //输出数码管选择信号
);
endmodule