FPGA测频
Posted xxniuren
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA测频相关的知识,希望对你有一定的参考价值。
最近一直在做FPGA的测频,有点心得,和大家分享一下。。
其实在网上找的蛮多测频的资料都归结于两种方法 1.测频法 2.测周期法。其实两种方法各有各的优缺点。测频法就是在给定一个门限时间t,看这个门限时间里待测信号的周期个数n,然后频率F = n/t,这种测频法可以测到很高的频率,当时我们测到了20MHZ误差不大,大约几百,但是这种测量方法在低频的时候不是很准确,而且有效位数无法到小数点,如果你给的是2s的门限,测得的精度就是0.5hz。所以有其局限性。然后是测周期法,测周期法是在待测信号的一个周期内计数标准脉冲的个数(FPGA的时钟晶振,在没有倍频的情况下)。这个有自己的优点,可以测得小数点后几位,当时我们用的是100Mhz的晶振,可以测到小数点后三位,而且和函数信号发生器输出的没有差别。但是这个高频上不去 当时我们测100KHZ的波形就不是很准确了的,我当时算过的,如果用100M的晶振,要测100k,此时要测1000个周期,如果测100020hz,这时候要测999.9个周期,这时候FPGA就没有什么分辨能力了,所以这个高频测不是很准。
综上,FPGA测频时候,用测频法,高频上的去,但是无法测到小数点后,如果不是要很高的精度的话,这种方法其实可以采用的。用测周期法,低频下的来,还可以侧刀精确的小数点后几位,但是高频不是很精确。
我们做的项目需要有很高的精准度,频率在几十K到几百K,我们经过自己的考虑后还是选择了测周期法,而且这种方法在经过改进之后可以在几百K的时候还保持者1hz的精度。在这里介绍一下。1 提高时钟频率,大家可以计算一下,当FPGA时钟在100M的时候如果对几十HZ的变化没有反应的话,给时钟增加到1000M,这时候就会对几十hz的变化也敏感了的。2 增加测量的周期,就是不是在一个周期内计算标准脉冲的个数,而是在多个周期里计算标准脉冲的个数。其实这两种方法的本质就是增加计数次数。 提高时钟,同样的时间内,计数的次数会增加,如果说没增加时钟时,1hz的方波要100000000次计数,如果把时钟提高到1000M的话,1hz的方波要1000000000次计数,比原先的多了10倍,所以如果再来小hz的改变,那么计数将被放大10倍,这样提高其精准度。增加测量周期,如果只是在一个周期内,频率的小增加,使多计数了一个点的话,那么延长为N个周期的话,此时的计数就为N个点,这样的话也是把计数点数放大了N倍,使得更加的准确。但是一般的话FPGA的时钟有自己的限制,不能无限倍上去,所以我推荐大家用延长周期的测量方法。
现在我把我的FPGA测周期法的程序给贴出来,时钟是100MHZ。
/*====================================================
程序名称:pinlvji
编者:xxniuren
日期:2012 8
程序目的:用测频法来测待测信号的频率,用的时钟是
100mhz的晶振,n/f2 = 1/(2*f1) f1 = f2/2*n
参数含义:clk--时钟信号 rst_n--复位信号 w_clk 单片机给的
时钟控制信号 cs--单片机给的使能信号 data FPGA给单片机的数据
clk_in 所要测得的信号 data_all_buf1和data_all_buf2是缓存器
====================================================*/
module pinlvji(clk,w_clk,cs,data,clk_in);
input clk;
input w_clk;
input cs;
input clk_in;
output data;
reg data;
reg en;
reg[15:0]jishu;
reg[6:0]count;
reg[31:0] data_all;
reg[31:0] count1;
reg[31:0] count3;
reg[31:0] count2;
reg[31:0] data_all_buf1;
//***************************************************
always@(posedge clk)
begin
count1 <= count1 + 1'b1;
count3 <= count1;
end
//********************************************************
always@(posedge clk_in)
begin
jishu <= jishu + 1'b1;
if(jishu == 16'd999)
begin
count2 <= count3;
data_all_buf1 <= count3 - count2;
jishu <= 16'd0;
end
end
/**********************************************************/
always@(posedge w_clk )
begin
if(cs == 1) begin
if(count == 32'd32)
begin
count <= 0;
data_all <= data_all_buf1;
end
else begin
count <= count + 32'd1;
data <= data_all[0];
data_all <= data_all >> 1;
end
end
end
endmodule
这个程序前面的两个触发就解决了所有问题了的,后面的always@(posedge w_clk )是来由FPGA发送数据,单片机接受数据的一个单工通信,大家可以不用太了解,该测频的核心点就是用一个寄存器一直在计数,当来了一个待测信号的上升沿的时候,把计到的数给另一个寄存器,同时两个寄存器相减,得到所需测量的东西,没有溢出的问题(这个我带过数试过的,大家可以仔细点带几个数试一下,看溢出后的第一个周期)。后面的通信的话,我下次再来详细解释如何单片机和FPGA全双工通信。这就介绍到这里吧,虽然有点粗想,但是程序在这里,大家可以试试看。。
以上是关于FPGA测频的主要内容,如果未能解决你的问题,请参考以下文章