轉(zhuǎn)載自:http://blog.sina.com.cn/s/blog_4dbde8ed0100v54x.html
在接口電路中,時(shí)鐘信號(hào)的作用至關(guān)重要。一般FPGA的外部時(shí)鐘信號(hào)可達(dá)幾十MHz,但由于一些接口電路的特性所致,這樣高頻率的時(shí)鐘不適合電路工作,所以應(yīng)該引入時(shí)鐘分頻電路,產(chǎn)生頻率適合接口電路工作的時(shí)鐘信號(hào),這樣才能便于接口電路工作
一、內(nèi)容說明
在數(shù)字邏輯電路設(shè)計(jì)中,分頻器是一種基本電路,通常用來對(duì)某個(gè)給定頻率進(jìn)行分頻,得到所需的頻率。整數(shù)分頻器的實(shí)現(xiàn)非常簡(jiǎn)單,可采用標(biāo)準(zhǔn)的計(jì)數(shù)器,也可以采用可編程邏輯器件設(shè)計(jì)實(shí)現(xiàn),但在某些場(chǎng)合下,時(shí)鐘源與所需的頻率不成整數(shù)倍關(guān)系,此時(shí)可采用小數(shù)分頻器進(jìn)行分頻。比如:分頻系數(shù)為2.5、3.5、7.5等半整數(shù)分頻器。
所以對(duì)于基于FPGA的時(shí)鐘分頻,可以簡(jiǎn)單分為奇數(shù)分頻與偶數(shù)分頻,而且分頻后時(shí)鐘的占空比也是可變的,最簡(jiǎn)單的時(shí)鐘分頻就是對(duì)時(shí)鐘進(jìn)行奇數(shù),然后輸出時(shí)鐘信號(hào)等于計(jì)數(shù)各位相與,這樣得到的分頻信號(hào),其占空比很小,即時(shí)鐘高電平只有一個(gè)外部時(shí)鐘周期,但由于FPGA設(shè)計(jì)的對(duì)時(shí)鐘跳變沿的判斷的精確性,故這種分頻方式也是可取的。本文章說明了如何產(chǎn)生P占空比的時(shí)鐘信號(hào)的方法。
二、硬件電路分析
1.半整數(shù)分頻器
分頻系數(shù)為N=0.5整數(shù)倍的分頻器電路可由一個(gè)異或門、一個(gè)模N計(jì)數(shù)器和一個(gè)2分頻器組成。在實(shí)現(xiàn)時(shí),模N計(jì)數(shù)器可設(shè)計(jì)成帶預(yù)置的計(jì)數(shù)器,這樣可以實(shí)現(xiàn)任意分頻系數(shù)為N=0.5整數(shù)倍的分頻器,圖1給出了通用半整數(shù)分頻器的電路組成。
基于圖1的電路,可以采用VHDL硬件描述語言,先實(shí)現(xiàn)任意模N的計(jì)數(shù)器,并可產(chǎn)生模N邏輯電路。然后,用原理圖輸入方式將模N邏輯電路、異或門和D觸發(fā)器連接起來,便可實(shí)現(xiàn)半整數(shù)(N-0.5)分頻器及2N-1的分頻,在通用半整數(shù)分頻器中,占空比是固定的。
圖1 通用的半整數(shù)分頻器電路圖
2.偶數(shù)與奇數(shù)分頻器
圖2為N位數(shù)字分頻器的設(shè)計(jì)結(jié)構(gòu)圖。
在圖中,分頻輸入信號(hào)和位分頻系數(shù)同時(shí)輸入到偶數(shù)倍分頻器和奇數(shù)倍分頻器中。當(dāng)分頻系數(shù)為偶數(shù)時(shí),偶數(shù)倍分頻器工作,其輸出為分頻后的信號(hào),而奇數(shù)倍分頻器不工作,其輸出為0;而當(dāng)分頻系數(shù)為奇數(shù)時(shí),奇數(shù)倍分頻器工作,其輸出為分頻后的信號(hào),而偶數(shù)倍分頻器不工作,其輸出為0.最后兩個(gè)分頻器出來的信號(hào)通過一個(gè)或門進(jìn)行或運(yùn)算而得到了最終的分頻輸出信號(hào),這樣即完成了對(duì)分頻輸入信號(hào)的N位數(shù)字分頻。

圖2 N(偶數(shù)或奇數(shù))分頻器
三、程序設(shè)計(jì)與仿真
1.VHDL程序
1) 偶數(shù)分頻
對(duì)時(shí)鐘進(jìn)行偶數(shù)分頻,使占空比達(dá)到P很簡(jiǎn)單,只要使用一個(gè)計(jì)數(shù)器,在計(jì)數(shù)器的前一半時(shí)間里,使輸出電平為高電平,在計(jì)數(shù)的后一半時(shí)間里使輸出的電平為低電平,這樣分頻出來的時(shí)鐘信號(hào)就是占空比為P的時(shí)鐘信號(hào)。
偶數(shù)分頻的VHDL程序代碼與注釋如下:
--evev frequency division
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity fredivn is
GENERIC(N:integer:=8);- -8分頻,偶數(shù)分頻
port (clk:in std_logic;
outclk:out std_logic);
end fredivn;
architecture rtl of fredivn is
signal count:integer;
begin
process(clk)
begin
if(clk'event and clk='1') then
if(count=N-1)then- - 計(jì)數(shù)周期
count<=0;
else
count<=count+1;
if count<(integer(N/2))then- -產(chǎn)生分頻脈沖,占空比達(dá)到50%
outclk<='0';
else
outclk<='1';
end if;
end if;
end if;
end process;
end rtl;
該程序的技術(shù)要點(diǎn)只要有兩點(diǎn)。第一點(diǎn)是內(nèi)部計(jì)數(shù)信號(hào)count的賦值語句,程序中主要通過if語句來實(shí)現(xiàn)。該語句實(shí)現(xiàn)的功能是:當(dāng)count小于N/2時(shí),輸出低電平,當(dāng)count大于N/2時(shí),輸出高電平,因?yàn)镹是偶數(shù),所以占空比是P,并且count循環(huán)計(jì)數(shù)。
if count<(integer(N/2))then- -產(chǎn)生分頻脈沖,占空比達(dá)到50%
outclk<='0';
else
outclk<='1';
end if;
end if;
程序的另一個(gè)技術(shù)要點(diǎn)是使用了generic語句,在entity的定義語句中有:
GENERIC (N:integer:=8);
這個(gè)語句定義了分頻數(shù)N,并且由于運(yùn)用了generic語句,故在其他程序調(diào)用的時(shí)候,可以任意更改分頻數(shù),使得對(duì)此模塊的調(diào)用非常方便。
2) 奇數(shù)分頻
奇數(shù)分頻相對(duì)于偶數(shù)分頻來說,如果不要求占空比的話,難度是一樣的,但是如果要使占空比為50%,則計(jì)數(shù)分頻比偶數(shù)分頻要復(fù)雜一些。
奇數(shù)分頻與偶數(shù)分頻思路是一樣的,都是使輸出信號(hào)在前一半計(jì)數(shù)時(shí)間里為低電平,在后一半計(jì)數(shù)時(shí)間里為高電平。如果要求占空比為50%,則 要使用一些技巧??梢韵葘?duì)輸入時(shí)鐘的上升沿進(jìn)行計(jì)數(shù),然后讓一個(gè)內(nèi)部信號(hào)在前一半時(shí)間里為低電平,后一半時(shí)間里為高電平。同時(shí)對(duì)輸入時(shí)鐘的下降沿進(jìn)行計(jì)數(shù),讓另一個(gè)內(nèi)部信號(hào)在前一半時(shí)間里為高電平,后一半時(shí)間里為低電平。然后讓兩個(gè)內(nèi)部信號(hào)相與,得到了半個(gè)時(shí)鐘周期的一個(gè)高電平,再讓信號(hào)與第一個(gè)內(nèi)部信號(hào)相或,就得到了占空比為50%的輸出時(shí)鐘。
奇數(shù)分頻的VHDL程序代碼如下:
--odd frequency division
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity fredivn1 is
GENERIC(N:integer:=7);//奇分頻數(shù)
port (clk:in std_logic;
outclk:out std_logic);
end fredivn1;
architecture rtl of fredivn1 is
signal count1,count2:integer;
signal q,outclk1,outclk2:std_logic;
begin
q<=outclk1 and outclk2;
outclk<=q xor outclk1;
process(clk)//上升沿進(jìn)行計(jì)數(shù)
begin
if(clk'event and clk='1') then
if(count1=N-1)then
count1<=0;
else
count1<=count1+1;
if count1<(integer(N/2))then//產(chǎn)生分頻脈沖1
outclk1<='0';
else
outclk1<='1';
end if;
end if;
end if;
end process;
process(clk)//下降沿進(jìn)行計(jì)數(shù)
begin
if(clk'event and clk='0') then
if(count2=N-1)then
count2<=0;
else
count2<=count2+1;
if count2<(integer(N/2))then//產(chǎn)生分頻脈沖2
outclk2<='1';
else
outclk2<='0';
end if;
end if;
end if;
endprocess;
end rtl;
以上程序的技術(shù)要點(diǎn)就是如何保證占空比為50%。在此程序中用到了兩個(gè)進(jìn)程process,第一個(gè)進(jìn)程是對(duì)上升沿進(jìn)行計(jì)數(shù),然后讓outclk1在計(jì)數(shù)的前一半時(shí)間里為低電平,在計(jì)數(shù)的后一半時(shí)間為高電平。第二個(gè)進(jìn)程對(duì)下降沿計(jì)數(shù),在計(jì)數(shù)的前一半時(shí)間里讓outclk2為高電平,在計(jì)數(shù)的后一半時(shí)間里讓outclk2為低電平,這樣outclk1與outclk2就有了半個(gè)時(shí)鐘周期的時(shí)間上重合的高電平,讓outclk1與outclk2相與,結(jié)果賦給q,q就是一個(gè)只有半個(gè)時(shí)鐘周期是高電平,其余時(shí)間都是低電平的信號(hào),最后讓q與outclk1相或,得到的波形正好是占空比為50%的分頻時(shí)鐘波形。
在實(shí)體的定義部分都用到了generic語句,用這個(gè)語句,可以使程序的一些參數(shù)在其他模塊調(diào)用時(shí)直接修改即可,這使得模塊的重復(fù)利用非常方便。
3) 對(duì)分頻器的調(diào)用
其中任意偶數(shù)N的分頻器的VHDL描述如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity fredivn is
GENERIC(N:integer);
port (clk:instd_logic;- -分頻后脈沖
outclk:out std_logic);
end fredivn;
architecture behav of fredivn is
signal count:integer;
begin
process(clk)
begin
if(clk'event and clk='1')then --將CLK信號(hào)N分頻
if(count=N-1)then
count<=0;
else
count<=count+1;
if count<(integer(N/2))then- -產(chǎn)生分頻后時(shí)鐘
outclk<='0';
else
outclk<='1';
end if;
end if;
end if;
end process;
end behav;
以上例子是一個(gè)分頻器的例子,可以對(duì)輸入時(shí)鐘進(jìn)行N分頻,注意在實(shí)體聲明中,generic語句中的參數(shù)N是分頻參數(shù),把頻率分為幾分之一就由這個(gè)參數(shù)決定。在其他對(duì)這個(gè)模塊進(jìn)行調(diào)用的程序中,只要把N賦予不同的參數(shù)值,就可以實(shí)現(xiàn)不同的分頻,下面是對(duì)fredivn進(jìn)行調(diào)用的例子。
package test_con is
constantN1:integer:=16;//16分頻
end test_con;
use work.test_con.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity frediv16 is
port(clkin :in std_logic;
clkout:out std_logic);
end frediv16;
architecture behav of frediv16 is
componentfredivn//調(diào)用分頻函數(shù)
generic(N:positive);
port (clk:in std_logic;
outclk:out std_logic);
END component;
begin
u1:fredivn//匹配端口、參數(shù)
generic map(N=>N1)
port map(clkin,clkout);
end behav;
如果在該例子中給N賦值16,就實(shí)現(xiàn)了一個(gè)16分頻的分頻器。可以看到,通過generic語句可以實(shí)現(xiàn)同一模塊的不同調(diào)用,非常方便。
4) 數(shù)控分頻器
數(shù)控分頻器的功能就是當(dāng)在輸入端給定不同輸入數(shù)據(jù)時(shí),將對(duì)輸入的時(shí)鐘信號(hào)有不同的分頻比。以下的數(shù)控分頻器就是用計(jì)數(shù)值可并行預(yù)置的加法計(jì)數(shù)器設(shè)計(jì)完成,方法是將計(jì)數(shù)溢出位與預(yù)置數(shù)加載輸入信號(hào)相接即可,其中D為8位預(yù)置數(shù),CLK是Clock輸入時(shí)鐘,輸出為FOUT。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY PULSE IS
PORT (CLK : IN STD_LOGIC;
D : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
FOUT : OUT STD_LOGIC );
END PULSE;
ARCHITECTURE beh OF PULSE IS
SIGNAL FULL :STD_LOGIC;
BEGIN
P_REG: PROCESS(CLK)
VARIABLE CNT8 : STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
IF CNT8 = "11111111"THEN
CNT8 :=D;--當(dāng)CNT8計(jì)數(shù)計(jì)滿時(shí),輸入數(shù)據(jù)D被同步預(yù)置給計(jì)數(shù)器CNT8
FULL <='1';--同時(shí)使溢出標(biāo)志信號(hào)FULL輸出為高電平
ELSE CNT8 := CNT8+ 1; --否則繼續(xù)作加1計(jì)數(shù)
FULL<='0';--且輸出溢出標(biāo)志信號(hào)FULL為低電平
END IF;
END IF;
END PROCESS P_REG ;
P_DIV: PROCESS(FULL)
VARIABLE CNT2 : STD_LOGIC;
BEGIN
IF FULL'EVENT AND FULL = '1'
THEN CNT2 := NOTCNT2;--如果溢出標(biāo)志信號(hào)FULL為高電平,D觸發(fā)器輸出取反
IF CNT2 = '1' THEN
FOUT <= '1';
ELSE
FOUT <= '0';
END IF;
END IF;
END PROCESS P_DIV ;
END beh;
2.時(shí)序仿真
1) 偶數(shù)分頻
偶數(shù)分頻程序中端口參數(shù)N是分頻數(shù),由它來決定多少分頻。在程序中預(yù)置該參數(shù)為8,即8分頻,該程序的仿真波形如圖3所示。
2) 奇數(shù)分頻
該程序的仿真波形如圖4(a)所示,在圖中可以看到最后的分頻輸出信號(hào)周期為70ns,正好頻率是分頻輸入信號(hào)的1/7,且其占空比為50%,由此驗(yàn)證了所設(shè)計(jì)電路的正確性。如果改變不同的奇數(shù)N的值,還可以得到不同的仿真波形圖4(b)。
3) 數(shù)控分頻器
4)輸入不同的CLK時(shí)鐘頻率和預(yù)置值D,得到的仿真波形圖如圖5所示。該模塊還能滿足其他預(yù)置值分頻的設(shè)計(jì)要求,并可以被上一級(jí)模塊調(diào)用。
四、總結(jié)
分頻器是一種基本數(shù)字電路,通常包括偶數(shù)分頻及奇數(shù)分頻兩種方式。本章分別討論了分頻系數(shù)為偶數(shù)或奇數(shù)時(shí),且占空比為50%的分頻器的設(shè)計(jì)方法。在設(shè)計(jì)中分頻器滿足N值范圍為2~2的7次方,這種電路在頻率合成及各類數(shù)字邏輯電路中有廣泛的應(yīng)用。
愛華網(wǎng)



