频率检测计

前言

        频率计是一种用于测量信号频率的仪器。它可以准确地确定电子信号的频率,广泛应用于电子设备的测试和维护中。频率计的工作原理通常包括对输入信号进行采样,并通过内部电路计算信号的周期,从而得到频率值。现代频率计通常具有高精度、高稳定性,并且能够测量从赫兹(Hz)到千兆赫兹(GHz)范围的频率。

正文

一、频率检测计

        1.项目需求

实验目标:设计基于等精度测量法的频率计(误差不大于10ns)测量结果通过数码管进行显示

        2.技术介绍

        误差不大于10ns,1/(10ns/10^9)=100Mhz,需要完成目标精度需要标准时钟为100Mhz。

        常用频率测量法:频率测量法、周期测量法、等精度测量法。
频率测量法:在时间T内对被测时钟信号的时钟周期N进行计数,然后求出单位时间内的时钟周期数,即为被测时钟信号的时钟频率。(在T时间内记N个周期,F= N/T,不能保证周期的整数倍,因而产生一个周期的误差,当T较小时,误差对测量精度影响较大,因此在低频信号测量下误差较大,常用于高频信号测量)
周期测量法:先测量出被测时钟信号的时钟周期T,然后根据频率f=1/T求出被测时钟信号的频率。(不适应高频信号测量  )
等精度测量法:实际闸门Tx于测量信号进行同步,在标准时钟下对实际闸门的Tx进行计算,设置较长的软件闸门或提高标准时钟频率,即可消除频率测量法的误差。

        等精度测量法是一种用于提高测量精度的技术,特别适用于高精度测量仪器,如频率计。其基本原理是通过对输入信号进行多次测量,并采用统计方法来减少误差。具体来说,等精度测量法通常包括以下步骤:对同一个信号进行多次独立测量,记录每次测量结果。将多次测量的结果进行统计分析,例如计算平均值、标准偏差等。通过分析测量结果的分布情况,识别和校正系统误差和随机误差。通过对测量数据的处理,可以得到更精确的频率值,并减小由噪声、环境变化等因素引入的误差。

        等精度测量法的核心思想是通过多次测量和统计分析来提高测量结果的可靠性和准确性,从而在实际应用中减少测量误差。这种方法在高精度频率测量、信号分析等领域中非常重要。

设置高频率时钟调用ip核进行实验

这里要注意锁相环的复位信号时高电平有效,需要将外接的复位信号进行取反后接入。

        3.顶层架构

这里因为数据位宽原因未将数据输出到数码管上,总工程框架如下。

        4.端口描述

clk基础时钟(50MHZ)
rst_n复位按键(低电平有效)
[2:0] sel位选信号
[7:0] seg段选信号
test_clk待测信号

二、代码验证

频率测量模块freq_meter

module freq_meter(

	input 				clk		,
	input					rst_n		,
	input					clk_test	,

	output reg[31:0]	data		
);

parameter cnt_max = 27'd74999999;//1.5s计数器值
parameter cnt_05  = 27'd12499999;//0.5s计数器值
parameter a100Mhz = 27'd100000000;//100Mhz

reg [26:0]	cnt;
reg 			gate;//软件闸门		
reg 			gata;//实际闸门
reg [47:0]	cnt_clk;//高精度计数值
reg 			test_clk;//寄存被测时钟
reg [47:0]	cnt_test;//被测时钟周期计数
reg [47:0]	cnt_long;//高频率时钟下周期计数
reg			gata_100Mhz;//高频率下对实际闸门进行寄存
reg [47:0]	cnt_long_100;//高频率时钟下周期计数寄存
reg 			cale_flag;//计算使能

wire 			clk100Mhz;
wire  		gata_fall;//闸门下降沿检测
wire  		fall_100Mhz;//高频率闸门下降沿检测

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cnt <= 27'd0;
	else
		if(cnt == cnt_max)
			cnt <= 27'd0;
		else
			cnt <= cnt +1'b1;	
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		gate <= 1'b0;
	else
		if((cnt > cnt_05)&&(cnt <= (cnt_max - cnt_05)))//0.5s的软件闸门开启
			gate <= 1'b1;
		else
			gate <= 1'b0;
end

always@(posedge clk_test,negedge rst_n)//使用待测时钟
begin
	if(rst_n == 0)
		gata <= 1'b0;
	else
		gata <= gate;//实际闸门
end

always@(posedge clk_test,negedge rst_n)//使用待测时钟
begin
	if(rst_n == 0)
		cnt_clk <= 48'd0;
	else
		if(gata == 1'b0)
			cnt_clk <= 48'd0;
		else
			if(gata == 1'b1)
				cnt_clk <= cnt_clk + 1'b1;
			else
				cnt_clk <= cnt_clk;
end

always@(posedge clk_test,negedge rst_n)//使用待测时钟
begin
	if(rst_n == 0)
        test_clk <= 1'b0;
    else
        test_clk <= gata;
end

assign gata_fall = ((test_clk == 1'b1)&&(gata == 1'b0))?1'b1:1'b0;

always@(posedge clk_test,negedge rst_n)//使用待测时钟
begin
	if(rst_n == 0)
		cnt_test <= 48'd0;
	else
		if(gata_fall == 1'b1)
			cnt_test <= cnt_clk;
end


always@(posedge clk100Mhz,negedge rst_n)//使用100Mhz
begin
	if(rst_n == 0)
		cnt_long <= 48'd0;
	else
		if(gata == 1'b0)
			cnt_long <= 48'd0;
		else
			if(gata == 1'b1)
				cnt_long <= cnt_long + 1'b1;
			else
				cnt_long <= cnt_long;
end

always@(posedge clk100Mhz,negedge rst_n)//使用100Mhz
begin
	if(rst_n == 0)
		gata_100Mhz <= 1'd0;
	else
		gata_100Mhz <= gata;
end

assign fall_100Mhz = ((gata_100Mhz == 1'b1)&&(gata == 1'b0))?1'b1:1'b0;

			
always@(posedge clk100Mhz,negedge rst_n)//使用100Mhz
begin
	if(rst_n == 0)
		cnt_long_100 <= 48'd0;
	else
		if(fall_100Mhz == 1'b1)
			cnt_long_100 <= cnt_long;
		else
			cnt_long_100 <= cnt_long_100;
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cale_flag <= 1'b0;
	else
		if(cnt == cnt_max)
			cale_flag <= 1'b1;
		else
			cale_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		data <= 32'd0;
	else
		if(cale_flag == 1'b1)
			data <=(a100Mhz / cnt_long_100 * cnt_test);
		else
			data <= data;
end		
	
mypll	mypll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk 	 ),
	.c0 ( clk100Mhz )
	);

endmodule

数码管显示:该模块没有小数点显示,在仿真时未进行数据传入,如需实现数码管显示,对数据进行缩小例如对数据整/1000,再对缩小后的数据进行二进制转bcd,这里要注意数据位宽,不需要显示小数点时最大可显示999999Khz(首先得需要该频率的信号),最小可显示1Khz。

module seg_driver(
 
	input clk,
	input rst_n,
	input [23:0] data_in,//接收数字时钟信号
	
	output reg [2:0] sel,//位选信号
	output reg [7:0] seg//段选信号
);
 
reg [18:0] cnt;//1MS
parameter MAX = 19'd50_000;
//20ns记50000次
//产生1ms的延时
//位选信号1ms变换一次
reg [3:0] temp;
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cnt <= 19'd0;
	else
		if(cnt < MAX - 1)//产生1ms的延时
			cnt <= cnt + 19'd1;
		else
			cnt <= 19'd0;
end 
 
//数码管位选信号控制逻辑
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		sel <= 3'd0;
	else
		if(cnt == MAX - 1)//位选信号6位,1ms的延时到变化一次
			if(sel < 5)
				sel <= sel + 3'd1;
			else 
				sel <= 3'd0;
		else 
			sel <= sel;	
end 
always @(*) begin
	if(rst_n == 0)
		temp <= 4'd0;
	else
		case(sel)//位选信号到将数据输出到对应输出位上
			3'd0	:	temp <= data_in[23:20];
			3'd1	:	temp <= data_in[19:16];
			3'd2	:	temp <= data_in[15:12];
			3'd3	:	temp <= data_in[11:8];
			3'd4	:	temp <= data_in[7:4];
			3'd5	:	temp <= data_in[3:0];
			default	:	temp <= 4'd0;
		endcase
end 
always @(*) begin
	if(rst_n == 0)
		seg <= 8'hff;
	else
		case(temp)//段选信号,对应的数码管信号
			4'd0	:	seg <= 8'b1100_0000;//0
			4'd1	:	seg <= 8'b1111_1001;//1
			4'd2	:	seg <= 8'b1010_0100;//2
			4'd3	:	seg <= 8'b1011_0000;//3
			4'd4	:	seg <= 8'b1001_1001;//4
			4'd5	:	seg <= 8'b1001_0010;//5
			4'd6	:	seg <= 8'b1000_0010;//6
			4'd7	:	seg <= 8'b1111_1000;//7
			4'd8	:	seg <= 8'b1000_0000;//8
			4'd9	:	seg <= 8'b1001_0000;//9
			4'd10	:	seg <= 8'b1000_1000;//A
			4'd11	:	seg <= 8'b1000_0011;//b
			4'd12	:	seg <= 8'b1100_0110;//C
			4'd13	:	seg <= 8'b1010_0001;//d
			4'd14	:	seg <= 8'b1000_0110;//E
			4'd15	:	seg <= 8'b1000_1110;//F
			default	:	seg <= 8'hff;
		endcase 
end 
endmodule 

顶层连线

module freq_meter_top(
	
	input clk,
	input rst_n,
	
	output [2:0]seg,
	output [7:0]sel
);

wire clk_test;
wire[31:0]data;

freq_meter freq_meter(

	.clk		(clk		) ,
	.rst_n	(rst_n	),
	.clk_test(clk_test),
         
	.data		(data		)
);

seg_driver seg_driver(
 
	.clk		(clk		),
	.rst_n	(rst_n	),
	.data_in	(     	),//接收数字时钟信号
        
	.sel		(sel		),//位选信号
	.seg		(seg		)//段选信号
);

pll_test	pll_test_inst (
	.areset ( ~rst_n 	),
	.inclk0 (  clk  	),
	.c0 ( clk_test 	)
	);


endmodule


仿真代码

`timescale 1ns/1ps
module freq_meter_top_tb;
	
	reg 			clk	;
	reg 			rst_n	;
	
	wire [2:0]	seg	;
	wire [7:0]	sel	;

	
defparam 	freq_meter_top.freq_meter.cnt_max = 74;//这里通过赋值减小计数,便于仿真
defparam 	freq_meter_top.freq_meter.cnt_05  = 12;//这里通过赋值减小计数,便于仿真

	
freq_meter_top freq_meter_top(
	
	.clk	(clk	),
	.rst_n(rst_n),
  
	.seg	(seg	),
	.sel	(sel	)
);


initial clk =1;
always #10 clk = ~clk;


initial begin
	rst_n = 0;
	#20
	rst_n = 1;
	#100000
	$stop;
end

endmodule

三、仿真验证

运行仿真文件,在顶层文件中未将数据传至数码管显示文件,这里需要直接调用频率计算模块,通过仿真可看到data的数据为46000000hz

与调用的IP核输出相同,证明实验成功。

a100Mhz / cnt_long_100 * cnt_test=100_000_000/100*46=46_000_000。在高时钟下记100个时钟周期,即1/100_000_000*100s,在这段时间上对被测信号进行计数,记得46个周期,即被测信号频率为46/(1/100_000_000*100)= 46_000_000hz

参考资料

频率计

  • 15
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张明阳.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值