资源描述
基于VDHL语言的数字频率计设计
唐耀清
电子工程学院·电子信息工程·(9)·2012029140023
【摘要】
数字频率计是使用领域非常广泛的测量仪器,在计算机、通讯设备、音频视频等科研生产领域不可缺少。通过十进制数字显示被测信号频率,具有测量迅速,精度高,显示直观等诸多优点。本实验中,我们使用VHDL开发FPGA的一般流程,在软件开发平台ISE上,采用频率计开发的基本原理和相应的测量方案,在FPGA实验开发板进行数字频率计的设计和实现。
【关键词】:频率计;VHDL;FPGA
【目录】
一、 系统总体要求 2
1. 设计要求 2
2. 系统工作原理 2
2. 单元电路的划分 5
二、 单元电路设计 6
1. 分频器 6
2. 控制器 8
3. 计数器 9
4. 锁存器 13
5. 显示单元 15
三、 设计实现 20
1. 顶层设计 20
2. 管脚分配 20
3. 下载过程 21
四、 测试结果及结论 21
测试结果: 21
实验结论: 21
五、 参考资料 22
一、 系统总体要求
1. 设计要求
要求频率计设计指标如下:
1、被测输入信号:方波
2、测试频率范围为:10Hz~100MHz
3、量程分为三档:第一档:闸门时间为1S时,最大读数为999.999KHz
第二档:闸门时间为0.1S时,最大读数为9999.99KHz
第三档:闸门时间为0.01S时,最大读数为99999.9KHz。
4、显示工作方式:a、用六位BCD七段数码管显示读数。
b、采用记忆显示方法
c、实现对高位无意义零的消隐。
2. 系统工作原理
在电子技术领域内,频率是一个最基本的参数,频率与其它许多电参量的测量方案、测量结果都有十分密切的关系。因此,频率的测量就显得更为重要.而且,目前在电子测量中,频率的测量精确度是最高的。
所谓“频率”,就是周期性信号在单位时间(1秒)内变化的次数。若在一定的时间间隔T内计数,计得某周期性信号的重复变化次数为N,则该信号的频率可表达为:
其中脉冲形成电路的作用是将被测信号变成脉冲信号,其重复频率等于被测频率f。时间基准信号发生器提供标准的时间脉冲信号,若其周期为1s,则门控电路的输出信号持续时间亦准确地等于1s。闸门电路由标准秒信号进行控制,当秒信号来到时,闸门开通,被测脉冲信号通过闸门送到计数译码显示电路。秒信号结束时闸门关闭,计数器停止计数。由于计数器计得的脉冲数N是在1秒时间内的累计数,所以被测频率f=NHz。
比如,时标信号的重复周期为1S,则加到闸门的门控信号作用时间T即闸门时间亦准确地等于1s,即闸门开通时间为1s,这时若计得10 000个数,则按式一,被测频率=10.000Hz,若计数器上单位显示为“kHz”,则显示10.000kHz,即小数点定位在第三位。不难设想,若闸门时间改为T=0.1s,则计数值为1 000,这个数乘以10就等于1s的计数值,即Hz。实际上,当改变闸门时间T时,显示器上的小数点也随着往右移一位(自动定位),即显示10.000kHz。
下面我们来分析计数器测频的测量误差。从公式一可知,上述测频方法的测量误差,一方面决定于闸门时间T准不准,另一方面决定于计数器计得的数准不准。根据误差合成方法,从公式可得:
公式二
公式二中第一项是数字化仪器所特有的误差,而第二项是闸门时间的相对误差,这项误差决定于石英振荡器所提供的标准频率的准确度。现分述如下。
±1误差
在测频时,主门的开启时刻与计数脉冲之间的时间关系是不相关的,所以它们在时间轴上的相对位置是随机的。这样,在相同的主门开启时间内,计数器所计得的数却不一定相同,当主门开启时间T接近甚至等于被测信号周期的整数倍N倍时,此项误差为最大,下图画出的就是这种情况。
图 一1
若主门开启时刻为,而第1个计数脉冲出现在,图 4-2 (a)中示出了>>0的情况(),这时计数器计得N个数(图中N=6);现在再来看图 4-2 (b)情况,即趋近于0,这就有两种可能的计数结果:若第1个计数脉冲和第7个计数脉冲都能通过主门,则可计得N+1=7个数;也可能这两个脉冲都没有能进入主门,则只能计得N-1=5个数。由此可知,最大的计数误差为个数。所以考虑到公式一),可写成
公式三
式中T为闸门时间,为被测频率。从公式三可知,不管计数值N多少,其最大误差总是±1个计数单位,故称“±1个字误差”,简称“±1误差”。而且一定时,增大闸门时间T,可减小±1误差对测频误差的影响。当T选定后,越低,则由±1误差产生的测频误差越大。
闸门时间T准不准,主要决定于由石英振荡器提供的标准频率的准确度,若石英振荡器的频率为,分频系数为k,则
而
所以
(4-4)
可见,闸门时间的准确度在数值上等于标准频率的准确度,式中负号表示由引起的闸门时间的误差为。
通常,对标准频率准确度的要求是根据所要求的测频准确度提出来的,例如,当测量方案的最小计数单位为1Hz,而=Hz,在T=1s时的测量准确度为(只考虑误差),为了使标准频率误差不对测量结果表明产生影响,石英振荡器的输出频率准确度应优于,即比误差引起的测频误差小一个量级。
综上所述,可得如下结论:
1、计数器直接测频的误差主要有两项:即误差和标准频率误差。一般,总误差可采用分项误差绝对值合成,即
公式五
可把公式五画成下图所示的曲线,即与T,以及的关系曲线。
图 一2
误差曲线
从图可知,一定时,闸门时间T选得越长,测量准确度就越高。而当T选定后,越高,则由于误差对测量结果的影响越小,测量准确度就越高。但是,随着误差的减小,标准频率误差将对测量结果产生影响,并以(图中以为例)为极限,即测量准确度不可能优于。
2、测量低频时,由于误差产生的测频误差大得惊人,例如,为10Hz,T=1s,则由误差引起的测频误差可达到10%,所以,测量低频时不宜采用直接测频方法。
2. 单元电路的划分
通过对实验要求的分析,我们可以将数字频率计的单元电路划分为一下部分。
1、 分频器
分频器的功能是提供标准闸门时间控制信号以精确控制计数器的开闭。
2、 控制器
控制器模块是整个数字频率计时序的关键,只有有恰当的时序关系,才能得到正确的结果。
3、 计数器
计数机是记录在闸门开启时间内方波上升沿的个数,从而计算出当前信号的频率大小。
4、 锁存器
如果计数器输出直接与译码器相连接,那么在计数过程中输出端则随输入脉冲数的增加而不断跳变,那么显示数码管则也会不断闪烁跳变,让人不能看到稳定的输出,设锁存器后,则不再跳变,便可清晰读出计数结果。
5、 显示部分
显示部分通过对数码管位选信号的循环扫描,实现不同位数上不同数字的显示功能,使测得的数据得以显示。
二、 单元电路设计
1. 分频器
思路:由于频率计闸门时间1s的产生需要1Hz的信号作为时基,并且显示部分的数码管扫描也需要提供1kHz的信号来扫描计数,但FPGA板载晶振只提供48MHz的信号输入,所以需要分频器来从高频获取我们所需要的低频信号。
分频器的工作原理:通过检测输入高频信号的上升沿跳变,并用一个计数单元记录下上升沿的个数,可得其累计时间=上升个数*输入信号周期,直到累计时间为所需低频信号周期的一半时,立即将计数单元清零并将低频信号的输出取反,适当设定累计上升沿的个数,即可获得我们所需的低频信号。
元件符号如图二-1所示:
图 二1
源程序:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity fdiv is
port(fin:in std_logic;
fout100,fout1k:buffer std_logic);
end fdiv;
architecture fdiv_arc of fdiv is
signal cnt1:integer range 0 to 23999:=0;
signal cnt2:integer range 0 to 499:=0;
begin
process(fin)
begin
if fin'event and fin='1' then
if cnt1=23999 then
cnt1 <= 0;
fout1k <= not fout1k;
else
cnt1 <=cnt1 + 1;
end if;
end if;
end process;
process(fout1k)
begin
if fout1k'event and fout1k='1' then
if cnt2=499 then
cnt2 <= 0;
fout100 <= not fout100;
else
cnt2 <=cnt2 + 1;
end if;
end if;
end process;
end fdiv_arc;
仿真结果如图 二2:
图 二2
结果分析:
从fin输入48MHz的信号, fout1k得到1KHz信号的输出,fout100得到1Hz的信号输出。
2. 控制器
思路:控制器通过输入信号bsignal作为时基,对计数器的计数使能、清零,以及锁存器的锁存触发的时序关系进行协调控制,是整个系统运行的关键。计数器的计数使能在一个bsignal信号的上升沿开启,在紧接的下一个上升沿关闭,从而使计数器在bsignal的一个周期所表示的闸门时间内进行计数;在上次使能关闭后,下一次使能未开启前,应对计数器清零以准备下一次计数,同时给锁存器发出锁存触发信号,以此次保存计数的结果到锁存器上。
其时序关系如图二-3所示
图 二3
元件符号如图二-4所示:
图 二4
源程序:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity control is
port(bsignal:in std_logic;
gate,rst,latch:out std_logic);
end control;
architecture control_arc of control is
signal g1,g2:std_logic:='0';
begin
process(bsignal,g1)
begin
if bsignal'event and bsignal='1' then
g1 <= not g1;
end if;
if bsignal'event and bsignal='0' then
g2 <= not g1;
end if;
end process;
gate <= g1;
latch <= g2;
rst <= (not bsignal) and (not g1) and (g2);
end control_arc;
仿真结果如图二-5:
图 二5
结果分析:
仿真结果与设计的时序关系一致。
3. 计数器
思路:计数器在1s的闸门时间内对被测信号进行计数,其计数所得的数值结果即为输入信号的频率,所以如果以十进制的方式对结果输出,其输出即可直接按位序在数码管上显示,而无需另作转换。由本实验要求,计数范围从10Hz到100MHz,如默认显示时单位为KHz,只显示6位数及一个小数点,则计数范围为0.010khz到99999.9khz,最高为实际为10000000Hz位,所以需要8个十进制的计数器级联来实现计数。
其级联方式为异步级联,如图二-6所示,即低位计数器的溢出信号为高一位计数器的时钟信号,并在最高为溢出后将over置位为高电平,表明被测信号超出测量范围。
图 二6
元件符号如图二-7:
图 二7
源程序:
*十进制计数器单元:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity counter_4 is
port(cnt_en,clk,rst:in std_logic;
cnt_out:buffer std_logic_vector(3 downto 0);
cnt_carry:out std_logic);
end counter_4;
architecture cnt_arc of counter_4 is
begin
process(clk,rst)
begin
if rst='1' then
cnt_out <= "0000";
cnt_carry <= '0';
elsif clk'event and clk='1' then
if cnt_en='1' then
if cnt_out="1001" then
cnt_out <= "0000";
cnt_carry <= '1';
else
cnt_out <= cnt_out + '1';
cnt_carry <= '0';
end if;
end if;
end if;
end process;
end cnt_arc;
8位十进制计数器:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity counter is
port(csignal,rst,cnt_en:in std_logic;
over:out std_logic;
result1,result2,result3,result4,
result5,result6,result7,result8:out std_logic_vector(3 downto 0));
end counter;
architecture counter_arc of counter is
component counter_4 is
port(cnt_en,clk,rst:in std_logic;
cnt_out:buffer std_logic_vector(3 downto 0);
cnt_carry:out std_logic);
end component counter_4;
signal c1,c2,c3,c4,c5,c6,c7,c8:std_logic:='0';
begin
u1:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>csignal,
cnt_out => result1,
cnt_carry =>c1);
u2:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c1,
cnt_out => result2,
cnt_carry =>c2);
u3:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c2,
cnt_out => result3,
cnt_carry =>c3);
u4:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c3,
cnt_out => result4,
cnt_carry =>c4);
u5:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c4,
cnt_out => result5,
cnt_carry =>c5);
u6:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c5,
cnt_out => result6,
cnt_carry =>c6);
u7:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c6,
cnt_out => result7,
cnt_carry =>c7);
u8:counter_4 port map(rst => rst,
cnt_en =>cnt_en,
clk =>c7,
cnt_out => result8,
cnt_carry =>c8);
process(rst,c8)
begin
if rst='1' then
over <= '0';
elsif c8'event and c8='1' then
over <= '1';
end if;
end process;
end counter_arc;
仿真结果:
在输入端输入频率为123456Hz的信号,仿真结果如图二-8所示
图 二8
结果分析:
在一个闸门时间内对频率为123456Hz的信号进行计数,最终所得结果为从result6到result1依次输出123457,即所测频率为123457Hz,误差小于1%。
4. 锁存器
思路:锁存器作为保存计数结果的单元,在计数器完成计数后,在接受控制器发出的锁存触发上升沿信号时,将计数器的输出数据存储,而当计数器正在计数中时不保存数据。
元件符号如图二-9:
图 二9
源程序:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity latcher is
port(latchin,overin:in std_logic;
numin1,numin2,numin3,numin4,numin5,numin6,numin7,numin8:in std_logic_vector(3 downto 0);
overout:out std_logic;
numout1,numout2,numout3,numout4,numout5,numout6,numout7,numout8:out std_logic_vector(3 downto 0));
end latcher;
architecture latch_arc of latcher is
begin
process(latchin)
begin
if latchin'event and latchin='1' then
overout <= overin;
numout1 <= numin1;
numout2 <= numin2;
numout3 <= numin3;
numout4 <= numin4;
numout5 <= numin5;
numout6 <= numin6;
numout7 <= numin7;
numout8 <= numin8;
end if;
end process;
end latch_arc;
仿真结果如图二-10:
图 二10
结果分析:
锁存器只在触发信号上升沿时才将输入信号传递到输出上,而在其他时刻输出不随输入改变。
5. 显示单元
思路:显示单元包含两方面作用:一是通过对数码管的动态扫描,将测得的频率数据显示在数码管上,显示的位数为6位包含一个小数点,并且要在当高位为零时将其隐藏;二是通过第8和第7两位是否为零来判断当前需要显示的档位,如7、8两位都为零则是第一档,只有8位为零则是第二档,7、8两位都不为零则是第三档,并根据判断出的档位来决定从锁存器的8位出入中选取哪6个数作为显示,以及决定小数点的位置。
元件符号如图二-11:
图 二11
源程序:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity display is
port(f1k,over:in std_logic;
fvalue1,fvalue2,fvalue3,fvalue4,fvalue5,fvalue6,fvalue7,fvalue8:in std_logic_vector(3 downto 0);
g,dp:out std_logic;
led:out std_logic_vector(6 downto 0);
selecte:out std_logic_vector(2 downto 0));
end display;
architecture display_arc of display is
signal cnt:std_logic_vector(2 downto 0):="000";
-- signal cnt0:std_logic_vector(2 downto 0):="000";
signal data:std_logic_vector(3 downto 0):="0000";
signal hide:std_logic:='0';
signal gear:std_logic_vector(1 downto 0):="00";
begin
process(f1k)
begin
if f1k'event and f1k='1' then
if cnt>="101" then
cnt <= "000";
else
cnt <= cnt + '1';
end if;
end if;
end process;
selecte <=cnt;
process(cnt,gear,fvalue1,fvalue2,fvalue3,fvalue4,fvalue5,fvalue6,fvalue7,fvalue8)
begin
case cnt is
when "000" => case gear is
when "00" => data <= fvalue1;
when "01" => data <= fvalue2;
when others => data <= fvalue3;
end case;
dp <= '1';
when "001" => case gear is
when "00" => data <= fvalue2; dp <= '1';
when "01" => data <= fvalue3; dp <= '1';
when others => data <= fvalue4; dp <= '0';
end case;
when "010" => case gear is
when "00" => data <= fvalue3; dp <= '1';
when "01" => data <= fvalue4; dp <= '0';
when others => data <= fvalue5; dp <= '1';
end case;
when "011" => case gear is
when "00" => data <= fvalue4; dp <= '0';
when "01" => data <= fvalue5; dp <= '1';
when others => data <= fvalue6; dp <= '1';
end case;
when "100" => case gear is
when "00" => data <= fvalue5;
when "01" => data <= fvalue6;
when others => data <= fvalue7;
end case;
dp <= '1';
when "101" => case gear is
when "00" => data <= fvalue6;
when "01" => data <= fvalue7;
when others => data <= fvalue8;
end case;
dp <= '1';
when others => null;
end case;
end process;
process(data,hide)
begin
if hide='0' then
case data is
when "0000" => led <= "1000000";
when "0001" => led <= "1111001";
when "0010" => led <= "0100100";
when "0011" => led <= "0110000";
when "0100" => led <= "0011001";
when "0101" => led <= "0010010";
when "0110" => led <= "0010010";
when "0111" => led <= "1111000";
when "1000" => led <= "0000000";
when "1001" => led <= "0010000";
when others => null;
end case;
else
led <="1111111";
end if;
end process;
process(cnt,fvalue1,fvalue2,fvalue3,fvalue4,fvalue5,fvalue6,fvalue7,fvalue8)
begin
hide <= '0';
case cnt is
when "101" =>
if fvalue8="0000" and fvalue7="0000" and fvalue6="0000" then
hide <= '1';
end if;
when "100" =>
if fvalue8="0000" and fvalue7="0000" and fvalue6="0000" and fvalue5="0000" then
hide <='1';
end if;
when others => null;
end case;
end process;
process(cnt,fvalue1,fvalue2,fvalue3,fvalue4,fvalue5,fvalue6,fvalue7,fvalue8,over)
begin
g <= '0';
if over='1' then
g <= '1';
else
if fvalue8="0000" and fvalue7="0000" then
gear <= "00";
elsif fvalue8="0000" then
gear <= "01";
else
gear <= "11";
end if;
end if;
end process;
end display_arc;
仿真结果:
第一档结果如图二-12:
图 二12
第二档结果如图二-13:
图 二13
第三档结果如图二-14:
图 二14
结果分析:
在不同档位时,数码管显示的是来自不同输入的数据,第一档显示1-6位,第二档显示2-7位,第三档显示3-8位,并且小数点也虽则档位的不同而改变位置。
三、 设计实现
1. 顶层设计
2. 管脚分配
NET "dp" LOC = C11;
NET "fin" LOC = T8;
NET "g" LOC = D7;
NET "led[0]" LOC = B14;
NET "led[1]" LOC = A13;
NET "led[2]" LOC = C13;
NET "led[3]" LOC = C12;
NET "led[4]" LOC = A12;
NET "led[5]" LOC = B12;
NET "led[6]" LOC = A11;
NET "sel[0]" LOC = F8;
NET "sel[1]" LOC = D8;
NET "sel[2]" LOC = E7;
NET "csignal" CLOCK_DEDICATED_ROUTE = FALSE;
# PlanAhead Generated physical constraints
NET "csignal" LOC = C16;
3. 下载过程
全部仿真通过后,就运行ISE的设计实现,然后再打开XILINX PACE,在里面分配引脚,即实现设计的输入输出端口与实际芯片的输入输出端口的对应连接。比如七段LED管的控制信号就连接到实际电路的七个引脚。需要注意的是一些端口是固定的,不能胡乱的连接。比如时基信号即石英振荡器所提供的信号就只能由T8输入。同时还要考虑内部的可配制逻辑块CLB的数量是否够满足程序的综合要求。一切都准备就绪后就可以运行Configure Device,选择要下载的位文件(.bit)便可开始下载了。
四、 测试结果及结论
测试结果:
在成功下载并运行后,为评估该设计系统的实际测量效果,做了一次对比实验,选用频率可调的函数发生器,同时用示波器做同步的跟踪。经过试验验证,测得的数据很精确,跟函数发生器以及示波器的显示全吻合。最低频率可以测到10Hz,不过要求输入信号很稳定且为方波,因为芯片输入端口自带的整形电路能力毕竟有限。结果表明该设计的确能测量到100MHz,测量结果表明该设计达到了最初的提出的所有设计要求。
实验结论:
本实验主要是利用VHDL语言完成基于FPGA的数字频率计的设计与实现。详细介绍了测量原理,设计方案以及各模块的设计过程及其实现的功能,并对设计中遇到的问题作了分析和处理;利用ISE和ModelSim对设计进行了仿真,分析,综合,并最终下载到FPGA芯片中,实现了对频率的测量。
传统数字频率计由于在高频段受基准时钟频率的限制,其测频精度受到很大的限制.本设计应用EDA技术,很好的解决了这一问题.在设计完成后,为评估系统的实际测量效果,做了一次对比实验,测量结果表明测量精度基本能达到,可满足一般测量精度的要求。但当被测信号频率较低时,测试精度较低,误差变大。究其原因,除了数字测量本身的正负误差和标准信号引起的误差外,还发现低频信号的上升沿和下降沿的变化较缓慢,影响了计数器的计数值,造成了测量精度的下降。
通过改进频率计的控制模块,使信号的输出变化更加迅速,优化了频率计的性能。
在实验过程中,学习到了许多有用的知识,特别是VHDL语言的应用和程序的仿真方法。
五、 参考资料
[1]陈学英,李颖,《FPGA应用实验教程》,国防工业出版社;
[2]谭会生,张昌凡,《EDA技术及应用》,西安电子科技大学出版社。
22 / 22
展开阅读全文