第一篇:基于VHDL編程FPGA的地鐵自動售票機(jī)
地鐵自動售票機(jī)
一、設(shè)計(jì)要求
1、功能描述
用于模仿地鐵售票自動售票,完成地鐵售票的核心控制功能。
2、功能要求
售票機(jī)有兩個(gè)進(jìn)幣孔,一個(gè)是輸入硬幣,識別的范圍是一元硬幣;一個(gè)是紙幣,識別的范圍是一元、兩元、五元、十元、二十元。乘客可以連續(xù)多次投入錢幣。乘客 一次只能選擇一個(gè)出站口,購買車票時(shí),乘客先選出站口,有六個(gè)出站口可供選擇,再選擇所需的票數(shù),然后投幣,投入的錢幣達(dá)到或者超過所需金額時(shí),售票機(jī)自 動出票,并找零。本次交易結(jié)束后,等待下一次交易。在選擇出站口、所需票數(shù)以及在投幣期間,乘客可以按取消鍵取消操作,錢幣自動退出。
二、實(shí)驗(yàn)分析
1、買票時(shí),乘客按下開始鍵,售票機(jī)進(jìn)入站臺選擇程序,乘客選擇出站口后,可以按取消鍵重新選擇,否則售票機(jī)自動進(jìn)入票數(shù)選擇程序,同樣這時(shí)可以按下取消鍵重新開始選擇出站口以及票數(shù)。
2、當(dāng)選擇好出站口以及所需票數(shù)時(shí),乘客可以投硬幣或者用紙幣,當(dāng)所投的錢幣總額大于或者等于票價(jià)時(shí),售票機(jī)自動出票以及找零。期間,可以按下取消鍵重新開始選擇,并退出所有的錢幣。
3、乘客若還沒選擇出站口或者票數(shù),就投幣或者使用紙幣,售票機(jī)會自動退出所有的錢幣。
4、有六個(gè)站臺可供乘客選擇,每個(gè)乘客最多可以買3張票,六個(gè)站臺編號為1到6,票價(jià)從2元依次遞增到7。
三、系統(tǒng)流程圖
四、程序源代碼 LIBRARY IEEE;USE IEEE.std_logic_1164.ALL;USE IEEE.std_logic_arith.ALL;USE IEEE.std_logic_unsigned.ALL;ENTITY metrosell IS PORT(clk:in std_logic;startselect:in std_logic;sure:in std_logic;save your forward step(s)coin1y:in std_logic;pmoney1y:in std_logic;pmoney2y:in std_logic;pmoney5y:in std_logic;pmoney10y:in std_logic;money pmoney20y:in std_logic;money cancel:in std_logic;number:in std_logic_vector(3 downto 0);the tickets platform:in std_logic_vector(3 downto 0);want to reach moneystorage:out std_logic;acceptmo:out std_logic;stamp:out std_logic;--set the clock signal--start to select the platform--this button is to--1 yuan coin
--1 yuan paper money--2 yuan paper money--5 yuan paper money--10 yuan paper--20 yuan paper--cancel the forward step(s)--choose the number of--choose the platform you--to store the money--accept the money--stamp outgate charge:out std_logic_vector(3 downto 0);--the mount of charge,up to 15 yuan chargegate:out std_logic--charge outgate);END metrosell;ARCHITECTURE sell OF metrosell IS type state_type is(initial_type,selectp_type,selectnum_type,insert_type,stamp_type,charge_type);--define six types signal state:state_type;--define a shared state BEGIN main:process(clk,state,startselect,platform,number,coin1y,pmoney1y,pmoney2y,pmoney5y,pmoney10y,pmoney20y,cancel,sure)variable univalence :integer range 0 to 7;--the univalence of the ticket variable total_money :integer range 0 to 21;--the price of the ticket(s)variable selectp_alr:std_logic;--the flag of select platform type variable selectnum_alr:std_logic;--the flag of select number type variable stamp_alr:std_logic;--the flag of the stamp gate variable charge_alr:std_logic;--the flag of the charge gate variable money_reg:integer range 0 to 21;--the mount of money put in variable coin1y_f:std_logic;--the flag of one yuan coin variable pmoney1y_f:std_logic;--the flag of one yuan paper money variable pmoney2y_f:std_logic;--the flag of two yuan paper money variable pmoney10y_f:std_logic;--the flag of ten yuan paper money variable pmoney20y_f:std_logic;--the flag of twelve yuan paper money variable pmoney5y_f:std_logic;--the flag of five yuan paper money variable charge_reg:integer range 0 to 15;
begin if(rising_edge(clk))then case state is when initial_type => variables univalence:=0;selectp_alr:='0';selectnum_alr:='0';stamp_alr:='0';charge_alr:='0';money_reg:=0;total_money:=0;coin1y_f:='0';pmoney1y_f:='0';pmoney2y_f:='0';pmoney5y_f:='0';
--the register of charge--initialize some pmoney10y_f:='0';pmoney20y_f:='0';moneystorage<='0';stamp<='0';charge_reg:=0;charge<=“0000”;acceptmo<='0';chargegate<='0';if(startselect='1')then state<=selectp_type;end if;when selectp_type => if(selectp_alr='0'and cancel='0')then--choose the platform if(platform=“0001”)then univalence:=2;selectp_alr:='1';elsif(platform=“0010”)then univalence:=3;selectp_alr:='1';elsif(platform=“0011”)then univalence:=4;selectp_alr:='1';elsif(platform=“0100”)then univalence:=5;selectp_alr:='1';elsif(platform=“0101”)then univalence:=6;selectp_alr:='1';elsif(platform=“0110”)then univalence:=7;selectp_alr:='1';elsif(platform=“0000”)then univalence:=0;selectp_alr:='0';else null;end if;elsif(selectp_alr='1'and cancel='1')then state<=initial_type;elsif(selectp_alr='1'and sure='1')then state<=selectnum_type;end if;when selectnum_type =>--you can buy at most 3 tickets if(selectnum_alr='0'and cancel='0')then--choose the number of tickets if(number=“0001”)then if(univalence=2)then total_money:=2;selectnum_alr:='1';elsif(univalence=3)then total_money:=3;selectnum_alr:='1';elsif(univalence=4)then total_money:=4;selectnum_alr:='1';elsif(univalence=5)then total_money:=5;selectnum_alr:='1';elsif(univalence=6)then total_money:=6;selectnum_alr:='1';elsif(univalence=7)then total_money:=7;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;
if(number=“0010”)then if(univalence=2)then total_money:=4;selectnum_alr:='1';elsif(univalence=3)then total_money:=6;selectnum_alr:='1';elsif(univalence=4)then total_money:=8;selectnum_alr:='1';elsif(univalence=5)then total_money:=10;selectnum_alr:='1';elsif(univalence=6)then total_money:=12;selectnum_alr:='1';elsif(univalence=7)then total_money:=14;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;if(number=“0011”)then if(univalence=2)then total_money:=6;selectnum_alr:='1';elsif(univalence=3)then total_money:=9;selectnum_alr:='1';elsif(univalence=4)then total_money:=12;selectnum_alr:='1';elsif(univalence=5)then total_money:=15;selectnum_alr:='1';elsif(univalence=6)then total_money:=18;selectnum_alr:='1';elsif(univalence=7)then total_money:=21;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;elsif(selectnum_alr='1'and cancel='1')then state<=initial_type;elsif(selectnum_alr='1'and sure='1')then state<=insert_type;end if;when insert_type => moneystorage<='1';if(money_reg
when 2 => charge<=“0010”;when 3 => charge<=“0011”;when 4 => charge<=“0100”;when 5 => charge<=“0101”;when 6 => charge<=“0110”;when 7 => charge<=“0111”;when 8 => charge<=“1000”;
end case;end if;
when 9 => charge<=“1001”;when 10 => charge<=“1010”;when 11 => charge<=“1011”;when 12 => charge<=“1100”;when 13 => charge<=“1101”;when 14 => charge<=“1110”;when 15 => charge<=“1111”;when others => charge<=“0000”;end case;if(charge_reg>0 and charge_alr='0')then chargegate<='1';charge_alr:='1';elsif(charge_reg=0 and charge_alr='0')then chargegate<='0';charge_alr:='1';else state<=initial_type;end if;end process main;END sell;
五、波形仿真
1、乘客按下開始按鈕,進(jìn)入選站臺模式,選擇二號站臺,按下確定鍵,再選擇票數(shù)為2張,按下確定鍵,售票機(jī)錢箱關(guān)閉,投入一張兩元和五元紙幣(對順序沒有要求),此時(shí)錢幣總額大于票價(jià),出兩張票并找零一元。之后系統(tǒng)進(jìn)入初始化狀態(tài)。具體仿真如圖 1 仿真1
圖 1 仿真1
2、測試cancel鍵,當(dāng)乘客按正確的操作完成選站臺時(shí),按下取消鍵,再重新選擇,如圖 2 cancel仿真,仿真波形如下。
圖 2 cancel仿真
3、還是測試cancel鍵,當(dāng)乘客選擇好票數(shù)時(shí),按下cancel鍵,然后重新選擇兩張單價(jià)為七塊錢的六號站臺票,投入一張20元和5元,找零六元。仿真波形如圖 3 cancel仿真2
圖 3 cancel仿真2
4、乘客選擇五號站臺,兩張票,然后先后投入一元紙幣,兩元紙幣,一元紙幣,五元紙幣,然后按下取消鍵,售票機(jī)自動放出所有的錢幣。仿真如圖 4 cancel仿真3。
圖 4 cancel仿真3
六、心得體會
在我的設(shè)計(jì)中,有一個(gè)moneystorage信號量用于控制儲存錢幣箱的開與關(guān),這個(gè)設(shè)計(jì)主要考慮到當(dāng)乘客要求退幣時(shí),最好不是從售票機(jī)中取出投入的錢數(shù),然后退還,設(shè)置了這個(gè)開關(guān),就可以在按下取消鍵時(shí),直接從儲存錢幣箱中退出錢幣。
還有,乘客選擇的站臺以及票數(shù),在售票機(jī)內(nèi)部會自動將這兩個(gè)信號傳給出票系統(tǒng),從而自動出票,以上寫的程序只是讓系統(tǒng)知道怎樣收錢以及找零。
這次實(shí)驗(yàn)總體上來說比六人搶答器簡單,但是因?yàn)檫@個(gè)售票機(jī)完全是自己寫的,所以也不是想象中的那么簡單。這也讓我看出,要完全自己去做一件東西不是簡單的,特別是要考慮很全面,還是要發(fā)一些時(shí)間的。
第二篇:EDA課程設(shè)計(jì)—自動售票機(jī)
燕 山 大 學(xué)
EDA課程設(shè)計(jì)報(bào)告書
題目:
自動售票機(jī)
姓名: 班級: 學(xué)號:
成績:
(注:此文件應(yīng)以同學(xué)學(xué)號為文件名)
一、設(shè)計(jì)題目及要求 1.設(shè)計(jì)題目:自動售票機(jī) 2.設(shè)計(jì)要求:
⑴、每次投一枚硬幣,但可以連續(xù)投入數(shù)枚硬幣。硬幣種類兩種:1元和5角,各用一個(gè)按鍵表示。
⑵、設(shè)定票價(jià)為2.5元,每次售一張票。購票時(shí)先投入硬幣,當(dāng)投入的硬幣總金額達(dá)到或超過票的面值時(shí),用LED發(fā)出指示,這時(shí)可以按取票鍵取出票。
⑶、如果所投硬幣超過票的面值則會有LED提示找零錢,取完票以后按找零鍵則可以取出零錢。
⑷、用兩位數(shù)碼管顯示已投幣金額,若剛好投幣2.5元,取票后金額歸零;若投幣超過2.5元,取票后顯示找零金額,按下找零鍵后金額再歸零。
1總體設(shè)計(jì)的文字描述,即由哪幾個(gè)部分構(gòu)
二、設(shè)計(jì)過程及內(nèi)容(包括○
2主要模塊比較詳盡的文字描成的,各個(gè)部分的功能及如何實(shí)現(xiàn)方法;○述,并配以必要的圖片加以說明,但圖片數(shù)量無需太多)1.總體結(jié)構(gòu)如下:
總體設(shè)計(jì)思路:此自動售票系統(tǒng)總共有5個(gè)主要模塊,分別是:累加模塊,比較器模塊,找零模塊,數(shù)字轉(zhuǎn)換模塊,顯示器模塊。⑴、累加模塊實(shí)現(xiàn)金額的累加功能。
實(shí)現(xiàn)方法:該模塊設(shè)置3個(gè)輸入口(包括5角、1元、復(fù)位),8個(gè)輸出口(B1—B8)。該模塊將在給五角或一元高電平的同時(shí)實(shí)現(xiàn)金額的累加,復(fù)位則會將會對其進(jìn)行清零。該模塊由一片8位的加法器,2片4位寄存器及簡單門電路組成,利用8位加法器將輸入的金額(5、10)進(jìn)行二進(jìn)制相加(00000101、00001010),通過寄存器后返回到加法器實(shí)現(xiàn)累加功能。復(fù)位鍵則與寄存器復(fù)位清零短CLRN相連,實(shí)現(xiàn)復(fù)位的功能。
⑵、比較器模塊實(shí)現(xiàn)與票價(jià)進(jìn)行比較的功能。
實(shí)現(xiàn)方法:該模塊設(shè)置了8個(gè)輸入口(A0—A7)1個(gè)取票口,4個(gè)輸出口。該模塊 將累加的錢幣與2.5元的票價(jià)比較,如果累加金額高于票價(jià)則黃燈亮,小于票價(jià)則紅燈亮,等于票價(jià)則綠燈亮。給取票輸入端高電平則會出票。該模塊由一片八位比較器及門電路組成,輸入的信號與二進(jìn)制的票價(jià)相比較(00011001)。⑶、找零模塊實(shí)現(xiàn)大于票價(jià)找零錢的功能。
實(shí)現(xiàn)方法:該模塊設(shè)置了2個(gè)輸入口(zhaoling,H),8個(gè)輸出口(E1—E8)。該模塊將在輸入金額大于票價(jià)及出票之后的時(shí)候給予高電平,使在顯示器中顯示5。該模塊由兩個(gè)四位寄存器及少量門電路組成。給zhaoling輸入口高電平,使寄存器工作,之后輸出所找的零錢(二進(jìn)制輸出),通過數(shù)碼管顯示出來。⑷、數(shù)字轉(zhuǎn)換模塊實(shí)現(xiàn)TTL 二進(jìn)制—BCD代碼轉(zhuǎn)換的功能。
實(shí)現(xiàn)方法:該模塊設(shè)置了8個(gè)輸入口(S1—S8),和8個(gè)輸出口(C1—C8)。該模塊由3個(gè)TTL 二進(jìn)制—BCD碼轉(zhuǎn)換器及門電路組成。將需要數(shù)碼管顯示的數(shù)字二進(jìn)制代碼輸入將輸出相應(yīng)的BCD碼。即用4位二進(jìn)制數(shù)來表示1位十進(jìn)制數(shù)中的0~9這10個(gè)數(shù)碼。
⑸、顯示器模塊實(shí)現(xiàn)將在數(shù)碼管上顯示數(shù)字的功能。
實(shí)現(xiàn)方法:該模塊設(shè)置了8個(gè)輸入口(A1—A7)輸入相應(yīng)的BCD碼,7個(gè)輸出口(Y1—Y7)輸出相應(yīng)的使數(shù)碼管亮的代碼及另外3個(gè)輸出口(str1,str2,str3)控制相應(yīng)的數(shù)碼管亮。該模塊由1個(gè)四位二進(jìn)制計(jì)數(shù)器和雙四選一數(shù)據(jù)選擇器和1個(gè)七段譯碼器及相應(yīng)門電路組成。將BCD碼輸入進(jìn)去,通過計(jì)數(shù)器控制雙位四選一數(shù)據(jù)選擇器的輸入端(00或01)。s0—s3通過00控制IC0的輸出,此時(shí)str2 str1 str0通過000來控制第一個(gè)數(shù)碼管亮,s4—s7通過01控制IC1口的輸出,此時(shí)str2 str1 str0通過001來控制第二個(gè)數(shù)碼管亮,將選擇的輸輸入到七段譯碼器中將進(jìn)行譯碼使數(shù)碼管顯示相應(yīng)數(shù)字。2.各個(gè)模塊電路圖及仿真模型 總體電路圖:
超過2.5元即3元時(shí)結(jié)果如下:
當(dāng)正好為2.5元時(shí),結(jié)果如下:
⑴、累加模塊
累加模塊仿真結(jié)果如下: ⑵、比較器模塊
比較器模塊仿真模型:
⑶、找零模塊
找零模塊仿真結(jié)果:
⑷、數(shù)字轉(zhuǎn)換模塊
數(shù)字轉(zhuǎn)換模塊仿真結(jié)果:
⑸、顯示器模塊
顯示器模塊仿真結(jié)果:
三、設(shè)計(jì)結(jié)論(包括設(shè)計(jì)過程中出現(xiàn)的問題;對EDA課程設(shè)計(jì)感想、意 見和建議)
經(jīng)過一周多的課程設(shè)計(jì),我受益匪淺,學(xué)到了團(tuán)隊(duì)合作,提高信息檢索能力的重要性。在這次設(shè)計(jì)中遇到了很多實(shí)際性的問題,在實(shí)際設(shè)計(jì)中才發(fā)現(xiàn),書本上理論性的東西與在實(shí)際運(yùn)用中的還是有一定的出入的,所以有些問題不但要深入地理解,而且要不斷地更正以前的錯誤思維。一切問題必須要靠自己一點(diǎn)一滴的解決,而在解決的過程當(dāng)中你會發(fā)現(xiàn)自己在飛速的提升。在實(shí)驗(yàn)過程中,根據(jù)任務(wù)書的要求,查找資料,設(shè)計(jì)了電路方案,在差額計(jì)算模塊、投幣模塊、選票模塊,有幾種預(yù)想方案,和同組人員仔細(xì)分析后確定了一套簡單實(shí)用的方案。
在課程設(shè)計(jì)過程中,其中最具有代表性的錯誤就是累加模塊。當(dāng)信號輸入時(shí),輸入信號與寄存器儲存信號相加時(shí)出現(xiàn)嚴(yán)重的延時(shí)問題,后來在老師以及同組同學(xué)的努力下,加入了延時(shí)器,解決了這個(gè)問題。還有在試驗(yàn)箱進(jìn)行仿真時(shí),發(fā)現(xiàn)顯示數(shù)字很不準(zhǔn)確,在查閱資料和老師的幫助下,意識到是輸入抖動問題,我們在輸入端口加入了防抖動電路,很好的解決了這個(gè)問題。
在進(jìn)行硬件方面測試的過程中,也遇到了一些問題,在進(jìn)行數(shù)據(jù)累加的過程中,數(shù)據(jù)很不穩(wěn)定,我們在摁鍵處加入了防抖動電路,便解決了這一問題。對設(shè)計(jì)的建議:
⑴課程設(shè)計(jì)是理論與實(shí)際相結(jié)合的應(yīng)用,對我們的學(xué)習(xí)幫助很大,讓我們更好的掌握所學(xué)知識,希望以后能更多的開展這樣的活動,讓我們有更多的機(jī)會運(yùn)用所學(xué)的知識。
⑵實(shí)際電路中,有些模塊在模擬軟件中無法進(jìn)行模擬仿真,這讓我們對自己設(shè)計(jì)的電路的可用性有些疑惑,希望學(xué)校能給我們提供能讓我們進(jìn)行實(shí)際仿真的實(shí)驗(yàn)室,讓我們能更加完善自己的電路。
同時(shí)在整個(gè)EDA的設(shè)計(jì)中,老師給予了無私的,耐心的教導(dǎo),在此感謝老師的教誨,愿老師工作順利,身體健康。
第三篇:VHDL 編程的一些心得體會
VHDL 編程的一些心得體會(轉(zhuǎn))
VHDL 是由美國國防部為描述電子電路所開發(fā)的一種語言,其全稱為(Very High Speed Integrated Circuit)Hardware Description Language。與另外一門硬件描述語言 Verilog HDL 相比,VHDL 更善于描述高層的一些設(shè)計(jì),包括系統(tǒng)級(算法、數(shù)據(jù)通路、控制)和行為級(寄存器傳輸級),而且 VHDL 具有設(shè)計(jì)重用、大型設(shè)計(jì)能力、可讀性強(qiáng)、易于編譯等優(yōu)點(diǎn)逐漸受到硬件設(shè)計(jì)者的青睞。但是,VHDL 是一門語法相當(dāng)嚴(yán)格的語言,易學(xué)性差,特別是對于剛開始接觸 VHDL 的設(shè)計(jì)者而言,經(jīng)常會因某些小細(xì)節(jié)處理不當(dāng)導(dǎo)致綜合無法通過。為此本文就其中一些比較典型的問題展開探討,希望對初學(xué)者有所幫助,提高學(xué)習(xí)進(jìn)度。
一.關(guān)于端口
VHDL 共定義了 5 種類型的端口,分別是 In, Out,Inout, Buffer及 Linkage,實(shí)際設(shè)計(jì)時(shí)只會用到前四種。In 和 Out 端口的使用相對簡單。這里,我們主要講述關(guān)于 buffer和inout 使用時(shí)的注意事項(xiàng)。
與 Out 端口比,Buffer 端口具有回讀功能,也即內(nèi)部反饋,但在設(shè)計(jì)時(shí)最好不要使用 buffer,因?yàn)?buffer類型的端口不能連接到其他類型的端口上,無法把包含該類型端口的設(shè)計(jì)作為子模塊元件例化,不利于大型設(shè)計(jì)和程序的可讀性。若設(shè)計(jì)時(shí)需要實(shí)現(xiàn)某個(gè)輸出的回讀功能,可以通過增加中間信號作為緩沖,由該信號完成回讀功能。
雙向端口 Inout 是四種端口類型中最為特殊的一種,最難以學(xué)習(xí)和掌握,為此專門提供一個(gè)簡單程序進(jìn)行闡述,部分程序如下:
...?
①DataB<=Din when CE=’1’ and Rd=’0’ else
②(others=>’Z’);
③ Dout<=DataB when CE=’1’ and Rd=’1’ else
④(others=>’1’);
? ?
程序中 DataB 為雙向端口,編程時(shí)應(yīng)注意的是,當(dāng) DataB 作為輸出且空閑時(shí),必須將其設(shè)為高阻態(tài)掛起,即有類似第②行的語句,否則實(shí)現(xiàn)后會造成端口死鎖。而當(dāng) DataB 作為有效輸入時(shí),DataB 輸出必須處于高阻態(tài),對于該例子中即,當(dāng) CE=’1’ and Rd=’1’時(shí),二.信號和變量
常數(shù)、信號和變量是 VHDL 中最主要的對象,分別代表一定的物理意義。常數(shù)對應(yīng)于數(shù)字電路中的電源或地;信號對應(yīng)某條硬件連線;變量通常指臨時(shí)數(shù)據(jù)的局部存儲。信號和變量功能相近,用法上卻有很大不同。
表 1信號與變量主要區(qū)別
信
號變量
賦值延遲至少有△延時(shí)無,立即變化
相關(guān)信息有,可以形成波形無,只有當(dāng)前值進(jìn)程敏
感是否全局性具有全局性,可存在于多個(gè)進(jìn)程中只能在某個(gè)進(jìn)程或子程序中有效相互賦值關(guān)系信號不能給變量賦值變量可以給信號賦值
對于變量賦值操作無延遲,初學(xué)者認(rèn)為這個(gè)特性對 VHDL 設(shè)計(jì)非常有利,但這只是理論上的。基于以下幾點(diǎn)原因,我們建議,編程時(shí)還是應(yīng)以信號為主,盡量減少變量的使用。
(1)變量賦值無延時(shí)是針對進(jìn)程運(yùn)行而言的,只是一個(gè)理想值,對于變量的操作往往被綜合成為組合邏輯的形式,而硬件上的組合邏輯必然存在輸入到輸出延時(shí)。當(dāng)進(jìn)程內(nèi)關(guān)于變量的操作越多,其組合邏輯就會變得越大越復(fù)雜。假設(shè)在一個(gè)進(jìn)程內(nèi),有關(guān)于變量的 3 個(gè)級連操作,其輸出延時(shí)分別為 5ns,6ns,7ns,則其最快的時(shí)鐘只能達(dá)到 18ns。相反,采用信號編程,在時(shí)鐘控制下,往往綜合成觸發(fā)器的形式,特別是對于 FPGA 芯片而言,具有豐富的觸發(fā)器結(jié)構(gòu),易形成流水作業(yè),其時(shí)鐘頻率只受控于延時(shí)最大的那一級,而不會與變量一樣層層累積。假設(shè)某個(gè)設(shè)計(jì)為 3 級流水作業(yè),其每一級延時(shí)分別為 10ns,11ns,12ns,則其最快時(shí)鐘可達(dá) 12ns。因此,采用信號反而更能提高設(shè)計(jì)的速度。
(2)由于變量不具備信息的相關(guān)性,只有當(dāng)前值,因此也無法在仿真時(shí)觀察其波形和狀態(tài)改變情況,無法對設(shè)計(jì)的運(yùn)行情況有效驗(yàn)證,而測試驗(yàn)證工作量往往會占到整個(gè)設(shè)計(jì) 70%~80%的工作量,采用信號則不會存在這類問題。
(3)變量有效范圍只能局限在單個(gè)進(jìn)程或子程序中,要想將其值帶出與其余進(jìn)程、子模塊之間相互作用,必須借助信號,這在一定程度上會造成代碼不夠簡潔,可讀性下降等缺點(diǎn)。
當(dāng)然,變量也具有其特殊的優(yōu)點(diǎn),特別是用來描述一些復(fù)雜的算法,如圖像處理,多維數(shù)組變換等。
三.位(矢量)與邏輯(矢量)
bit 或其矢量形式 bit_vector只有’0’和’1’兩種狀態(tài),數(shù)字電路中也只有’0’和’1’兩種邏輯,因此會給初學(xué)者一個(gè)誤區(qū),認(rèn)為采用位(矢量)則足夠設(shè)計(jì)之用,而不必像std_logic那樣出現(xiàn)’X’,’U’,’W’各種狀態(tài),增加編程難度。但實(shí)際情況卻并非如此,以一個(gè)最簡單 D型觸發(fā)器設(shè)計(jì)為例
? ?
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Q<=D;
⑤ end if;
⑥ end process;
? ?
實(shí)際中 clk 對數(shù)據(jù)端 D的輸入有一定的時(shí)間限制,即在 clk 上升沿附近(建立時(shí)間和保持時(shí)間之內(nèi)),D必須保持穩(wěn)定,否則 Q輸出會出現(xiàn)亞穩(wěn)態(tài),如下圖所示。
當(dāng) clk 和 D時(shí)序關(guān)系不滿足時(shí),由于 bit 只有’0’或’1’,系統(tǒng)只能隨機(jī)的從’0’和’1’中給 Q 輸出,這樣的結(jié)果顯然是不可信的;而采用 std_logic 類型,則時(shí)序仿真時(shí)會輸出為一個(gè)’X’,提醒用戶建立保持時(shí)間存在問題,應(yīng)重新安排 D和 clk 之間時(shí)序關(guān)系。
此外,對于雙向總線設(shè)計(jì)(前面已提及)、FPGA/CPLD上電配置等問題,如果沒有’Z’,’X’等狀態(tài),根本無法進(jìn)行設(shè)計(jì)和有效驗(yàn)證。
四.關(guān)于進(jìn)程
進(jìn)程(Process)是 VHDL 中最為重要的部分,大部分設(shè)計(jì)都會用到 Process 結(jié)構(gòu),因此掌握Process 的使用顯得尤為重要。以下是初學(xué)和使用 Process 經(jīng)常會出錯的例子。
1.多余時(shí)鐘的引入
在設(shè)計(jì)時(shí)往往會遇到這種情況,需要對外部某個(gè)輸入信號進(jìn)行判斷,當(dāng)其出現(xiàn)上跳或下跳沿時(shí),執(zhí)行相應(yīng)的操作,而該信號不像正常時(shí)鐘那樣具有固定占空比和周期,而是很隨機(jī),需要程序設(shè)計(jì)判斷其上跳沿出現(xiàn)與否。這時(shí),很容易寫出如下程序:
①process(Ctl_a)--Ctl_a即為該輸入信號
② begin
③ if Ctl_a’event and Ctl_a=’1’ then
④??;--執(zhí)行相應(yīng)操作
⑤ end if;
⑥ end process;
由于出現(xiàn)第③行這類語句,綜合工具自動默認(rèn) Ctl_a 為時(shí)鐘,某些 FPGA 更會強(qiáng)行將該輸入約束到時(shí)鐘引腳上。而設(shè)計(jì)者的初衷只是想將其作為下位機(jī)的狀態(tài)輸入以進(jìn)行判斷。上面的程序容易造成多時(shí)鐘現(xiàn)象,增加設(shè)計(jì)的難度。解決的辦法可以如下,將 Ctl_a 增加一級狀態(tài)
Ctl_areg 寄存,通過對 Ctl_a 和Ctl_areg 狀態(tài)判斷上跳與否,改正程序如下:① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Ctl_areg<=Ctl_a;--產(chǎn)生相鄰狀態(tài)
⑤ if Ctl_areg=’0’ and Ctl_a=’1’ then--上跳判斷
⑥??;--執(zhí)行相應(yīng)操作
⑦ end if;
⑧ end if;
⑨ end process;
程序中第④行用以產(chǎn)生兩個(gè)相鄰狀態(tài),第⑤行對前后狀態(tài)進(jìn)行判斷是否有上跳現(xiàn)
象發(fā)生。其中,需注意的是 clk 的時(shí)鐘頻率應(yīng)明顯快于 Ctl_a信號的變化頻率,以保證正確采樣。
2.輸出多驅(qū)動
誤用 Process經(jīng)常會引起輸出多驅(qū)動源的發(fā)生,即在兩個(gè)以上的進(jìn)程內(nèi)對同一信號賦值操作。
以下程序就出現(xiàn)了這類情況:
⑴ Proc_a: process(clk)
⑵ begin
⑶ if clk’event and clk=’1’ then
⑷ Dout<=Din_A;
⑸ end if
⑹ end process;;
⑺
⑻ Proc_b:process(sel_en)
⑼ begin
⑽ if sel_en=’1’ then
⑾ Dout<=Din_B;
⑿ end if;
⒀ end process;
進(jìn)程 Proc_a 和 Proc_b 中都出現(xiàn)了對 Dout 的賦值語句,設(shè)計(jì)者原本的想法是,只要合理控制好 clk 和 sel_en 輸入,使其不發(fā)生沖突,即 clk上升沿時(shí) sel_en 不為’1’;sel_en 為’1’時(shí),不出現(xiàn) clk 的上升沿,這樣 Proc_a,Proc_b 兩個(gè)進(jìn)程就不會發(fā)生沖突。但綜合時(shí),綜合工具會將所有可能情況全部羅列進(jìn)去,包括第⑶行和第⑽行同時(shí)成立的情況,此時(shí)對于 Dout就有 Din_A和 Din_B 兩個(gè)輸入驅(qū)動,Dout 不知接收哪一個(gè),因此該程序無法綜合,改正的方法是只要將兩個(gè)進(jìn)程合并成一個(gè)即可。
由于進(jìn)程在 VHDL 中的重要性,對此專門做了一個(gè)總結(jié)如下:
(1)一個(gè)進(jìn)程中不允許出現(xiàn)兩個(gè)時(shí)鐘沿觸發(fā),(Xilinx 公司 CoolRunner 系列 CPLD 支持單個(gè)時(shí)雙鐘的雙觸發(fā)沿除外)
(2)對同一信號賦值的語句應(yīng)出現(xiàn)在單個(gè)進(jìn)程內(nèi),不要在時(shí)鐘沿之后加上 else 語句,如 if clk’event and clk=’1’ then-else?的結(jié)構(gòu),現(xiàn)有綜合工具支持不了這種特殊的觸發(fā)器結(jié)構(gòu)
(3)當(dāng)出現(xiàn)多層 IF語句嵌套時(shí),最好采用 CASE 語句替代,一是減少多層嵌套帶來的延時(shí),二來可以增強(qiáng)程序的可讀性
(4)順序語句如 IF語句、CASE 語句、LOOP 語句、變量賦值語句等必須出現(xiàn)在進(jìn)程、函數(shù)或子程序內(nèi)部,而不能單獨(dú)出現(xiàn)在進(jìn)程之外
(5)進(jìn)程內(nèi)部是順序執(zhí)行的,進(jìn)程之間是并行運(yùn)行的;VHDL 中的所有并行語句都可以理解為特殊的進(jìn)程,只是不以 Process結(jié)構(gòu)出現(xiàn),其輸入信號和判斷信號就是隱含的敏感表
五.關(guān)于 VHDL 學(xué)習(xí)中的幾點(diǎn)說明
與軟件語言相比,VHDL 最重要的特點(diǎn)就在于它的并行運(yùn)行特性,當(dāng)設(shè)計(jì)好的電路上電后,器件內(nèi)部所有信號將同時(shí)并發(fā)工作,而不會以軟件方式按照
程序順序執(zhí)行,即使在進(jìn)程內(nèi)部也是趨向并行工作的。例如以下程序:① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ <=;
⑤ <=;
⑥ end if;;
⑦ end process;
綜合的結(jié)果兩個(gè)獨(dú)立的 D 型觸發(fā)器,雖然進(jìn)程內(nèi)部應(yīng)按順序執(zhí)行,但是硬件實(shí)現(xiàn)后,只要采樣到時(shí)鐘上升沿,和 狀態(tài)會同時(shí)翻轉(zhuǎn),而不會先執(zhí)行的變化,然后才會去執(zhí)行的轉(zhuǎn)變。因此,VHDL 學(xué)習(xí)過程中,應(yīng)加強(qiáng)硬件概念的理解,沒有硬件概念或是硬件概念不強(qiáng),在設(shè)計(jì)時(shí),往往會將 VHDL 設(shè)計(jì)以軟件編程的方式來處理,而得出一些不可思議的結(jié)果。
作為一門硬件描述語言,VHDL 幾乎可以用來描述現(xiàn)有的大型系統(tǒng)數(shù)字電路、算法以及其它設(shè)計(jì)。但是,限于目前綜合工具的水平,VHDL 中的許多語法還不能支持,例如:
dout<=din after 5 ns;
綜合時(shí)就無法達(dá)到如此精度,因此這條語句主要用來編寫測試激勵,而很少出現(xiàn)在設(shè)計(jì)實(shí)體中。類似的情況還有很多,目前 VHDL 設(shè)計(jì)使用的也只是整個(gè)標(biāo)準(zhǔn)中的一部分,這也正是VHDL 的“可綜合子集”性質(zhì),它一定程度上限制了 VHDL 的廣泛應(yīng)用,但是隨著綜合技術(shù)的發(fā)展,這種情況會逐漸得以改善,VHDL 也將在各個(gè)領(lǐng)域中發(fā)揮出愈來愈重要的作用
第四篇:FPGA編程經(jīng)驗(yàn)
整個(gè)verilog中是以module為編寫基本單元的,module不宜過大,目標(biāo)是實(shí)現(xiàn)一些基本功能即可,module的層次不宜太深,一般3-5層即可,給module劃分層次原則:實(shí)現(xiàn)最基本功能的為底層module,然后中層是調(diào)用這些基本module,實(shí)現(xiàn)大的功能,最高層是系統(tǒng)級模塊,統(tǒng)籌各大塊之間端口連接,時(shí)序關(guān)系等。
在module內(nèi)部編寫中,最基本塊是initial,always,以及assign塊(此外還有一些UDP原語,在行為級暫且不談),其他語句都要包含在這些塊里面。這其中,initial塊是不可綜合語句,可以用來編寫testbench,這里面的內(nèi)容在程序運(yùn)行時(shí)只執(zhí)行一次;assign語句是在不用寄存器的情況下直接編寫組合邏輯;always塊是最常用的塊,其語法格式是always @(*);其中括號里稱為敏感列表,即對于組合邏輯而言,必須是所實(shí)現(xiàn)邏輯的所有輸入變量,意思是當(dāng)組合邏輯的每一個(gè)變量發(fā)生變化,結(jié)果立刻發(fā)生變化(這與實(shí)際情況一致,對于任何組合邏輯,輸入變化,輸出立刻變化)。對于時(shí)序邏輯,常為
always@(posedge/negedge clk),指在時(shí)鐘上升沿/下降沿到來時(shí),輸出才根據(jù)那一時(shí)刻的輸入來決定輸出結(jié)果。
編程思想:
這一部分是我的心得體會,一般講verilog的書肯定不會講這個(gè),因?yàn)檫@部分感覺的東西比較多,完全靠理解應(yīng)用,沒什么固定模式,呵呵,玄了點(diǎn)。不廢話了,開始切入正題。Verilog歸根到底還是編程,同時(shí)它是對電路的編程,所以就可以利用這兩個(gè)特點(diǎn),充分利用高級語言編程(例如C)的思想和數(shù)字電路的知識,就會很大程度上幫助你。首先牢記,編寫verilog依據(jù)的是時(shí)間軸,根據(jù)時(shí)間順序確定各種信號何時(shí)進(jìn)入你的電路,可以在編寫時(shí)先把幾個(gè)主流信號(即貫穿于整個(gè)系統(tǒng)的信號,比如數(shù)據(jù)流信號)用always寫出來,這些信號就是你的基準(zhǔn),其他控制信號根據(jù)所處的位置在介入這些主流信號,分別用 always
模塊寫入。這樣,這種時(shí)間軸順序跟C的編程思想就一致,在編寫這種順序性信號時(shí),帶著C的思想,基本就容易的多。同時(shí),verilog有個(gè)很重要的電路特點(diǎn),就是在每一時(shí)刻,同時(shí)會有多個(gè)電路有信號(即在運(yùn)行),這樣就必須從傳統(tǒng)的順序語言中跳出來(跳出C的思想),然后進(jìn)入數(shù)字電路的思想,即你的編程要時(shí)刻跟實(shí)際電路模型聯(lián)系到一起,比如A<=B,C<=A,即可以想象成兩個(gè)D觸發(fā)器,其中C的輸入就是A的輸出,這樣當(dāng)時(shí)鐘沿到來時(shí),兩個(gè)D觸發(fā)器同時(shí)運(yùn)行,B的值就給了A,而A的輸出就給了C,不考慮電路延時(shí),就可以認(rèn)為二者在時(shí)間軸的同一時(shí)刻運(yùn)行成功,A在此時(shí)刻的值為B,C 在此時(shí)刻的值就是A前一時(shí)刻的值。這里只是舉了簡單的例子,但是時(shí)間軸的思路、高級語言編程思想和數(shù)字電路模型化思想以及這幾個(gè)思想的轉(zhuǎn)換對于編程來說幫助很大,幫你在編程時(shí)頭腦時(shí)刻冷靜,即使有很多信號,也會讓你從全局把握整個(gè)電路,避免頭腦一團(tuán)糟。
關(guān)于復(fù)用:
復(fù)用對于硬件設(shè)計(jì)來說,尤為重要,在實(shí)現(xiàn)功能的前提下,電路比的就是主頻和資源,而資源的減少思路就是復(fù)用。比如多次調(diào)用一個(gè)子函數(shù)A,如果直接寫,在結(jié)構(gòu)上就是這個(gè)子函數(shù)電路塊A的復(fù)制,電路完成后就會看到你調(diào)用了幾次A函數(shù),你的結(jié)構(gòu)中就有幾個(gè)一模一樣的A電路,當(dāng)你的A電路本身資源很大,而且你調(diào)用的次數(shù)很多時(shí),就很少有FPGA能裝的下了。這當(dāng)然跟我們的思想不符,我們只是想讓整個(gè)電路中只有一塊電路A,只不過把A電路在不同時(shí)刻用了幾次而已,這時(shí)就要用到電路復(fù)用的思想。電路復(fù)用并不神秘,簡單來講,就是把控制端放在A電路兩邊,用計(jì)數(shù)器之類的東西,控制在時(shí)間軸的不同時(shí)刻把值寫入A和從A輸出端讀取值。補(bǔ)充一點(diǎn),對于電路的同步,計(jì)數(shù)器是一個(gè)很好的東西,因?yàn)楸旧碛?jì)數(shù)器資源并不很大,用它來對于相差多個(gè)周期的信號進(jìn)行同步,非常實(shí)用。但是,當(dāng)信號相差的時(shí)間過于大,計(jì)數(shù)器的計(jì)數(shù)規(guī)模
就變的不可接受,這時(shí)就要用到狀態(tài)機(jī)劃分狀態(tài)的方法進(jìn)行同步了。有了同步,復(fù)用就變得簡單的多。
關(guān)于task:
這是前段時(shí)間論壇里討論比較熱的東西。語法上說,task是比always低個(gè)等級,即task必須在always里面調(diào)用,task本身可以調(diào)用 task,但不能調(diào)用module(module的調(diào)用是與always,initial,assign語句并列的,所以在這些語句中均不能直接調(diào)用 module,只能采用給module端口送值的方法達(dá)到調(diào)用的目的)。Task有什么用呢,個(gè)人覺得,用task來封裝大的邏輯語句不錯,使代碼顯得簡單明了,這個(gè)對于testbench尤為有用,但在實(shí)際電路中用處不大,因?yàn)轫樞蛘{(diào)用task對于電路來說就是電路塊的復(fù)制,順序多次調(diào)用就是多次復(fù)制電路,資源會成倍增加,不能達(dá)到電路復(fù)用的目的,同時(shí)用task封裝的純邏輯代碼會使得電路的周期變大,主頻降低,不利于為了提高主頻而采用的大邏輯切分的方法!
第五篇:LabVIEW FPGA編程小結(jié)
LabVIEW FPGA編程小結(jié)
NI PXI-7813R為FPGA卡,板卡上引出4個(gè)端口,每個(gè)端口有40路引腳,共160路DIO,使用LabVIEW FPGA模塊進(jìn)行編程控制。當(dāng)FPGA程序復(fù)雜度變大或是使用的DIO端口數(shù)增多時(shí),可能面臨的主要問題包括FPGA空間不夠用以及實(shí)際循環(huán)時(shí)間過長等。之前編寫的 FPGA程序示意圖如下,采集循環(huán)與輸出循環(huán)獨(dú)立,均采用控件形式與RT程序通訊,兩塊板卡均使用了近120路DIO口?;?813R板卡編程實(shí)踐及涉及到的幾個(gè)瓶頸問題,簡要做了一下總結(jié):
1)使用FIFO還是使用控件?
FPGA與RT通訊時(shí),常用的方法是使用讀寫FIFO或是使用輸入輸出控件。這兩者的特點(diǎn)是:
a)兩者在速度上無明顯差別。這是建立在不使用For循環(huán)的基礎(chǔ)上的,但實(shí)際中FIFO通常都要配合For循環(huán)來使用,F(xiàn)or循環(huán)相當(dāng)于串行操作,當(dāng)同類端口較多時(shí),使用for將導(dǎo)致循環(huán)時(shí)間變長,故運(yùn)行速度上FIFO并沒有多少優(yōu)勢。b)FIFO使用合理時(shí)不丟數(shù),而控件不能保證。
通過配置FPGA與RT中讀寫FIFO的超時(shí)以及FIFO大小,讀寫方式等手段,通常可保證FIFO傳遞數(shù)據(jù)不丟數(shù)(可能要經(jīng)過多次嘗試);而使用控件則可能會有丟數(shù)的情況。當(dāng)不嚴(yán)格要求每次while循環(huán)都不丟數(shù)時(shí),可考慮使用控件,例如對DO輸出的配置,用戶可能很久才會去配置一次,而且配置后不會要求馬上生效,稍微晚幾個(gè)循環(huán)周期(us級)再使配置生效也不會有很大影響,這種時(shí)候使用讀取控件值是合理的。c)FIFO可使用的數(shù)據(jù)類型有限,而控件幾乎無限制。
就7813R而言,F(xiàn)IFO只能傳遞指定的幾種類型的數(shù)據(jù),而使用控件時(shí),可使用包括簇?cái)?shù)組在內(nèi)的自定義控件。
所以,還是根據(jù)實(shí)際需要來選擇吧,雖然這句話跟沒說一樣~ 2)用不用For循環(huán)?
端口較多時(shí),很容易就遇到連續(xù)幾個(gè)都是要求采集脈寬的,而另外連續(xù)幾個(gè)要求采集電平即可。這時(shí)候很自然想到使用For循環(huán)對多個(gè)端口一起進(jìn)行操作,例如下圖:
如上面所說,使用FOR循環(huán)相當(dāng)于使端口操作(上圖中所說的操作是指將采集到的布爾轉(zhuǎn)成U32數(shù)值)變?yōu)榇校涣硗?,要使用For,通常就得配合數(shù)組操作,例如上圖中創(chuàng)建數(shù)組等,這樣就更加導(dǎo)致循環(huán)時(shí)間變長。當(dāng)發(fā)現(xiàn)循環(huán)時(shí)間不滿足使用要求時(shí),這種處理方法可能就不能使用了,每一路單獨(dú)處理就省掉了創(chuàng)建數(shù)組及For,節(jié)省了循環(huán)時(shí)間,但這樣又使重復(fù)代碼變多,工作量加大。
3)怎么使用子VI?
輸出脈沖時(shí),脈沖的產(chǎn)生可以封裝成一個(gè)子VI,供多路端口進(jìn)行使用;采集脈寬時(shí),脈寬采集可以封裝成一個(gè)子VI供多路端口進(jìn)行調(diào)用。然而,默認(rèn)情況下,子VI的執(zhí)行是串行的(因?yàn)椴]有設(shè)置VI屬性為“可重入執(zhí)行”),子VI在同一時(shí)間內(nèi)只能被一路端口所占用,可能導(dǎo)致的結(jié)果是循環(huán)時(shí)間變長,精度降低。如果設(shè)置子VI為可重入執(zhí)行,又可能導(dǎo)致FPGA空間占用率過高,編譯無法通過。我想到的一種折中的辦法是:使用幾個(gè)程序框圖一樣的子VI(功能完全一樣,將子VI多另存為幾個(gè)所生成)來代替原先一個(gè)子VI,替換之后,相當(dāng)于減少了串行運(yùn)行的子VI數(shù)量,循環(huán)用時(shí)減少明顯。下圖中使用6個(gè)子VI A,如果用2個(gè)B與2個(gè)C替換其中的4個(gè)A,循環(huán)時(shí)間可能減少為原來的1/3。
While循環(huán)方式1:子VI A子VI A子VI A子VI A子VI A子VI AWhile循環(huán)方式2:子VI A子VI A子VI B子VI B子VI C子VI C
4)精打細(xì)算
這一點(diǎn)可能只會在FPGA空間不夠用時(shí)才會被重視,下圖是邏輯片不夠用時(shí)導(dǎo)致的FPGA編譯失敗錯誤:
因此,當(dāng)資源有限時(shí),盡量使用能滿足使用要求的最小長度的數(shù)據(jù)類型來實(shí)現(xiàn),能使用U16滿足要求的堅(jiān)決不用U32!另一方面,暫時(shí)還沒有發(fā)現(xiàn)數(shù)據(jù)類型變長時(shí)對FPGA循環(huán)運(yùn)行時(shí)間產(chǎn)生明顯影響。
5)循環(huán)延時(shí)考慮
脈沖輸出及采集均需要根據(jù)實(shí)際循環(huán)時(shí)間來計(jì)算,若參與運(yùn)算的值不是實(shí)際的循環(huán)時(shí)間,輸出或采集的結(jié)果自然不會準(zhǔn)確。例如可配置脈沖或電平輸出的端口,若輸出電平,其算法簡單,所需時(shí)間較少,而配置為脈沖輸出時(shí),算法復(fù)雜。配置為單路脈沖輸出可能不會有明顯的影響循環(huán)時(shí)間,但當(dāng)多路脈沖一起輸出時(shí),可能影響到循環(huán)時(shí)間增加1~2us甚至更長。故實(shí)際配置循環(huán)時(shí)間時(shí),需按照可能的最復(fù)雜算法進(jìn)行運(yùn)行測試,并依此來設(shè)置循環(huán)時(shí)間,以保證循環(huán)時(shí)間的確定性已經(jīng)算法運(yùn)算的正確性。
總而言之,設(shè)計(jì)時(shí)還是應(yīng)該根據(jù)實(shí)際需要,綜合考慮數(shù)據(jù)完整性、FPGA板卡資源大小、循環(huán)時(shí)間等因素,已達(dá)到滿意效果。