使用VHDL进行分频器设计作者:ChongyangLee摘要使用VHDL进行分频器设计作者:ChongyangLee本文使用实例描述了在FPGA/CPLD上使用VHDL进行分频器设计,包括偶数分频、非50%占空比和50%占空比的奇数分频、半整数(N+0.5)分频、小数分频、分数分频以及积分分频。所有实现均可通过SynplifyPro或FPGA生产厂商的综合器进行综合,形成可使用的电路,并在ModelSim上进行验证。目录概述.......................................................................................................................................1计数器..................................................................................................................................1普通计数器..................................................................................................................1约翰逊计数器.............................................................................................................3分频器..................................................................................................................................4偶数分频器..................................................................................................................4奇数分频器..................................................................................................................6半整数分频器.............................................................................................................9小数分频器................................................................................................................11分数分频器................................................................................................................15积分分频器................................................................................................................18概述分频器是数字电路中最常用的电路之一,在FPGA的设计中也是使用效率非常高的基本设计。基于FPGA实现的分频电路一般有两种方法:一是使用FPGA芯片内部提供的锁相环电路,如ALTERA提供的PLL(PhaseLockedLoop),Xilinx提供的DLL(DelayLockedLoop);二是使用硬件描述语言,如VHDL、VerilogHDL等。使用锁相环电路有许多优点,如可以实现倍频;相位偏移;占空比可调等。但FPGA提供的锁相环个数极为有限,不能满足使用要求。因此使用硬件描述语言实现分频电路经常使用在数字电路设计中,消耗不多的逻辑单元就可以实现对时钟的操作,具有成本低、可编程等优点。计数器计数器是实现分频电路的基础,计数器有普通计数器和约翰逊计数器两种。这两种计数器均可应用在分频电路中。普通计数器最普通的计数器是加法(或减法)计数器。下面是加法计数器的VHDL实现,其SynplifyPro下的RTLView如图1所示。--fileName:ripple.vhd--Description:带复位功能的加法计数器libraryieee;useieee.std_logic_1164.all;useieee.std_logic_arith.all;useieee.std_logic_unsigned.all;entityrippleisgeneric(width:integer:=4);port(clk,rst:instd_logic;cnt:outstd_logic_vector(width-1downto0));endripple;architectureaofrippleissignalcntQ:std_logic_vector(width-1downto0);beginprocess(clk,rst)beginif(rst='1')thencntQ=(others='0');elsif(clk'eventandclk='1')thencntQ=cntQ+1;1endif;endprocess;cnt=cntQ;enda;代码1加法计数器VHDL代码图1加法计数器RTL视图加法计数器的TestBench代码如下所示,在ModelSim下进行功能仿真,仿真波形结果如图2所示。libraryieee;useieee.std_logic_1164.all;useieee.std_logic_arith.all;useieee.std_logic_unsigned.all;entityripple_tbisendripple_tb;architecturetestbenchofripple_tbiscomponentripplegeneric(width:integer:=4);port(clk,rst:instd_logic;cnt:outstd_logic_vector(width-1downto0));endcomponent;signalclk_tb:std_logic:='0';signalrst_tb:std_logic:='0';signalcnt_tb:std_logic_vector(3downto0);beginUUT:ripplegenericmap(width=4)portmap(clk=clk_tb,rst=rst_tb,cnt=cnt_tb);clk_tb=notclk_tbafter50ns;processbeginrst_tb=transport'1';waitfor200ns;2rst_tb=transport'0';waitfor2000ns;endprocess;endtestbench;代码2加法计数器的testbench代码图2加法计数器的仿真结果波形在同一时刻,加法计数器的输出可能有多位发生变化,因此,当使用组合逻辑对输出进行译码时,会导致尖峰脉冲信号。使用约翰逊计数器可以避免这个问题。约翰逊计数器约翰逊计数器是一种移位计数器,采用的是把输出的最高位取非,然后反馈送到最低位触发器的输入端。约翰逊计数器在每个时钟下只有一个输出发生变化。下面是约翰逊计数器的VHDL实现代码。--fileName:ripple.vhd--Description:带复位功能的约翰逊计数器libraryieee;useieee.std_logic_1164.all;useieee.std_logic_arith.all;useieee.std_logic_unsigned.all;entityjohnsonisgeneric(width:integer:=4);port(clk,rst:instd_logic;cnt:outstd_logic_vector(width-1downto0));endjohnson;architectureaofjohnsonissignalcntQ:std_logic_vector(width-1downto0);beginprocess(clk,rst)beginif(rst='1')thencntQ=(others='0');elsif(rising_edge(clk))thencntQ(width-1downto1)=cntQ(width-2downto0);cntQ(0)=notcntQ(width-1);endif;endprocess;3cnt=cntQ;enda;代码3约翰逊计数器VHDL代码图3约翰逊计数器RTL视图显然,约翰逊计数器没有有效利用寄存器的所有状态,假设最初值或复位状态为此分频器器的关键在于输出电平翻转的时机。下面使用加法计数器分别描述各种分频器的实现。偶数分频器频最易于实现,欲实现占空比为50%的偶数N分频,一般来说有两种方案:一是当计数器计数到,当计数器计数到在如下所示的以6分频为例的VHDL代码中,architecturea使用的是第一种方案,--filenameclk_div1.vhd0000,则依次为0000、0001、0011、0111、1111、1110、1100、1000、0000如循环。再者,如果由于干扰噪声引入一个无效状态,如0010,则无法恢复到有效到循环中去,需要我们加入错误恢复处理,在此不再赘述。如前所述,分频器的基础是计数器,设计分频偶数分N/2-1时,将输出电平进行一次翻转,同时给计数器一个复位信号,如此循环下去;二是当计数器输出为0到N/2-1时,时钟输出为0或1,计数器输出为N/2到N-1时,时钟输出为1或0N-1时,复位计数器,如此循环下去。需要说明的是,第一种方案仅仅能实现占空比为50%的分频器,第二种方案可以有限度的调整占空比,参考非50%占空比的奇数分频实现。architectureb使用的是第二种方案。更改configuration可查看不同方案的综合结果。4--description:占空比为50%的6分频libraryieee;useieee.std_logic_1164.all;;d_logic;clk_out:outstd_logic);ofclk_div1is'0';--赋初始值仅供仿真使用tandclk_in='1')then_outQ;种方案ofclk_div1isor(2downto0);andclk_in='1')thenthenuseieee.std_logic_arith.all;useieee.std_logic_unsigned.alltityclk_div1isenport(clk_in:instendclk_div1;使用第一种方案--architectureasignalclk_outQ:std_logic:=signalcountQ:std_logic_vector(2downto0):=000;beginess(clk_in)procbegink_in'evenif(clif(countQ/=2)then;CountQ=CountQ+1elseoutQ=notclk_outQ;clk_CountQ=(others='0');endif;endif;;endprocessclk_out=clkenda;使用第二--architecturebs