当前位置:文档之家› 基于FPGA的等精度数字频率计总结

基于FPGA的等精度数字频率计总结

作品总结
智冰冰
前几天做了数字频率计,虽然做的不是太好吧,但是还算是做出来了,我在这里就对大家分享一下我的制作过程,希望想做频率计的朋友能够少走一些弯路,如果有不好的地方请大家提出来,如果有更好的方法也可以和我交流交流。

拿到这个题目我首先看到题目要求频率计要能测频率、测周期、测占空比,所以我们要准备的东西就要有FPGA板,51开发板(主要利用数码管模块)、直流稳压电源、数字信号发生器。

准备好这些东西之后就要考虑作品方案问题了。

确立作品方案是整个作品中比较重要的一部分,如果作品方案不合理,就不会做出来比较好的作品。

在确立数字频率计设计方案的时候,首先就要确定用什么方法实现测频率、测周期、测占空比,查找了一些资料,大概知道了一下三种方法:
(1)测频率法:测频率法是用脉冲信号产生一个固定的闸门时间t,在固定的闸门时间t内对被测信号进行计数,然后运算求出被测信号频率、周期,但是在闸门时间t内不能保证被测信号计数为整数个,这就会让被测信号产生±1的误差,所以当被测信号频率高时测量比较准确,但是测低频时误差就比较大了。

(2)测周期法:测频率法是用被测信号作为门控信号,在闸门时间t内对脉冲信号进行计数,然后运算求出被测信号频率、周期,但是同样的在闸门时间t内不能保证脉冲信号计数为整数个,这就会让脉冲信号产生±1的误差,所以当被测信号频率低时,相对来说比较准确,但对于高频来说误差就大了。

(3)等精度法:等精度测量是用脉冲信号产生一个预置闸门,然后在预置闸门时间内通过被测信号上升沿产生一个实际闸门,这样实际闸门刚好是被测信号的整数倍。

在计数允许时间内,同时对脉冲信号和被测信号进行计数,再通过数学公式推导得到被测信号的频率。

由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l周期误差,但是会产生对脉冲信号±1周期的误差。

但是相对测频率法来说误差相对较小。

确立好自己的设计方案后,就要设计自己的程序了。

下面就那我的程序进行分析一下,虽然写的不是很完美,但是分析出来之后希望能给大家带来一些帮助。

下图是我的程序的的总体设计,共分了5块:测频、测周期、测占空比、档位选择、数码管显示。

因为只有六个数码管,所以每次只能显示六个数字,所以要进行档位切换,我的测频用了两个档位,hz、khz,测周期用了us、ms两个档位,上面四个档位是根据测得数据的大小自动切换,我用了不同颜色的指示灯进行了标记,另外就是测频、测周期、测占空比的数据不能同时在数码管上显示,所以又加了屏幕切换,用按键控制,并且用不同颜色的指示灯表示。

图一(程序模块设计图)
首先说测频这一块,测频我脉冲信号用的是5mhz的脉冲,因为直接用50mhz的频率计数会使计的数比较大,不好运算,所以要先分频:
因为我采用的是等精度法,所以用了脉冲信号产生一个1s的预置闸门:
然后就是在预置闸门的高电平时利用被测信号的上升沿让实际闸门打开,同样的当预置闸门为低电平时利用被测信号的上升沿让实际闸门闭合。

实现方法如下:
下面就不用说了,就是在实际闸门时间内分别对5mhz的已知信号和被测信号进行计数,这样对被测信号的计数就是整数个。

下面主要说一说怎样将计好的数进行锁存,之前由于方法不正确老是出不来现象,数据要不就是自动清零,要不就是不清零自动累加,纠结了老半天,后来想到了这种方法,当然方法有很多种,我就说我知道的两种,一种是我写的,用世纪闸门的下降沿进行数据锁存:
//************************数据锁存************************
always@(negedge gate) //实际闸门下降沿
begin
datax<=cntx; //被测信号计的数锁存
data<=cnt; //已知信号计的数锁存
end
另一种方法是我看别人的方法,在这里我也说一下:
begin
if(u) //实际闸门打开
begin
fx_count<=fx_count+1'b1; //计数
state<=0; //赋零
end
else case(state) //选择
0: begin
fx_cnt<=fx_count; //锁存
state<=1; //赋一
end
1: fx_count<=0; //清零
endcase
End
测周期也大概用的这种方法,都是在实际闸门时间内对已知信号和被测信号进行计数,只不过最后的计算方法不一样而已。

这里就不再说了,就说一下计算方法吧。

频率计算:
data_pin<=(5000000/data)*datax; //频率计算
因为我的已知信号用的是5mhz的频率,所以:
被测信号频率=(被测信号计数/已知信号计数)*5000000
在测周期时我的已知信号用的是25mhz的频率,所以每个脉冲的时间为40ps=0.04us,所以:被测信号周期=(已知信号计数/被测信号计数)*已知脉冲时间
因为乘以0.04相当于除以25,所以us挡除以25。

data_zhou<=(d_c/d_x)/25; //周期计算(us)
data_zhou<=(d_c/d_x)*40; //周期计算(ps)
在第三个数码管上加上小数点,us挡就变成了ms挡,ps挡就变成了us挡。

虽然用了等精度的测量方法,但是在测频率的低频部分还是误差较大,所以我又在测低频部分改成了周期测量法,一直频率用了1mhz,其他不变,还是在计算的时候注意一下。

我在1khz以上还是采用等精度法测量,小于1khz用测周法测量:
always@(posedge clk)
begin
if(datax>=1000)
begin
Data_pin<=(5000000/data)*datax; 大于1khz
end
else
begin
Data_pin<=1000000000/data2; 小于1khz
end
End
由于大于1khz直接用khz挡,所以在第三个数码管上加上小数点就行了,但小于1khz的用hz挡,不能直接加小数点,所以将算出的数乘了1000,这样就能显示小数部分,使显示更准确,这就是为什么1mhz的频率为什么用1000000000作为被除数了。

看起来是两种算法,其实可以看成一种被测信号计数为1,然后被测信号频率=(1/已知信号计数)*已知信号频率。

下面就是测占空比部分,测占空比我用的是测周法,分别在被测信号的高电平和低电平进行对已知信号进行计数,已知信号用的是50mhz的脉冲信号。

//***********************数据锁存********************************** always@(negedge clkx) //闸门信号下降沿锁存
begin
data_h<=cnt_h;
end
always@(posedge clkx) //闸门信号上升沿锁存
begin
data_l<=cnt_l;
end
计完数之后就是计算,下面是我的计算方法:
data_re<=data_h*10000;
data_p<=data_re/(data_l+data_h);(data_h为高电平计数,data_l为低电平计数)
占空比=高电平计数/(高电平计数+低电平计数),但是我一开始先将高电平计的数乘了10000,因为如果直接相除的出的肯定是零,放大10000倍后,可以使得出的数据精确到小数点后两位,结果为xx.xx%,四个数码管就行了。

档位转换和指示灯的选择我是放到一块的,用一个case语句实现的:
在写着一块时,一开始就是档位转换不正确,显示出来的数据也是对不上,后来发现是在数据赋值的时候赋错了,把频率的数据赋到了占空比上,虽然不是太大的错误,但是这反映出来做事还是要认真!
最后一块就是数码管显示了,我在数码管扫描时频率、周期数据扫面和占空比数据扫描分开写的,因为频率、周期用了六个数码管,占空比只用了四个,没用到的就不用扫描了。

上面说的都是对方波的测量,正弦波的测量由于硬件原因还没有实现,这也是我在这个作品中比较不完善的一方面,但是我会尽快将此功能完善,以弥补不足。

通过做这个作品让我学到了很多,首先就是对资料的收集和分析能力,资料收集现在很方便,网络很发达,但是找到了资料不理解也是不行的,比如这次频率计的制作,用等精度法实现,但是对于等精度法的理解我们几个就有不同的看法,如果说理解上就错了的话,那么在写程序的时候就会出现偏差,有可能就会造成作品的不完善。

另外就是程序的调试,程序写出来了但是不一定能够用,特别是运算那一块,乘以某个数在除以某个数结果可能就改变了,因为在编程语言中除以好和数学中的不太一样,除还分为除完之后取余取模问题,所以这方面要注意,另外就是运算的顺序,如果顺序不一样,运算出来的结果也不一样,所以程序的调试有时候比写程序还要复杂,还要重要!。

相关主题