<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 深入而全面:FPGA學(xué)習(xí)之獨立按鍵檢測

          深入而全面:FPGA學(xué)習(xí)之獨立按鍵檢測

          作者: 時間:2017-10-21 來源:網(wǎng)絡(luò) 收藏

            幾乎沒有哪一個系統(tǒng)沒有輸入輸出設(shè)備,大到顯示器,小到led燈,輕觸按鍵。作為一個系統(tǒng),要想穩(wěn)定的工作,輸入輸出設(shè)備的性能占了很重要的角色。本實驗,小梅哥就通過一個獨立按鍵的檢測實驗,來正式步入基本外設(shè)驅(qū)動開發(fā)的大門。

          本文引用地址:http://www.ex-cimer.com/article/201710/366956.htm

            一、 實驗?zāi)康?/strong>

            實現(xiàn)4個獨立按鍵的抖動檢測實驗,并通過4個獨立按鍵控制4個led燈亮滅狀態(tài)的翻轉(zhuǎn)。

            二、 實驗原理

            實際系統(tǒng)中常用的按鍵大部分都是輕觸式按鍵,如圖2-1所示。該按鍵內(nèi)部由一個彈簧片和兩個固定觸點組成,當(dāng)彈簧片被按下,則兩個固定觸點接通,按鍵閉合。彈簧片松開,兩個觸點斷開,按鍵也就斷開了。根據(jù)這種按鍵的機械特性,在按鍵按下時,會先有一段時間的不穩(wěn)定期,在這期間,兩個觸點時而接通,時而斷開,我們稱之為抖動,當(dāng)按鍵大約按下20ms后,兩個觸點才能處于穩(wěn)定的閉合狀態(tài),按鍵松開時和閉合時情況類似。而我們的工作在很高的頻率,按鍵接通或斷開時任何一點小的抖動都能輕易的捕捉到,如果不加區(qū)分的將每一次閉合或斷開都當(dāng)做一次按鍵事件,那么勢必一次按鍵動作會被識別為很多次按鍵操作,從而導(dǎo)致系統(tǒng)工作穩(wěn)定性下降。

            

            圖2-1 輕觸按鍵實物圖

            一次按鍵動作的大致波形如下圖所示:

            因此,我們所需要做的工作,就是濾除按鍵按下和釋放時各存在的20ms的不穩(wěn)定波形

            三、 硬件設(shè)計

            獨立按鍵屬于一種輸入設(shè)備,其與連接的IO口被接上了10K的上拉電阻,在按鍵沒有按下時,F(xiàn)PGA會檢測到高電平;當(dāng)按鍵按下后,F(xiàn)PGA的IO口上則將呈現(xiàn)低電平。因此,按鍵檢測的實質(zhì)就是讀取FPGA的IO上的電平。

            

            圖3-1 獨立按鍵典型電路

            四、 架構(gòu)設(shè)計

            本實驗由總共四個模塊組成,分別為LED驅(qū)動模塊、獨立按鍵檢測模塊、控制模塊和頂層模塊,其架構(gòu)如下:

            

            圖4-1 led實驗?zāi)K組織結(jié)構(gòu)圖

            由圖可知本實驗有n個輸出端口,對應(yīng)驅(qū)動了n個led燈。n+2個輸入端口,對應(yīng)了n個按鍵輸入和一個時鐘輸入以及一個復(fù)位輸入。詳細端口名及其意義如下

            表4-1 獨立按鍵檢測實驗端口說明

            因為存在模塊間的連接,因此有部分內(nèi)部信號,下表為內(nèi)部信號的名稱和功能說明

            表4-2 獨立按鍵檢測實驗內(nèi)部信號說明

            五、 代碼組織方式

            本實驗中,按鍵檢測部分用到了狀態(tài)機,該狀態(tài)機包括兩個狀態(tài):按下消抖狀態(tài)和釋放消抖狀態(tài),詳細內(nèi)容將在關(guān)鍵代碼中進行講解,此處不做細致討論。

            實驗中還設(shè)計了一個控制器,該控制器主要進行按鍵事件與LED燈狀態(tài)的控制,通過讀取按鍵值,并根據(jù)按鍵信息翻轉(zhuǎn)對應(yīng)的LED的亮滅狀態(tài)。這部分內(nèi)容由于篇幅原因,不在文檔中寫出,請直接參看附件源代碼即可。

            LED的驅(qū)動采用實驗一的模塊,因此這里不進行過多的分析介紹。

            六、 關(guān)鍵代碼解讀

            以下為按鍵電平變化的檢測代碼,通過存儲前一次時鐘上升沿時的按鍵狀態(tài)和當(dāng)前時鐘上升沿時的按鍵狀態(tài),并比較兩次狀態(tài)是否相同,即可獲知是否有按鍵按下。

            以下為按鍵抖動檢測的代碼,采用狀態(tài)機的方式編寫,總共有兩個狀態(tài),按下消抖為狀態(tài)0,釋放消抖為狀態(tài)1。具體的消抖流程代碼中的注釋已經(jīng)寫的比較清楚,但如果全部用文字解釋出來還是有一定的復(fù)雜性。這也是實地講解和網(wǎng)上文檔的一點點差距吧,希望我后期的視頻里面能講清楚。其實抖動消除的核心思路就是對按鍵狀態(tài)的變化進行計時,若兩次電平變化之間時間小于20ms,則視為抖動,若低電平穩(wěn)定時間超過20ms,則表明檢測到了穩(wěn)定的按鍵狀態(tài)。釋放時的消抖過程與按下時的消抖過程類似。

            七、測試平臺設(shè)計

            本實驗主要對按鍵檢測的結(jié)果進行觀察和分析,通過仿真,驗證設(shè)計的正確性和合理性。按鍵消抖模塊的testbench的代碼如下:

            testben中使用了一個任務(wù)(task),該任務(wù)模擬按鍵抖動的過程,給按鍵按下和釋放時增加抖動,調(diào)用時只需要輸入需要按下的按鍵編號,該任務(wù)便可自動完成按下抖動、穩(wěn)定、松開抖動的過程。

            整個工程的testbench與消抖模塊的testbench一樣,只需要在例化部分將消抖模塊替換為頂層模塊,同時將每個按鍵的任務(wù)由一次調(diào)用該為兩次調(diào)用即可,詳細請參考附件代碼。

            八、 仿真分析

            由上圖仿真結(jié)果可知,當(dāng)有按鍵按下時,需要較長一段時間后,Key_Flag會有一個高電平脈沖,同時Key_Value更新為輸入按鍵的反碼。

            為了確定消抖是成功的,這里再附上按鍵松開時的抖動細節(jié)圖:

            由圖可知,松開按鍵時,該按鍵IO不斷的檢測到高電平和低電平,直到一段時間和,抖動方停止,穩(wěn)定為按鍵沒有按下時的狀態(tài)

            下圖為整個工程的仿真結(jié)果,由圖可知,每按下一次按鍵0(key_in[0]),led[0]的狀態(tài)便翻轉(zhuǎn)一次。

            九、 下板驗證

            手頭暫無開發(fā)板,板級驗證略。

            十、 總結(jié)

            本文檔對按鍵消抖的原理進行了分析,并對消抖核心模塊的設(shè)計進行了仿真,通過modelsim仿真驗證了消抖模塊設(shè)計的正確性。

            具體的控制模塊這里因為篇幅和時間關(guān)系暫不介紹,也因為沒有開發(fā)板,暫時無法錄制演示視頻,等錄制視頻時,我會對整個系統(tǒng)的架構(gòu)設(shè)計,代碼設(shè)計進行詳細的分析和講解。以前沒有做過不知道,寫了兩三次后才發(fā)現(xiàn),原來文檔的編寫和整理比編寫代碼要的時間要多的多。不過,我總還是會堅持做下去的,希望我能有足夠的時間來做這些事。



          關(guān)鍵詞: FPGA

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();