我们通过FPGA测量信号频率,一般来说有两种方案。传统测频法和等精度测频法。
方案一:
传统测频是在一段闸门时间内直接对输入信号的周期进行计数,也被叫做直接测频法。设闸门信号为gate,检测待测信号上升沿,然后判断gate是否为高电平,若为高电平便开始计数。这就存在gate的时间和待测信号周期数可能不成整数倍,导致产生+1hz或-1hz的误差。
方案二:
等精度测频可以弥补传统测频的缺点,它保证了闸门时间永远是被测信号周期的整数倍。设预设闸门信号为base,实际闸门信号为gate,检测待测信号上升沿,当base为高电平时,实际闸门打开,gate为高电平,此时两个计数器同时对标准信号和待测信号的周期进行计数。当base为低电平,实际闸门关闭,gate为低电平计数器停止计数。下面的时序图(从别人博客摘过来的,但是他博客里说时从百度摘过来的,原博客看水印)可以很好的说明。
最终由公式:
待测信号频率/待测信号实际闸门周期数 = 标准信号频率/标准信号实际闸门周期数
可以得到待测信号的频率。
结论:
由等精度测量公式可以知道等精度测频的误差来源于标准信号,而标准信号的频率为50Mhz,可以认为误差足够小,所以可以消除+1hz或-1hz的误差。并且因为等精度测频能够在整个时域保持恒定的误差,所以非常适合用来测量可调位同步时钟信号的频率。
module FreMeasure(
input clk,
input rst_n,
input Sig_in,
output reg [31:0] Fre
);
parameter T_1s = 28'd49_999_999;
//————————————————————————
// 预置闸门
reg [27:0] TCount;
always @ (posedge clk or negedge rst_n)
if(!rst_n)
TCount <= 28'd0;
else if(TCount >= T_1s)
TCount <= 'd0;
else
TCount <= TCount + 1'b1;
reg TCountCnt;
always @ (posedge clk or negedge rst_n)
if(!rst_n)
TCountCnt <= 1'b0;
else if(TCount >= T_1s)
TCountCnt <= ~TCountCnt;
//————————————————————————
// 实际闸门
reg startCnt;
always @ (posedge Sig_in)
if(TCountCnt == 1'b1)
startCnt <= 1'b1;
else
startCnt <= 1'b0;
//————————————————————————
// 在实际闸门中计数
reg [31:0] SigTemp;
always @ (negedge Sig_in)
if(startCnt == 1'b1)
SigTemp <= SigTemp + 1'b1;
else
SigTemp <= 'd0;
//————————————————————————
// 锁存输出
always @ (negedge startCnt)
Fre <= SigTemp;
endmodule