3.4串口通信-明德?lián)P至簡設(shè)計法原理與應(yīng)用(1)
第三篇?FPGA至簡設(shè)計項目實踐? ?
本文的文檔編號:002700000016
需要看對應(yīng)的視頻,請點擊視頻編號:000900000098
1.至簡原理與應(yīng)用配套的案例
2.實現(xiàn)通過串口調(diào)試助手發(fā)送一個8位的數(shù)據(jù)data,其可以控制開發(fā)板上的8個LED燈,data[0]~data[7]分別控制LED0~LED7燈。當(dāng)數(shù)據(jù)位為0時,對應(yīng)的LED燈點亮,數(shù)據(jù)為1時,對應(yīng)的LED燈熄滅。
3. 這是ALTERA入門學(xué)習(xí)案例文檔
? ?第四章 串口通信
第1節(jié) 項目背景
信息數(shù)據(jù)被逐位按順序傳送的通訊方式稱為串行通信。串行接口(SerialInterface),簡稱串口,即是采用串行通信方式的擴(kuò)展接口。其采用一位一位的方式順序的傳送數(shù)據(jù),又可稱串行通信接口或串行通訊接口(通常指COM接口)。串行接口的特點是通信線路簡單,只要一對傳輸線就可以實現(xiàn)雙向通信,并且可以直接利用電話線作為傳輸線,從而大大降低了成本,因此非常適用于遠(yuǎn)距離通信,但傳送的速度較慢。
1980年前后串口首次出現(xiàn),其數(shù)據(jù)傳輸率是115kbps~230kbps。初期,串口是為了實現(xiàn)計算機(jī)外設(shè)的連接,一般用來連接鼠標(biāo)和外置Modem以及老式攝像頭和寫字板等設(shè)備,也可以應(yīng)用于兩臺計算機(jī)(或設(shè)備)之間的互聯(lián)及數(shù)據(jù)傳輸。目前,串口多用于工控和測量設(shè)備以及部分通信設(shè)備中。
根據(jù)通信方式的不同,串口可分成同步串行接口(SynchronousSerial Interface,SSI)和異步串行接口(UniversalAsynchronous Receiver/Transmitter,UART)。SSI常用于工業(yè)通信,UART通用于異步接收/發(fā)送。按照電氣標(biāo)準(zhǔn)及協(xié)議的不同,串口包括RS-232-C、RS-422、RS485等。其中,RS-232-C、RS-422與RS-485標(biāo)準(zhǔn)只對接口的電氣特性做出規(guī)定,不涉及接插件、電纜或協(xié)議。下面將具體介紹一下這些常用的串口。
RS-232:RS-232是1970年由美國電子工業(yè)協(xié)會(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計算機(jī)終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準(zhǔn),其全稱為“數(shù)據(jù)終端設(shè)備(DTE)和數(shù)據(jù)通訊設(shè)備(DCE)之間串行二進(jìn)制數(shù)據(jù)交換接口技術(shù)標(biāo)準(zhǔn)”,又被稱為標(biāo)準(zhǔn)串口。RS-232是最常用的一種串行通訊接口,采用標(biāo)準(zhǔn)25芯D型插頭座(DB25),后簡化為9芯D型插座(DB9),現(xiàn)25芯插頭座在應(yīng)用中已很少采用。RS-232采取不平衡的傳輸方式,即所謂的單端通訊。由于其發(fā)送電平與接收電平僅差2V至3V左右,所以其共模抑制能力差,再加上雙絞線上的分布電容,其傳送距離最大為約15米,最高速率為20kb/s。RS-232是為點對點(即只用一對收、發(fā)設(shè)備)通訊而設(shè)計的,其驅(qū)動器負(fù)載為3~7kΩ,因此其適合本地設(shè)備之間的通信。
RS-422:RS-422標(biāo)準(zhǔn)的全稱是“平衡電壓數(shù)字接口電路的電氣特性”,其對接口電路的特性進(jìn)行了定義,采用DB9連接器。典型的RS-422是四線接口,實際上還存在一根信號地線,共為5根線。由于接收器采用高輸入阻抗和發(fā)送驅(qū)動器,RS-422比RS232的驅(qū)動能力更強,因此其可在相同傳輸線上連接多個接收節(jié)點(最多可接10個)。RS-422支持點對多的雙向通信,主設(shè)備(Master)一臺,其余為從設(shè)備(Slave),且從設(shè)備之間不能通信。接收器的輸入阻抗為4k,故最大負(fù)載能力是10×4k+100Ω(終接電阻)。由于采用單獨的發(fā)送和接收通道,RS-422四線接口不必控制數(shù)據(jù)方向,各裝置之間的信號交換均可以通過軟件方式(XON/XOFF握手)或硬件方式(一對單獨的雙絞線)實現(xiàn)。RS-422的最大傳輸距離為1219米,最大傳輸速率為10Mb/s。其平衡雙絞線的長度與傳輸速率成反比,只有在很短的距離下才能獲得最高速率傳輸,一般100米長的雙絞線上所能獲得的最大傳輸速率僅為1Mb/s,在100kb/s速率以下才可能使用規(guī)定最長的電纜長度。
RS-485:RS-485從RS-422基礎(chǔ)上發(fā)展而來,因此其許多電氣規(guī)定與RS-422相仿,如都采用平衡傳輸方式、都需要在傳輸線上接終接電阻等。與RS-422相同,其最大傳輸距離約為1219米,最大傳輸速率為10Mb/s,平衡雙絞線的長度與傳輸速率成反比,只有在很短的距離下才能獲得最高速率傳輸。RS-485可以采用二線與四線兩種連接方式:二線制可實現(xiàn)真正的多點雙向通信,而四線制與RS-422一樣只能實現(xiàn)點對多的通信,即只能有一臺主(Master)設(shè)備,其余為從設(shè)備。但無論四線還是二線連接方式總線上可多接到32個設(shè)備,與RS-422相比有一定的提升。此外,RS-485與RS-422的共模輸出電壓不同,RS-485的輸出范圍是-7V至+12V,而RS-422是-7V至+7V。RS-485接收器最小輸入阻抗為12kΩ,而RS-422是4kΩ??梢钥闯鯮S-485滿足RS-422的所有規(guī)范,因此其可以在RS-422網(wǎng)絡(luò)中應(yīng)用。
CH340:由于串口(COM)不支持熱插拔及傳輸速率較低,目前大部分新主板和便攜電腦已開始取消CH340接口,只有工控和測量設(shè)備以及部分通信設(shè)備中還保留有串口。因此,為了使用該串口,需要使用USB轉(zhuǎn)串口的芯片來使電腦把USB當(dāng)串口來使用。這種類型的芯片很多,本書使用的是CH340芯片。CH320是一個USB總線的轉(zhuǎn)接芯片,用來實現(xiàn)USB轉(zhuǎn)串口、USB轉(zhuǎn)IrDA紅外或者USB轉(zhuǎn)打印口等功能。在串口方式下,CH340可以為計算機(jī)擴(kuò)展異步串口提供常用的MODE聯(lián)絡(luò)信號,或?qū)⑵胀ǖ拇谠O(shè)備直接升級到USB總線。
本書的串口功能原理如下圖所示,通過USB線將電腦與教學(xué)板上的USB接口相連,USB接口的另一端與CH340芯片連接,CH340芯片與FPGA相連。從FPGA的角度來看,串口其實就是兩根線:輸入線USB_RXD和輸出線USB_TXD,通過USB_RXD接收來自電腦過來的串口數(shù)據(jù),通過USB_TXD將數(shù)據(jù)傳送給電腦。其他電氣特性、電平轉(zhuǎn)換的工作,都可以通過CH340完成。

圖3.4-1教學(xué)板串口實現(xiàn)架構(gòu)圖
進(jìn)行傳輸數(shù)據(jù)時,USB_RXD和USB_TXD將數(shù)據(jù)字符按位傳輸,其串口時序如下圖所示。USB_RXD的時序由CH340芯片產(chǎn)生,F(xiàn)PGA依此來接收數(shù)據(jù)。反過來,F(xiàn)PGA芯片按規(guī)范產(chǎn)生USB_TXD的時序,使得CH340可以正確地接收。其中,產(chǎn)生時序的為MASTER(主),接收數(shù)據(jù)為SLAVE(從)。

圖3.4-2串口時序圖
串口時序主要包括:空閑、起始位、數(shù)據(jù)拉、校驗位和停止位。下面逐一朋友解釋每個時序位的狀態(tài)。
空閑:空閑狀態(tài)下,數(shù)據(jù)線一直處于高電平狀態(tài)。
起始位:當(dāng)MASTER準(zhǔn)備發(fā)送數(shù)據(jù)時,會先將數(shù)據(jù)線拉低“一段時間”,以此來告知SLAVE做好數(shù)據(jù)傳輸?shù)臏?zhǔn)備。
數(shù)據(jù)位:起始位之后是數(shù)據(jù)位,其位數(shù)由主從雙方共同約定,支持4、5、6、7、8位等,完成約定后才能正確地傳輸。傳輸順序是從低位開始,每個數(shù)據(jù)位傳輸時都會占用“一段時間”。從圖3.4-2中可以看出,傳輸從LSB開始,至MSB結(jié)束,LSB即表示低位,MSB表示高位。以數(shù)據(jù)8’b00000001為例,傳輸該數(shù)據(jù)時最先傳送的即是最低位的“1”。
檢驗位:顧名思義,校驗位是用于數(shù)據(jù)校驗。目前簡單常用的數(shù)據(jù)校驗方式是奇偶校驗,分為奇校驗和偶校驗。奇校驗需要保證傳輸數(shù)據(jù)總共有奇數(shù)個邏輯高電平,偶校驗則需保證傳輸數(shù)據(jù)有偶數(shù)個邏輯高電平。即“奇偶”指的是數(shù)據(jù)中(包括該校驗位)1的個數(shù)。例如:傳輸?shù)臄?shù)據(jù)是0100_0011。如果校驗方式是奇校驗則校驗位是0,若是偶校驗則校驗位是1。傳輸中校驗位不是必須項,雙方可以約定不需要校驗位,或者使用奇/偶校驗方式。
停止位:字符幀的最后一位是停止位。由于每臺設(shè)備都有其自身時鐘,在通信中兩臺設(shè)備間可能出現(xiàn)了小小的不同步,從而影響了數(shù)據(jù)傳輸結(jié)果。因此,MASTER必須保證有停止位,即數(shù)據(jù)線需拉高“一段時間”。停止位不僅僅是表示傳輸?shù)慕Y(jié)束,也是一個校正時鐘同步的機(jī)會,讓SLAVE可以正確地識別下一輪數(shù)據(jù)的起始位。假如沒有停止位,若校驗碼剛好是0,數(shù)據(jù)連續(xù)發(fā)送時SLAVE無法判斷下一輪的起始位。對于SLAVE來說,數(shù)據(jù)位或校驗位接收后就已經(jīng)完成接收工作,在停止位無需任何操作,只需等待下一輪起始即可。
上文中提到每個數(shù)據(jù)都會傳輸“一段時間”,這段時間并不是隨便定義的,需要傳輸雙方做好約定,否則就不能正確地進(jìn)行通信。那么“一段時間”究竟是指多長時間呢?這與波特率有關(guān)。波特率在串口通信中是一個非常重要的概念,其為模擬信號線路的速率。在串口通信中常用的波特率是9600、19200、38400、57600、115200,代表每個碼元傳輸?shù)乃俾?。在二進(jìn)制數(shù)據(jù)傳輸中,波特率和比特率相同都為每個比特數(shù)據(jù)傳輸?shù)乃俾剩涞箶?shù)為1bit數(shù)據(jù)的位寬,也就是1bit數(shù)據(jù)持續(xù)的時間。確定了這一時間,就可用FPGA構(gòu)造計數(shù)器實現(xiàn)比特周期的延時,從而實現(xiàn)特定波特率的數(shù)據(jù)傳輸。
舉個例子,假設(shè)波特率為9600,數(shù)據(jù)位為8位,無校驗位。電腦要傳送數(shù)據(jù)8’b00110001給FPGA。由于波特率為9600,每位占用時間為1s/9600=104166ns。那么FPGA的USB_RXD(圖中的rx_uart)將如下圖所示進(jìn)行變化。

圖3.4-3帶時間信息的串口時序圖
在使用開發(fā)板的串口前,需要安裝CH340的驅(qū)動程序(下載鏈接:http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=433),下載后直接解壓安裝就可以進(jìn)行使用。
使用USB線將電腦和開發(fā)板進(jìn)行連接后將開發(fā)板上電,打開電腦的“設(shè)備管理器”。當(dāng)出現(xiàn)如下圖所示的界面時表示驅(qū)動程序安裝成功并且已經(jīng)被電腦正確地識別。

圖3.4-4驅(qū)動程序成功安裝且被電腦正確地識別界面
在“設(shè)備管理器”中可以查看串口號,點擊“USBSerial Port(COM3)”,如下圖所示。

圖3.4-5在設(shè)備管理器中查看串口號
隨后點擊“端口設(shè)置”選擇“高級”選項,如下圖所示。

圖3.4-6端口設(shè)置界面
下圖中可見端口號的具體設(shè)置信息,其串口號為COM3。

圖3.4-7高級設(shè)置界面
點擊CON端口號,可以對串口號進(jìn)行修改,如下圖所示。

圖3.4-8更改串口號
電腦發(fā)送數(shù)據(jù)給FPGA這一操作中需要使用串口調(diào)試助手(下載鏈接:http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=437),其界面如下圖所示,下面對其具體參數(shù)設(shè)置進(jìn)行說明。

圖3.4-9串口調(diào)試助手界面
串口:選擇串口號,支持串口號1~4。如果連接的串口號不在此范圍,則需要在設(shè)備管理器中修改串口號,詳細(xì)參見前文描述。
波特率:選擇串口的波特率,支持9600、19200、38400、57600、115200。該選項決定了每一位碼元占用的時間。
校驗位:可選擇“沒有檢驗位”、“奇校驗”和“偶校驗”。
數(shù)據(jù)位:設(shè)置數(shù)據(jù)位的位數(shù),可選擇4~8位的數(shù)據(jù)拉。
停止位:設(shè)置停止位的時間長度??蛇x擇1位、1.5位和2位。
打開/關(guān)閉串口:打開軟件時,該串口默認(rèn)是關(guān)閉狀態(tài)。這里要注意有關(guān)串口使用的方法:一定要先設(shè)置好參數(shù)后,才能打開串口;反之,一定要先關(guān)閉串口后,才能關(guān)掉教學(xué)板電源和拔掉USB線。
十六進(jìn)制顯示:本軟件支持ASCII顯示和十六進(jìn)制顯示。若勾選了十六進(jìn)制顯示,軟件就會顯示十六進(jìn)制。例如FPGA發(fā)送數(shù)據(jù)8’b00110001,軟件收到后會顯示為十六進(jìn)制,即31。反之如果不勾選十六進(jìn)制顯示,則會顯示ASCII碼。如果FPGA依然發(fā)送8’b00110001,對照下圖的ASCII表可看出其所對應(yīng)的圖形為“1”,因此軟件會顯示“1”;假設(shè)FPGA發(fā)送的是8’h00100011,下表中其所對應(yīng)的是圖形是“#”,因此軟件會顯示“#”。

圖3.4-10ASCII編碼圖
十六進(jìn)制發(fā)送:同樣的,本軟件支持ASCII發(fā)送和十六進(jìn)制發(fā)送。若勾選十六進(jìn)制發(fā)送,軟件則會以十六進(jìn)制形式發(fā)送。例如填寫“31”后手動發(fā)送,那么FPGA收到的值為8’b00110001。如果不勾選十六進(jìn)制發(fā)送,則軟件以ASCII碼形式發(fā)送。若同樣填寫“31”后手動發(fā)送,軟件將首先發(fā)送ASCII碼“3”所對應(yīng)的十六進(jìn)制值8’h33,再發(fā)送ASCII碼“1”所對應(yīng)的十六進(jìn)制值8’h31,即FPGA將收到兩個字節(jié)數(shù)據(jù):8’h33和8’h31。
第2節(jié) 設(shè)計目標(biāo)
了解了串口通信的原理后,本書將完成串口通信的設(shè)計。按照至簡設(shè)計法的思路,進(jìn)行設(shè)計之前首先應(yīng)明確設(shè)計目標(biāo),后續(xù)設(shè)計中每一個步驟都是圍繞著設(shè)計目標(biāo)的實現(xiàn)來針對性的展開。如果沒有明確設(shè)計目標(biāo)就開始操作實踐,最終的作品也只是東拼西湊的產(chǎn)物。在這種狀態(tài)下的工程調(diào)試過程如果出現(xiàn)了問題,則需要花費大量的精力進(jìn)行尋找修復(fù)。因此建議初學(xué)者在最開始學(xué)習(xí)時養(yǎng)成良好的工作習(xí)慣,在后續(xù)工作中會受益無窮。
本設(shè)計中串口調(diào)試助手的參數(shù)設(shè)置為:波特率9600;數(shù)據(jù)位為8位;無奇偶校驗位;停止位為2比特;接收和發(fā)送都是16進(jìn)制數(shù)。
本設(shè)計中,用戶通過串口調(diào)試助手發(fā)送一個8位的數(shù)據(jù)data,其可以控制開發(fā)板上的8個LED燈,data[0]~data[7]分別控制LED0~LED7燈。當(dāng)數(shù)據(jù)位為0時,對應(yīng)的LED燈點亮,數(shù)據(jù)為1時,對應(yīng)的LED燈熄滅。例如,用戶發(fā)送數(shù)據(jù)data=8’b10000000后,開發(fā)板上的LED0、LED1、LED2LED3、LED4、LED5、LED6保持為亮,LED7保持為滅。這里要注意,信號的傳輸順序是從低到高的,數(shù)據(jù)的最后一位“0”對應(yīng)LED0,倒數(shù)第二位“0”對應(yīng)LED1,倒數(shù)第三位“0”對應(yīng)LED2,依次類推,第一位“1”對應(yīng)LED7。
設(shè)計完成后的上板效果如下圖所示。

圖3.4-11串口通信實現(xiàn)效果圖
第3節(jié) 設(shè)計實現(xiàn)
確定設(shè)計目標(biāo)后,下面會逐步分析講解工程的實現(xiàn)步驟。本書不僅分享案例,還會在操作過程中剖析設(shè)計理念及原理,同時也分享一些至簡設(shè)計法的設(shè)計技巧以鍛煉獨立設(shè)計工程的能力。因此,建議初學(xué)者認(rèn)真學(xué)習(xí)每一步。當(dāng)然,在已經(jīng)擁有扎實的功底、只是想要根據(jù)步驟完成設(shè)計的情況下可以跳過此部分,直接進(jìn)入后續(xù)章節(jié)中的簡略版操作步驟。
3.1?頂層信號
新建目錄:D:mdy_bookuart,并在此目錄中新建一個名為uart.v的文件。并用GVIM打開該文件后開始編寫代碼。在這里再次強調(diào),初學(xué)者一定要按照本書提供的文件路徑以及文件名進(jìn)行設(shè)置,避免后面出現(xiàn)未知錯誤。
根據(jù)設(shè)計目標(biāo)可知,用戶通過串口調(diào)試助手向FPGA發(fā)送數(shù)據(jù),即CH340控制RX信號讓其根據(jù)串口時序變化,從而將數(shù)據(jù)信號傳送至FPGA。因此FPGA工程必須有一個接口信號,本書將其命名為rx_uart。
本設(shè)計中需要控制8個LED燈的亮滅,按照之前章節(jié)中信號與燈的對應(yīng)方法,需要8個信號來進(jìn)行控制:led0,led1,led2,led3,led4,led5,led6,led7。然而本設(shè)計是采用串口指令控制小燈,且8個信號數(shù)目過于繁多。因此,可以選擇使用一個8比特的信號,將其命名為led。既然如此,那之間幾個章節(jié)中的工程可以用這種方法嗎?答案是肯定的,可以將led0,led1,led2,led3四個信號轉(zhuǎn)換為一個4比特的信號led。雖然設(shè)計內(nèi)容與需求不同,但是至簡設(shè)計法一定會分享最合適最簡單的方法。
硬件電路的連接關(guān)系如下表所示。本設(shè)計中采用8比特的信號led來控制8個LED燈,工程的時鐘管腳為G1,對應(yīng)FPGA工程信號為clk;復(fù)位管腳為AB12,對應(yīng)FPGA工程信號為rst_n;串口輸入管腳為D6,對應(yīng)FPGA工程信號為rx_uart。因此本工程共需要4個信號:8位信號led,時鐘clk,復(fù)位rst_n和串口輸入信號rx_uart。
表3.4 - 1信號和管腳關(guān)系

將module的名稱定義為uart,在頂層信號代碼中將與外部相連接的輸入/輸出信號列出,從而實現(xiàn)信號與管腳的連接。已知該模塊有四個信號:clk、rst_n、rx_uart和led,其具體代碼如下:

隨后對信號的輸入輸出屬性進(jìn)行聲明,指出對于FPGA來說這一信號屬于輸入還是輸出,若為輸入,聲明則為input;若為輸出,聲明則為output。在本設(shè)計中由于clk是外部的晶振輸送給FPGA的,因此在FPGA中clk為輸入信號input;同樣地,rst_n是外部按鍵給FPGA的,在FPGA中也是輸入信號input;同時可知led是FPGA輸出給LED燈的,是輸出信號output。clk、rst_n、rx_uart三個信號的值都為0或1,用一根線表示即可,而led信號位寬為8。根據(jù)信號屬性將輸入輸出端口定義補充完整,其代碼如下:

3.2 信號設(shè)計
由前文可知,led信號控制了8個LED燈的亮滅,然而其亮滅控制還是取決于串口發(fā)送數(shù)據(jù)。那么就存在這樣一個問題:串口發(fā)送的數(shù)據(jù)是如何告知FPGA并與led對應(yīng)起來呢?下面本書就來分析一下串口數(shù)據(jù)的時序,CH340控制信號rx_uart的時序如下圖所示。

圖3.4-12串口時序圖
從時序圖中可以看出:發(fā)送8位數(shù)據(jù)data前,信號rx_uart會先變?yōu)?并持續(xù)一段時間(起啟位),然后發(fā)送data[0]、data[1],以此類推直至發(fā)送完data[7],發(fā)送每位數(shù)據(jù)時都會持續(xù)一段時間,發(fā)送完畢后rx_uart會變?yōu)?并持續(xù)一段時間(結(jié)束位)。至此,CH340完成了數(shù)據(jù)的發(fā)送??梢钥闯雒慷斡行盘柕拈_始前和結(jié)束后,都會有特殊信號:有效數(shù)據(jù)開始前會有一段變0的信號,用以告
知FPGA開始傳送數(shù)據(jù);結(jié)束后會有一段變1的信號,告知FPGA此數(shù)據(jù)傳送結(jié)束。
例如,CH340要發(fā)送的數(shù)據(jù)為data=8’h00110001,則rx_uart的波形如下。

3.4-13串口通信時序圖
由于波特率設(shè)置為9600,考慮時間信息,每位持續(xù)的時間是1s/9600=104166ns。補充時間信息后的時序如下圖所示。

圖3.4-14帶時間的時序圖
本開發(fā)板的晶振時鐘是50Mz,對應(yīng)時間周期為20ns。由此可知每位數(shù)據(jù)持續(xù)時間為104166ns/20ns=5208.3個時鐘周期,近似為5208個時鐘周期。由于5208只是估計的大概數(shù)字,實際情況會產(chǎn)生一定的偏差。在實現(xiàn)過程中,應(yīng)對數(shù)據(jù)位數(shù)進(jìn)行計數(shù),以此來判斷開始位、數(shù)據(jù)位和停止位等。

圖3.4-15串口通信實現(xiàn)架構(gòu)圖【這個圖要去掉ns】
通過上文分析可知:本設(shè)計一共需要2個計數(shù)器,1個計數(shù)器用于計算1比特的位寬長度即5208個時鐘周期,將其命名為cnt0;另一個用于計算有多少個比特,將其命名為cnt1。
首先討論cnt0的實現(xiàn),至簡設(shè)計法中計數(shù)器的設(shè)計只考慮兩個因素:加1條件和計數(shù)數(shù)量。由于1比特的位寬長度是5208個時鐘周期,因此cnt0的計數(shù)數(shù)量是5208。
確定了計數(shù)數(shù)量后來分析一下cnt0的加1條件。為了更好理解加1條件的概念,這里以停車位來進(jìn)行比喻。一般情況下對每個停車位置會進(jìn)行對應(yīng)編號,但是如果某個位置上放置了一塊石頭無法作為停車位時,該位置就不能獲得對應(yīng)的編號。反之則可以認(rèn)為停車位編號的加1條件就是:對應(yīng)位置上沒有石頭,其可以繼續(xù)的進(jìn)行編號,即assign add_cnt0 = “沒有石頭”。因此如果在設(shè)計中計數(shù)器一直沒有阻礙地進(jìn)行計數(shù)工作,就可以認(rèn)為加1條件是一直有效的。根據(jù)設(shè)計目標(biāo),可以確定cnt0的加1區(qū)域為其一直工作的區(qū)域,如下圖灰色區(qū)域所示。

圖3.4-16計數(shù)器cnt0的加1區(qū)域
雖然確定了cnt0的加1區(qū)域,但現(xiàn)有設(shè)計中沒有任何一個信號可以單獨表示出這一區(qū)域。在這種情況下,進(jìn)行對信號進(jìn)行補充。因此本設(shè)計添加一個“flag_add”信號,該信號為1時表示上述灰色區(qū)域,即cnt0的加1區(qū)域。這樣就可以明確計數(shù)器cnt0的加1條件為“flag_add==1”。

圖3.4-17補充加1條件flag_add
確定好cnt0的加1條件和計數(shù)數(shù)量后,就開始進(jìn)行代碼編寫,以往都是一行行的輸入相應(yīng)代碼。但是至簡設(shè)計法有一個小技巧,可以節(jié)省代碼編寫時間的同時在一定程度上降低了代碼的出錯率。至簡設(shè)計法將日常代碼中常用到的固定部分制作成模板,進(jìn)行代碼編程時可以調(diào)用相應(yīng)模板后根據(jù)邏輯輸入對應(yīng)設(shè)計的變量將代碼補充完整。這里就可以用模板編寫計數(shù)器代碼,感受一下這個炫酷的功能。
打開GVIM工具,在命令模式下輸入“:Mdyjsq”后點擊回車,調(diào)出對應(yīng)模板如下圖所示。

圖3.4-18至簡設(shè)計法調(diào)用計數(shù)器代碼模板
通過上文分析可知,cnt0的加1條件是“flag_add==1”,計數(shù)數(shù)量為5208。將其填入到模板中,可以得到完整正確的計數(shù)器cnt0代碼如下:

下面來設(shè)計計數(shù)器cnt1,該計數(shù)器用于表示數(shù)到第幾比特,每個比特結(jié)束,即“end_cnt0”時,cnt1就會加1。因此cnt1的加1條件是:end_cnt0。通過設(shè)計目標(biāo)中可知cnt1的計數(shù)數(shù)量為9。打開GVIM,繼續(xù)調(diào)用模板,在命令模式下輸入“:Mdyjsq”,點擊回車。將“add_cnt1”和“end_cnt1”補充完整,得到cnt1的代碼為:

在設(shè)計cnt0時,考慮到其加1條件增加了輔助信號flag_add,下面就來思考如何設(shè)計這一信號。通過分析可知flag_add具有兩個變化點:變0和變1,這兩種變化可以從功能上進(jìn)行理解。工程通電后,如果PC端沒有發(fā)送任何數(shù)據(jù),則rx_uart始終保持為1,cnt0和cnt1無須計數(shù),flag_add信號也一直保持為0。當(dāng)PC端要發(fā)送數(shù)據(jù)時,rx_uart就會按串口時序產(chǎn)生變化,首先會發(fā)送一個開始位,即rx_uart由1變成0。FPGA接收到這一信號后,就明白PC要開始傳送數(shù)據(jù),此時cnt0和cnt1要計數(shù)了,即flag_add要變?yōu)?。
可以通過下圖來輔助分析,可以看到當(dāng)rx_uart為1時,flag_add為0,此時PC沒有發(fā)來任何數(shù)據(jù),cnt0和cnt1不計數(shù)。當(dāng)rx_uart數(shù)第1比特,即開始位時,即通知FPGA準(zhǔn)備好接收數(shù)據(jù),這時rx_uart變0時,flag_add變1,cnt0和cnt1開始計數(shù)。

圖3.4-19確定flag_add信號
從上圖可以很容易看出:當(dāng)rx_uart由1變0時,flag_add就由0變成1。其中,rx_uart信號的由1變0波動被稱為下降沿,在圖中可以清晰的看出此時波形是下降的。那么又如何得知下降沿的到來呢?這里就需要引入一個邊沿檢測電路工程來輔助設(shè)計。
3.2.1邊沿檢測電路設(shè)計
檢測rx_uart的下降沿需要用到FPGA中的邊沿檢測技術(shù)。所謂邊沿檢測,就是檢測輸入信號或FPGA內(nèi)部邏輯信號的跳變,即檢測上升沿或下降沿。這一技術(shù)這在FPGA電路設(shè)計中被廣泛應(yīng)用,其電路圖及各信號定義如下所示。

圖3.4-20邊緣檢測實現(xiàn)原理圖

圖3.4-21各信號定義
可以看出中間信號trigger與觸發(fā)器的信號輸入端D連接,將trigger信號取反后與觸發(fā)器的輸出tri_ff0相與得到信號neg_edge。如果neg_edge=1就表示檢測到trigger的下降沿。將觸發(fā)器的輸出tri_ff0取反與trigger相與后得到信號pos_edge,如果pos_edge=1則表示檢測到trigger的上升沿。利用這一原理可以畫出信號的波形圖如下圖所示。

圖3.4-22邊緣檢測電路波形圖
tri_ff0是觸發(fā)器的輸出,因此tri_ff0的信號與trigger信號只是相差了一個時鐘周期。這里也可以這樣理解:每個時鐘上升沿看到的tri_ff0值實際上是上一個時鐘看到的trigger信號值,即tri_ff0的值是trigger在上一時刻的值。
以記錄的體重值為例來幫助理解,假設(shè)第一天的體重是49kg,第二天是50kg,第三天是50kg,第四天為49kg,可以看到體重值在發(fā)生變化。此時tigger信號為當(dāng)天記錄的體重值,而tri_ff0信號為前一天的體重值,即第二天的tigger值為當(dāng)天體重50kg,tri_ff0值為前一天體重49kg,第三天的tigger值為當(dāng)天體重50kg,tri_ff0值為前一天體重50kg,以此類推。在生活中將當(dāng)天的體重和前一天進(jìn)行對比就可以得知體重的變化,通過兩個信號的對比也能得知信號的變化。比如第二天的tigger值50kg,此時tri_ff0為49kg,50大于49,可以看到體重上升,對應(yīng)信號變化即可視作迎來了一次上升沿。綜上所述,rx_uart的上升沿/下降沿檢測依據(jù)為這一刻的狀態(tài)與上一刻的狀態(tài)有0到1或者1到0的變化。
從圖3.4- 22可以看出,第3個時鐘的上升沿處trigger值為0,而tri_ff0值為1,即trigger的值發(fā)生了從1到0的變化,即迎來下降沿,此時neg_edge為1。反之,當(dāng)neg_edge的值為1,就表示檢測到了trigger的下降沿。同理,在第7個時鐘的上升沿處trigger值為1,而tri_ff0值為0,此時pos_edge的值為1,表示檢測到了trigger的上升沿。
綜上所述,可以得出Verilog實現(xiàn)邊沿檢測電路的代碼如下:

3.2.2異步信號同步化
在邊沿檢測波形的討論中將trigger信號視為理想的同步信號,即trigger滿足D觸發(fā)器的建立和保持時間,這種情況下在同步系統(tǒng)中實現(xiàn)邊沿檢測不是問題。但如果trigger信號不是理想的同步信號(如外部按鍵信號或是本工程的rx_uart信號)時,信號的變化由外部傳輸指令給FPGA,對于FPGA來說這些信號什么時候產(chǎn)生變化是完全隨機(jī)的。因此,很可能出現(xiàn)信號在時鐘上升沿發(fā)生變化,無法滿足觸發(fā)器的建立時間和保持時間要求,從而出現(xiàn)亞穩(wěn)態(tài),導(dǎo)致系統(tǒng)崩潰。詳細(xì)原因可以參看至簡設(shè)計法D觸發(fā)器中亞穩(wěn)態(tài)一節(jié)的相關(guān)內(nèi)容。根據(jù)這一結(jié)論,本設(shè)計需要對輸入的信號延遲兩拍即先用兩個觸發(fā)器寄存后再進(jìn)行使用。如下圖所示,用2個觸發(fā)器對信號進(jìn)行寄存,確定了信號的穩(wěn)定性,然后再進(jìn)行邊沿檢測,滿足了同步系統(tǒng)中實現(xiàn)邊沿檢測的需求。

圖3.4-23異步信號同步化電路圖
因此,在邊沿檢測代碼設(shè)計前需要先對觸發(fā)器進(jìn)行設(shè)計。假設(shè)輸入的信號trigger不是同步信號,則該信號需要用2個觸發(fā)器進(jìn)行寄存,得到信號tri_ff0和tri_ff1。需要特別注意的是,在第一個觸發(fā)器階段,信號依舊存在亞穩(wěn)態(tài)的情況,因此tri_ff0絕對不可以作為條件使用,只能以信號tri_ff1作為條件。得到同步信號后用寄存器寄存,得到信號tri_ff2,根據(jù)tri_ff1和tri_ff2就可以得到邊沿檢測結(jié)果。即當(dāng)tri_ff1==1且tri_ff2==0時,上升沿的pos_edge有效;當(dāng)tri_ff1==0且tri_ff2==1時,下降沿的neg_edge有效,其具體代碼如下:

綜上所述,如果輸入信號是異步信號,需要先對其進(jìn)行同步化之后再做檢測,即通過延遲兩拍的方式實現(xiàn)信號的同步化,再通過延遲一拍的方式實現(xiàn)邊沿檢測電路。反之,如果輸入信號本身就是同步信號,則沒有必要進(jìn)行同步化了,可以直接對其進(jìn)行邊沿檢測。
回到本設(shè)計中,此時需要檢測的是rx_uart的下降沿,并以此為條件拉高信號flag_add。由于PC端隨機(jī)地給FPGA發(fā)送數(shù)據(jù),其發(fā)送時刻是不確定的,因此本設(shè)計中rx_uart是異步信號。根據(jù)邊緣檢測的設(shè)計方法,此時需先將rx_uart進(jìn)行同步化后再對其進(jìn)行下降沿檢測。其具體設(shè)計代碼如下:

如此一來,flag_add變1的條件就變成:rx_uart_ff1==0&& rx_uart_ff2==1。
確定flag_add變1條件后,再來討論一下其變0的條件。當(dāng)完成9比特數(shù)據(jù)的傳輸后,flag_add的值變?yōu)?,不再計數(shù)。因此,其變0條件為end_cnt1。根據(jù)以上分析可以得到flag_add的代碼如下。

下面來設(shè)計data信號,根據(jù)串口時序可知,該信號的值來自下圖中第2~第9比特的值。其中第2比特的值賦給data[0],第3比特的值賦給data[1],以此類推,第9比特的值賦給data[7]。

圖3.4-24串口通信實現(xiàn)架構(gòu)圖【去掉ns】
由于每一個比特都會持續(xù)5208個時鐘周期,因此必須選定一個具體時刻來將值賦給data。此處可能會有這樣的疑慮:直接在每個比特計數(shù)結(jié)束的時刻,即在end_cnt0的時刻賦值不就可以了么?然而實際上,這一時刻并不可取。end_cnt0的時刻在下圖中用點表示出來,此時的5208個時鐘周期是理想、估算的數(shù)值,而在實際計算中很有可能出現(xiàn)偏差,如果在end_cnt0的時候取值,就有可能會出現(xiàn)錯誤。

圖3.4-25邊緣取值方法【去掉ns】
因此,最保險的做法是在中間點取值,如下圖所示。在這種取值方法下,即使有較多的偏差,也不會影響到采樣的正確性。

圖3.4-26中間取值的方法
綜上所述,本設(shè)計在cnt0計數(shù)到一半時將采到的當(dāng)前rx_uart值賦給led,其中第2比特賦給led[0],第3比特賦給led[1],以此類推,第9比特賦給led[7]。將其用代碼的形式表現(xiàn)出來則為:當(dāng)add_cnt0&& cnt0==5208/2 -1時,如果cnt1==1,則將rx_uart_ff1賦給led[0]。如果cnt1==2,則將rx_uart_ff1賦給led[1],以此類推,如果cnt1==8,將rx_uart_ff1賦給led[7]。其具體代碼如下所示。

對以上代碼進(jìn)行優(yōu)化,可簡寫為:

在進(jìn)行設(shè)計時,通常是首先想到實現(xiàn)功能,所以會先寫出第一段的優(yōu)化前代碼。在功能實現(xiàn)的前提下,再考慮有沒有優(yōu)化空間,從而對其進(jìn)行優(yōu)化得到第二段代碼。設(shè)計過程中,好的代碼也是這樣一步步優(yōu)化出來的。至此,主體程序已經(jīng)完成。
3.3 信號定義
下面需要將module補充完整,首先來定義信號類型。reg和wire的判斷很容易搞不清楚總會有其余的聯(lián)想,比如認(rèn)為reg就是寄存器,wire是線;或者認(rèn)為reg的會綜合成寄存器,wire不會綜合成寄存器。但是這些其實和reg型還是wire型都是沒有關(guān)系的,因此在信號類型判斷時不需要做任何的聯(lián)想,只要記住一個規(guī)則“用always實現(xiàn)的是reg型,其他都是wire型”就可以了。
cnt0是用always產(chǎn)生的信號,因此類型為reg。根據(jù)前文分析可知,該計數(shù)器計數(shù)的最大值為5208,因此需要用13根線表示,即位寬是13位。
關(guān)于信號位寬的獲取,至簡設(shè)計法在此分享一個非常實用的技巧:打開計算器,點擊“查看”,選擇“程序員”模式,在“十進(jìn)制”下將信號值輸入,就會獲得對應(yīng)的信號位寬,如下圖所示,將計數(shù)器的最大值5208輸入,可以看出其位寬為13。

圖3.4-27通過計算器獲取信號位寬
綜上所述,cnt0的信號定義代碼如下:

cnt1也是用always產(chǎn)生的信號,因此類型為reg。cnt1計數(shù)的最大值為9,需要用4根線表示,即位寬是4位。編輯模式下輸入“Reg4”調(diào)用至簡設(shè)計法模板,補充完整后得到代碼表示如下:

add_cnt0和end_cnt0都是用assign方式設(shè)計的,因此類型為wire。其值是0或者1,用1根線表示即可。編輯模式下輸入“Wire1”調(diào)用模板,得到代碼表示如下:

add_cnt1和end_cnt1也是用assign方式設(shè)計的,因此類型為wire。其值是0或者1,用1根線表示即可,其代碼如下:

flag_add是用always方式設(shè)計的,因此類型為reg。其值是0或者1,用1根線表示即可。編輯模式下輸入“Reg1”調(diào)用模板,得到代碼如下:

rx_uart_ff0、rx_uart_ff1和rx_uart_ff2也都是用always方式設(shè)計的,因此類型為reg。并且其值是0或1,需要1根線表示即可。編輯模式下輸入“Reg1”調(diào)用模板,得到代碼表示如下:

至此,整個代碼的設(shè)計工作已經(jīng)完成,完整的工程代碼如下:

?未完,請看3.4串口通信-明德?lián)P至簡設(shè)計法原理與應(yīng)用(2)