【连载】【FPGA黑金开发板】Verilog HDL那些事儿--蜂鸣器封装(十七)
聲明:本文轉載于http://www.cnblogs.com/kingst,版權歸akuei2及黑金動力社區(http://www.heijin.org)共同所有。
5.3?實驗十六:蜂鳴器封裝
當讀者看到這章,不要笑出來,筆者連蜂鳴器也不放過,蜂鳴器也逃不過封裝的命運。
在前面(5.1和5.2)的試驗中,無論是獨立鍵盤,還是數碼管,它們都有自己的考慮,如:獨立按鍵必須消抖,數碼管有掃描的規則?...
?
?
?
那么蜂鳴器要干什么!它這家伙那么單調,只要拉低電平,這家伙就會被驅動了。既然蜂鳴器那么單調,我們就要它不單調,那怎么不單調法呢?很簡單,就是在蜂鳴器的封裝中,為它加入“功能”。蜂鳴器應該加入什么功能?就加入產生S摩斯碼和O模式碼的功能吧。
?
?
?
我們利用4.3章的“命令式仿順序操作”的方法來建立它的功能模塊。(請稍微復習一下)
?
?
?
?
?
?
?
?
?
?
?
?
如上圖。等等!這就不是一個模塊嗎!?封裝?等于?建立模塊!?那么問題來了“模塊”和“接口”本質上到底有什么的不同呢?在這里我們需要重新為“接口”加入一個“新的定義”。?
?
?
?
在5.1和5.2章中,我們定義了“接口”是“最后的工程”,不錯“封裝”卻是針對某個資源的最后建模工程。但是讀者有沒有發現,起始在5.1?和?5.2?章還包含著一個信息?
那就是“接口都是獨立性”這一個事實。
?
?
?
如果從另一個角度去理解“接口”,你可以把它看成是一個“部門”這樣的存在。在現實中我們知道“部門和部門之間”都市獨立性,而且每一個部門都是有內部的操作。那么如果要把這個觀點放入“蜂鳴器的封裝”里邊,又應該如何實現呢?
?
?
?
?
?
?
在這里我們就需要用到“FIFO”。顧名思義?FIFO?就是“先入先讀”的意思。但是在宏觀來看FIFO是雙向口的RAM,FIFO可分為兩方,“左方是寫”和“右方是讀”。然后經過一些內部加工,讀和寫可以在同時發生。?
?
?
?
FIFO的被需要時絕對有目的的。我們重新復習一下仿順序操作的概念。當某一個下層被使能時(Start_Sig?等于1),上一層模塊就必須等待下層模塊直到完成工作,才能執行下一個操作。為了避免上述的內容,我們必須借用FIFO的力量。
我們可以嘗試這樣想“如果我把操作信息全部緩沖到FIFO里的話?...”,那么上一層的模塊可以將全部操作信息緩沖到?FIFO里面,就可以擺脫“反饋信息”的“束縛”。這話怎么講呢?每當下一層模塊完成工作以后,可以直接從FIFO里面讀取操作信息,而不必依賴上一層模塊所下達的操作指令。
?
?
?
?
?
?
如果以“圖形”來表示,那么結果會是如圖上。上圖大致的操作如下:
?
?
?
(一)首先上一層模塊可以往FIFO里邊寫入大量的操作信息。然后上一層模塊可以執行其他的操作,而不必在乎“反饋信息”。
(二)當FIFO里面存在信息,控制模塊會從FIFO里面讀取信息。信息被過濾以后,轉換為執行命令,故啟動功能模塊。
(三)功能模很快便開始工作,直到工作結束,并且反饋完成信息給控制模塊。
(四)當控制模塊接收到從功能模塊反饋回來的完成信息,會再度從FIFO讀取信息,重復上述一樣的動作,直到FIFO里面的信息全部讀取完畢。
?
?
?
估計筆者們都對FIFO不怎么熟悉吧(筆者也是),那么我們就稍微的來理解一下FIFO的時序和操作:
?
?
?
(時間上升沿有效)
?
?
?
上圖是8個深度的FIFO。在FIFO初始化的時候?wr_en_a_0拉高,然而Wr_data_a_0?和?wr_level_0?都呈現?“32”?的信息?。但是在第二個時鐘的時候,?信息1就被存入深度1。第三個時鐘信息2存入深度2。直到第七個時鐘,當寫入信息6到深度6的時候,FIFO的狀態反應出“忙”,故此拉高?wr_full_0?信號,在同一個時間?we_en_a_0?被拉低。在第九個時鐘?wr_en_a0?拉高,信息8被寫入深度7。由于FIFO出現飽和狀態,所以拉高?wr_full_0信號。
?
?
在上述的內容中,我們發現在初始化的時候FIFO的深度0是用來預備初始化信息。然而在第九個時鐘的時候,基本上?FIFO已經飽和了。因此FIFO沒有理由再往里面寫入信息了,多以拉高?wr_en_a0?也沒有任何意義。
?
?
?
// wr_en?寫使能,?wr_data?寫數據,?wr_full?寫飽和。
?
?
?
?
下圖是FIFO讀數據的時序圖:?
?
?
?
(時間上升沿有效)
?
?
在初始化的時候?rd_data_b_0?呈現初始化信息“32”。在第二個時間中,從FIFO的深度7讀出信息1。在第三個時間中,從深度6讀出信息2。直到第八個時間從深度1讀出信息8以后,FIFO反應出“FIFO沒有信息了”,所以就拉高?rd_empty_0?信號。?
?
?
?
// rd_en?讀使能,?rd_data?讀數據,?rd_empty?讀空置。
?
?
?
?
上述FIFO讀寫內容的大致“圖形”如下:?
?
?
?
?
?
在時序圖上分析FIFO看似很輕松,實際上FIFO的調用也挺別扭的。信息會發生“被卡現象”。??
?
?
?
?
?
?
上圖?beep_interface.v?組合模塊中:
?
?
?
(一)FIFO擁有16個深度。
?
?
?
(二)蜂鳴器控制模塊的主要功能是從FIFO讀入一個信息經FIFO_Read_Data,?蜂鳴器控制模塊,根據從FIFO讀取的信息來使能“蜂鳴器功能模塊”;
?
?
在這一章的實驗中“蜂鳴器功能模塊”只包含兩個功能:就是產生S摩斯碼和O摩斯碼。?
所以?Command_Sig?或者?Function_Start_Sig?都是2個位寬。
?
?
?
| Function_Start_Sig = 2'b10 | 產生S摩斯碼 |
| Function_Start_Sig = 2'b01 | 產生O模式嗎 |
?
?
?
整個?beep_interface.v?說穿了就是“如何調用FIFO”而已,??FIFO?的信號有?:
?
?
?
(一)Write_Req_Sig?等價于?write_en ;
(二)Read_Req_Sig?等價于?read_en ;
(三)Full_Sig?等價于?write_full ;
(四)Empty_SIg?等價于?read_empty ;
(五)FIFO_Write_Data?等價于?write_data ;
(六)FIFO_Read_Data?等價于?read_data ;
?
?
?
那么這個?beep_interface.v?具體是如何運作還是直接看代碼好。
?
beep_function_module.v
?
?
?
|
|
?
?
?
?
?
?
|
|
?
?
?
|
|
?
?
?
第5行中的[1:0]Start_Sig?表示了該功能模塊包含了兩個功能。11~40行是1ms定時器到1秒計數器。57~74行是S摩斯碼的產生,反之75~92行是O摩斯碼的產生。在97行,由于在實際資源,蜂鳴器的控制只掛著PNP三極管,rPin_Out的輸出必須取反。
?
?
beep_control_module.v
?
?
?
|
|
?
?
?
?
?
?
|
|
?
?
?
17~31行是“加碼操作”的部分,23行會判斷經FIFO_Read_Data?讀來的信息,將它加碼為特定的命令。如通碼S“1B”加碼為命令“2'b10”(25行),通碼O“44”加碼為命令“2'b01”(26行)。然后將轉換后的命令,暫存在rCmd寄存器。但是前提必須在步驟i等于1的時候才能執行(22行),和步驟i等于5的時候清零rCmd寄存器。為什么呢?
?
?
?
35~70行是該控制模塊的核心部分。在50行,步驟0先判斷FIFO是否為空,如果FIFO不是為空?Empty_Sig?信號就被拉低。如果FIFO不為空?if?條件成立,i遞增以示下一步步驟。
?
?
?
52~56行是讀FIFO的操作,在這里我先簡單的介紹一下。在前面的?FIFO?時序圖中,當FIFO為讀狀態,如果??Read_Reg_Sig ( read_en )?不拉高,就無法把數據讀出來。FIFO讀數據是根據每一個時鐘的上升沿,如果?Read_Reg_Sig(?read_en?)拉高,那么在這一個上升沿中,數據就會被讀出來。換句話說,我們可以利用?Read_Reg_Sig?來充當讀取數據的“鎖匙”。?
?
?
?
1:begin isRead <= 1'b1; i <= i + 1'b1; end
2:begin isRead <= 1'b0; i <= i + 1'b1; end
?
?
?
如上的步驟1致2表示從FIFO讀取“一個深度的數據”。
?
?
?
在52~56行正是如上的操作。在53行將?isRead?拉高,從FIFO讀取數據。在讀入FIFO數據的一瞬間,“加碼操作”發生了(22行),“加碼成功的數據”會暫存在rCmd寄存器里。然后在56行將?isRead?拉低,為此我們已經完成“從FIFO讀取數據,然后加碼成功”。
?
?
?
在步驟3,58行先判斷?rCmd的值是否為8'h00,如果?rCmd的我值為?8'h00表示這不是我們要的命令,然后步驟i清理,返回開始。如果?rCmd的值不是?8'h00?的話,i遞增以示下一步步驟。
?
?
?
在步驟4,64行是使能?beep_function_module.v?的工作。isStart是作為?Function_Start_Sig?的驅動(75行)。加入我從FIFO讀取的信息是?8'h1B,那么它會被加碼為?2'b10?,亦即執行“S摩斯碼產生”的命令。接下來的工作就和“仿順序操作一樣”,直到下一層模塊反饋完成信號,isStart會被清理?(63行),i遞增以示下一個步驟。
?
?
?
步驟5(66~67行)多出來是用來清零rCmd寄存器的(30行)。如果不清零?rCmd寄存器后果會很麻煩。最后i清零,以示返回開始。
?
?
?
beep_interface.v
?
?
?
|
|
?
?
?
?
?
?
|
|
?
?
?
beep_interface.v?組合模塊的結果和“圖形”一樣。自己看著辦吧。
?
?
?
實驗十六說明:
實驗十六的重點,就是“如何對FIFO讀取”而已。其余的建模部分都是以往實驗的復習。
?
?
?
完成擴展圖:
?
?
?
?
?
?
實驗十六結論:
在某種程度來說,實驗十六的蜂鳴器接口,標準操作信息是“鍵盤通碼”。
實驗十六演示:
?
?
?
在上圖的組合模塊中,控制模塊對蜂鳴器接口寫入“8'h1B, 8'h44, 8'h1B”這三個信息,然后就停止操作。接著,蜂鳴器接口卻會發出“SOS信號”實際上對蜂鳴器接口的調用就是“如何對FIFO寫入信息”這一回事。
?
?
?
beep_interface_demo.v
?
?
?
|
|
?
?
?
|
|
?
?
?
這份源碼有分為兩種對FIFO寫入的辦法。
?
?
?
辦法一:
?
?
?
在拉高?isWrite?的三個時間內,同時寫入3份信息。然后再追加寫入一份?8'h00以使得達到強制擠出的效果。寫完后拉低isWrite,以示一次性的寫入操作已經結束(29~41行)。
?
?
?
辦法二:
?
?
?
辦法比較傻瓜,但是解讀性卻很好。把?isWrite?當著寫入數據的鑰匙。在拉高?isWrite?的同時寫入數據,然后在下一個步驟拉低?isWrite?以示一次性的寫數據操作已經完成。(44~60行)。
?
?
?
如果給筆者選擇,筆者會選擇辦法二。原因是辦法二比較“和藹可親”。還有一點,就是Full_Sig?這個信號是從?beep_interface.v?反饋出有關FIFO的空間狀態。如果Full_Sig?被拉高,亦即?beep_interface.v?中的?FIFO?全部?16個深度?空間已經被寫滿了。所以每一次要向?beep_interface.v?寫入信息的時候,必須判斷?Full_Sig?是否是被拉高的狀態(47,53,59行)。第65行寫入8'h00追加信息,以使得達到強制擠出的效果。
實驗十六演示說明:
在這個演示中是“beep_interface.v?如何調用”等于“FIFO如何寫入”這一回事。
?
?
?
為什么在?beep_interface_demo.v?中,當寫入?3個信息至?FIFO以后,還將無相關的?8'h00?信息寫入呢?原因很簡單,8'h00信息用來擠出前3個信息中的最后一個。如果不把第三個信息擠出,它就會卡在FIFO里邊。
?
?
?
為什么在FIFO里邊的第3個信息,如果不把它擠出,就會發生被卡現象?這個筆者也說不清楚,只是實驗結果如此?......
?
?
?
實驗十六演示結論:
?
?
?
在這一章中我們明白到,“接口”的定義除了“最后的工程”以外還有“接口是獨立”這一個定義。實際上FIFO是用來緩沖兩個時間域不同的訪問,在某種程度上“數據緩沖”的作用有如“倉庫”。所以我們可以利用這個“倉庫”作為“接口的輸入”,以致“接口”有獨立性的作用。
?
?
?
所以呀,當上一層模塊調用某個“接口”時,只要把“信息”寫入“倉庫”即可,上一層模塊用不著與該接口“互動”而被“束縛著”。該接口如果發現“倉庫”有信息,就處理信息,如果“倉庫”里沒有信息就作罷。
總結
以上是生活随笔為你收集整理的【连载】【FPGA黑金开发板】Verilog HDL那些事儿--蜂鸣器封装(十七)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python整数序列求和_Python从
- 下一篇: 电脑知识:关于电脑的十大误区,原来是这样