【文章內容簡介】
/輸出 Pin 4 ~Pin11 適配器上側 Pin 4 ~Pin11 8個 I/O 可編程輸入 /輸出 CLK1 適配器左上方 83 CLK1 全 局 時鐘 輸入 Clk2 2 CLk2 全 局 時鐘 輸入 電子科技大學成都學院 12 CLRn 1 Reset 全 局 清零 輸入 OE1n 84 OE 全 局 使能 輸入 注: Altera 公司的 FLEX10K10 適配器與上述相似 其中 CLRn=3, OE=83, CLK1=43, CLK0=1 在最終設計編譯后,確定此次設計使用 EMP7128S 芯片是可行的。如圖 211 圖 212 EPM7128S 芯片的編譯報告 第 3 章 軟件設計 13 第 3章 軟件設計 分頻器的設計 概述 分頻器是數字電路中最常用的電路之一,在 FPGA 的設計 中也是使用效率非常高的基本設計?;?FPGA 實現的分頻電路一般有兩種方法:一是使用FPGA 芯片內部提供的鎖相環(huán)電路,如 ALTERA 提供的 PLL( Phase Locked Loop), Xilinx 提供的 DLL( Delay Locked Loop);二是使用硬件描述語言,如VHDL、 Verilog HDL 等。使用鎖相環(huán)電路有許多優(yōu)點,如可以實現倍頻;相位偏移;占空比可調等。但 FPGA 提供的鎖相環(huán)個數極為有限,不能滿足使用要求。因此使用硬件描述語言實現分頻電路經常使用在數字電路設計中,消耗不多的邏輯單 元就可以實現對時鐘的操作,具有成本低、可編程等優(yōu)點。 計數器 計數器是實現分頻電路的基礎,計數器有普通計數器和約翰遜計數器兩種。這兩種計數器均可應用在分頻電路中。最普通的計數器是加法(或減法)計數器。下面是加法計數器的 VHDL 實現: library ieee。 use 。 use 。 use 。 entity ripple is generic (width: integer := 4)。 port(clk, rst: in std_logic。 t: out std_logic_vector(width 1 downto 0))。 end ripple。 architecture a of ripple is signal tQ: std_logic_vector(width 1 downto 0)。 電子科技大學成都學院 14 begin process(clk, rst) begin if (rst = 39。139。) then tQ = (others = 39。039。)。 elsif (clk39。event and clk = 39。139。) then tQ = tQ + 1。 end if。 end process。 t = tQ。 end a。 在同一時刻,加法計數器的輸出可能有多位發(fā)生變化,因此,當使用組合邏輯對輸出進行譯碼時,會導致尖峰脈沖信號。使用約翰遜計數器可以避免這個問題。 約翰遜計數器 約翰遜計數器是一種移位計數器,采用的是把輸出的最高位取非,然后反饋送到最低位觸發(fā)器的輸入端。約翰遜計數器在每個時鐘下只有一個輸出發(fā)生變化。下面是約翰遜計數器的 VHDL 實現代碼。 file Name: Description: 帶復位功能的約翰遜計數器 library ieee。 use 。 use 。 use 。 entity johnson is generic (width: integer := 4)。 第 3 章 軟件設計 15 port (clk, rst: in std_logic。 t: out std_logic_vector(width 1 downto 0))。 end johnson。 architecture a of johnson is signal tQ: std_logic_vector(width 1 downto 0)。 begin process(clk, rst) begin if(rst = 39。139。) then tQ = (others = 39。039。)。 elsif (rising_edge(clk)) then tQ(width 1 downto 1) = tQ(width 2 downto 0)。 tQ(0) = not tQ(width 1)。 end if。 end process。 t = tQ。 end a。 顯然,約翰遜計數器沒有有效利用寄存器的所有狀態(tài),假設最初值或復位狀態(tài)為此 0000,則依次為 0000、 000 001 011 111 11 1100、 1000、0000 如循環(huán)。再者,如果由于干擾噪聲引入一個無效狀態(tài),如 0010,則無法恢復到有效到循環(huán)中去,需要我們加入錯誤恢復處理,在此不再贅述。 分頻器 如前所述,分頻器的基礎是計數器,設計分頻器的關鍵在于輸出電平翻轉的時機。下面使用加法計數器分別描述各種分頻器的實現。 偶數分頻最易于實現,欲實現占空比為 50%的偶數 N 分頻,一 般來說有兩種方案:一是當計數器計數到,當計數器計數到 N/21 時,將輸出電平進行一次翻轉,同時給計數器一個復位信號,如此循環(huán)下去;二是當計數器輸出為 0 到電子科技大學成都學院 16 N/21 時,時鐘輸出為 0 或 1,計數器輸出為 N/2 到 N1 時,時鐘輸出為 1 或0N1 時,復位計數器,如此循環(huán)下去。需要說明的是,第一種方案僅僅能實現占空比為 50%的分頻器,第二種方案可以有限度的調整占空比,參考非 50%占空比的奇數分頻實現。 在本文中,使用第一種方案實現分頻。 用下面 VHDL 代碼實現占空比為 50%的分頻: 6 分頻 library ieee。 use 。 use 。 use 。 entity clk_div1 is port(clk_in: in std_logic。 clk_out: out std_logic)。 end entity clk_div1。 architecture a of clk_div1 is signal clk_outQ: std_logic :=39。039。賦初始值僅供仿真使用 signal countQ: std_logic_vector(2 downto 0) := 000。 begin process(clk_in) begin if(clk_in’event and clk_in=’1’) then if(countQ/=2) then countQ= countQ+1。 else clk_outQ = not clk_outQ。 第 3 章 軟件設計 17 countQ = (others =’0’)。 end if。 end if。 end process。 clk_out = clk_outQ。 end architecture a。 仿真圖如下: 基于分頻器的電子琴設計 概述 電子琴基本模塊的核心內容是分頻器。 其中 有兩個分頻器,一個是基頻分頻計數器,將時鐘信號分頻至較小的頻率 ,便于二次分頻 ;另一個是音階分頻計數器,由基頻分頻產生各個音階。 流程如圖 32 。 音階分頻器的敏感參數是可以是時鐘信號或基頻分頻出的信號。兩次分頻的嵌套疊加產生合適的音階頻率,驅動蜂鳴器發(fā)聲,實現電子琴的基本部分 。 音階分頻器還具有檢驗琴鍵輸入信號的作用,以便能依據琴鍵信號做出正確的響應。 音階分頻器還具有控制數碼管顯示與琴鍵相應數值,和當高音“多”時驅動彩燈發(fā)光指示的能力。 圖 31 50%占空比 6 分頻仿真圖 電子科技大學成都學院 18 自頂向下電子琴設計探討 自頂向下設計電子琴可分為自動 手動 演奏 選擇 ,基頻分頻,和音階分頻 發(fā)聲顯示 三部分。 a u t ocl ki n d e x 2 [ 7 . . 0 ]i n d e x 0 [ 7 . . 0 ]cl kr stcl k _ d i v 5 [ 3 . . 0 ]i n d e x [ 7 . . 0 ]h i g h 1o u t _ b i tl e d 7 [ 6 . . 0 ]cl kr stcl k _ d i v [ 3 . . 0 ]a u t oh i g h 1o u t _ b i tke y i n [ 7 . . 0 ]l e d 7 [ 6 . . 0 ]f re s p e : U 2cl k1rs t 1a u t o 1 : U 1f re : U 3圖 33 電子琴 RTL 電路圖 rst 是否為 1 進入 /清零 琴鍵輸入 基頻分頻 12MHz 時鐘信號 音階分頻 顯示,發(fā)聲 圖 32 流程圖 第 3 章 軟件設計 19 自動手動演奏選擇模塊 自動手動演奏選擇模塊是個控制開關??刂瓢l(fā)聲部分是否按自動演奏或者手動演奏發(fā)聲。 自動 手動 演奏 選擇模塊 主要 VHDL 代碼 如下 : entity auto1 is port ( clk: in std_logic。 auto: in std_logic。 q : buffer std_logic。 index2: in std_logic_vector(7 downto 0)。 index0: out std_logic_vector(7 downto 0))。 end auto1。 architecture beh of auto1 is CONSTANT duo : std_logic_vector(7 DOWNTO 0) := 11111110。 CONSTANT lai : std_logic_vector(7 DOWNTO 0) := 11111101。 CONSTANT mi : std_logic_vector(7 DOWNTO 0) := 11111011。 CONSTANT fa : std_logic_vector(7 DOWNTO 0) := 11110111。 CONSTANT suo : std_logic_vector(7 DOWNTO 0) := 11101111。 CONSTANT la : std_logic_vector(7 DOWNTO 0) := 11011111。 CONSTANT xi : std_logic_vector(7 DOWNTO 0) := 10111111。 CONSTANT duo1 : std_logic_vector(7 DOWNTO 0) := 01111111。 signal count0: integer range 0 to 7。 begin pulse0:process(clk,auto) variable count: integer range 0 to 8。 begin if auto=39。139。 then 電子科技大學成都學院 20 count:=0。q=39。039。 elsif(clk39。event and clk=39。139。) then count:=count+1。 if count=4 then q=39。139。 elsif count=8 then q=39。039。count:=0。 end if。 end if。 end process。 music:process(q) begin if (q39。event and q=39。139。) then if (count0=7) then count0=0。 else count0=count0+1。 end if。 end if。 end process。 1:process(count0,auto,index2) begin if auto=39。039。 then case count0 is when 0=index0=duo。 when 1=index0=xi。 第 3 章 軟件設計 21 ?? when others=null。 end case。 else index0=index2。 end if。 end proce