FPGA_频率计

一般计算频率有三种方法:频率测量法、周期测量法、等精度测量法

频率测量法

在已知的时间T内,对被测信号的周期个数N进行计数。所以被测信号的周期为T/N,被测信号的频率为N/T。缺点:无法保证时间T是被测信号的整数倍,所以会有一个被测信号周期的误差。可以增加时间T的长度来减小这种误差。这种方法适合测量高频的信号。

周期测量法

对被测信号周期的时间T进行测量。缺点:无法保证时间T是系统时钟的整数倍,所以会有一个系统时钟周期的误差。可以增加系统时钟的频率,或者测量多个被测信号周期来减小这种误差。这种方法适合测量低频的信号。

等精度测量法

先人为规定一个测量时间T1,然后在被测信号下对其同步(打一拍),得到T2,在T2下计算被测信号的周期个数,这样就消除了频率测量法里的误差。然后用一个已知的高频信号(一般PLL生成)来确定T2的真实时间,这样也会存在“已知的高频信号”的一个周期的误差,但是这是一个高频信号,误差在极小范围内。这种方法高、低频信号都可以测。但过程比前两种复杂。如图

 

module freq(clk_50m,rest,clk_test,data);

parameter cnt_gate_sMAX=27'd74_999_999;//1.5
parameter cnt_gateMAX=27'd17_499_999;//0.5
parameter cnt_100m_freq=27'd100_000_000;//定义100M的频率参数,方便计算

input clk_50m,rest,clk_test;
output reg[26:0]data;

reg [26:0]cnt_gate_s;//软件闸门计数器,存1.5s
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_100m;//
reg gate_a_clk_100m_reg;//
reg [47:0]cnt_clk_100m_reg;//
reg calc_flag;
reg calc_flag_req;
reg [63:0]data_reg;//计算过程中,会产生很大位宽的数,先用它存

wire gate_a_fall_t;//提取出的下降沿
wire clk_100m;
wire gate_a_fall_s;


always@(posedge clk_50m or negedge rest)
	if(!rest)
		cnt_gate_s<=27'd0;
	else if(cnt_gate_s==cnt_gate_sMAX)
		cnt_gate_s<=27'd0;
	else
		cnt_gate_s<=cnt_gate_s+27'd1;

always@(posedge clk_50m)
	if(!rest)
		gate_s<=1'b0;
	else if(cnt_gate_s>cnt_gateMAX && cnt_gate_s<=(cnt_gateMAX-cnt_gateMAX))
		gate_s<=1'b0;
	else
		gate_s<=1'b0;

always@(posedge clk_test or negedge rest)
	if(!rest)
		gate_a<=1'b0;
	else
		gate_a<=gate_s;

always@(posedge clk_test or negedge rest)
	if(!rest)
		cnt_clk_test<=48'd0;
	else if(gate_a==1'b0)
		cnt_clk_test<=48'd0;
	else if(gate_a==1'b1)
		cnt_clk_test<=cnt_clk_test+1'd1;

always@(posedge clk_test or negedge rest)
	if(!rest)
		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 negedge rest)
	if(!rest)
		cnt_clk_test_reg<=48'd0;
	else if(gate_a_fall_t==1'b1)
		cnt_clk_test_reg<=cnt_clk_test;
	
always@(posedge clk_100m or negedge rest)
	if(!rest)
		cnt_clk_100m<=48'd0;
	else if(gate_a==1'b0)
		cnt_clk_100m<=48'd0;
	else if(gate_a==1'b1)
		cnt_clk_100m<=cnt_clk_100m+48'd1;

always@(posedge clk_100m or negedge rest)
	if(!rest)
		gate_a_clk_100m_reg<=1'b0;
	else 
		gate_a_clk_100m_reg<=gate_a;
		
assign gate_a_fall_s=((gate_a_clk_100m_reg==1'b1)&&(gate_a==1'b0))?1'b1:1'b0;		
	
always@(posedge clk_100m or negedge rest)
	if(!rest)
		cnt_clk_100m_reg<=48'd0;
	else if(gate_a_fall_s==1'b1)
		cnt_clk_100m_reg<=cnt_clk_100m;

always@(posedge clk_50m or negedge rest)
	if(!rest)
		calc_flag<=1'b0;
	else if(cnt_gate_s==cnt_gate_sMAX)
		calc_flag<=1'b1;
	else
		calc_flag<=1'b0;

clk_100m	clk_100m_inst (
	.areset (~rest),
	.inclk0 (clk_50m),
	.c0 (clk_100m)
	);

always@(posedge clk_50m or negedge rest)
	if(!rest)
		data_reg<=64'd0;
	else if(calc_flag==1'b1)
		data_reg<=(cnt_100m_freq*cnt_clk_test_reg/cnt_clk_100m_reg);
	
always@(posedge clk_50m or negedge rest)
	if(!rest)
		calc_flag_req<=1'b0;
	else
		calc_flag_req<=calc_flag;

always@(posedge clk_50m or negedge rest)
	if(!rest)
		data<=27'd0;
	else if(calc_flag_req==1'b1)
		data<=data_reg[26:0];
endmodule

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值