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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > 小梅哥和你一起深入學(xué)習(xí)FPGA之獨(dú)立按鍵檢測(上)

          小梅哥和你一起深入學(xué)習(xí)FPGA之獨(dú)立按鍵檢測(上)

          作者: 時間:2015-03-28 來源:網(wǎng)絡(luò) 收藏

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

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

            一、 實(shí)驗(yàn)?zāi)康?/p>

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

            二、 實(shí)驗(yàn)原理

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

            

           

            圖2-1 輕觸按鍵實(shí)物圖

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

            

           

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

            三、 硬件設(shè)計

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

            

           

            圖3-1 獨(dú)立按鍵典型電路

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

            本實(shí)驗(yàn)由總共四個模塊組成,分別為LED驅(qū)動模塊、獨(dú)立模塊、控制模塊和頂層模塊,其架構(gòu)如下:

            

           

            

           

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

            以下是代碼片段:

            module normal_keys_detect #(parameter KEY_WIDTH = 4)

            (Clk,Rst_n,Key_in,Key_Flag,Key_Value);

            input Clk;

            input Rst_n;

            input [KEY_WIDTH-1:0]Key_in;

            output reg Key_Flag;

            output reg[KEY_WIDTH-1:0]Key_Value;

            reg [KEY_WIDTH-1:0]key_tmp,key_tmp1;

            reg [19:0]cnt1;

            reg state;

            wire level_change; /*按鍵狀態(tài)變化標(biāo)志信號*/

            localparam cnt1_TOP = 1_000_000;

            /*-------存儲按鍵狀態(tài)的上一個狀態(tài)---------------*/

            always @ (posedge Clk or negedge Rst_n)

            begin

            if(!Rst_n)

            begin

            key_tmp <= 'd0;

            key_tmp1 <= 'd0;

            end

            else

            begin

            key_tmp <= Key_in;

            key_tmp1 <= key_tmp;

            end

            end

            /*---通過比較按鍵上一個狀態(tài)和此時刻狀態(tài)來獲知按鍵狀態(tài)是否改變---*/

            assign level_change = (key_tmp == key_tmp1)?1'b0:1'b1;

            always @ (posedge Clk or negedge Rst_n)

            if(!Rst_n)

            begin

            cnt1 <= 20'd0;

            state <= 1'b0;

            Key_Value <= 4'b0000;

            Key_Flag <= 1'b0;

            end

            else

            begin

            case(state)

            0: /*按下檢測*/

            //沒有電平變化,且按鍵輸入狀態(tài)不全為1

            if(!level_change & key_tmp1 != {KEY_WIDTH{1'b1}})

            begin

            if(cnt1 == cnt1_TOP)/*計數(shù)滿消抖所需時間*/

            begin

            Key_Value <= ~Key_in;

            Key_Flag <= 1;

            cnt1 <= 0;

            state <= 1;

            end

            else

            cnt1 <= cnt1 + 1'b1;

            end

            else

            begin

            cnt1 <= 0;

            Key_Flag <= 0;

            state <= 0;

            end

            1:/*釋放檢測*/

            begin

            Key_Flag <= 0;

            /*沒有電平變化,且按鍵輸入狀態(tài)全為1*/

            if(!level_change & key_tmp1 == {KEY_WIDTH{1'b1}})

            begin

            if(cnt1 == cnt1_TOP)/*計數(shù)滿消抖所需時間*/

            begin

            cnt1 <= 0;

            state <= 0;

            end

            else

            cnt1 <= cnt1 + 1'b1;

            end

            else

            begin

            cnt1 <= 0;

            state <= 1;

            end

            end

            endcase

            end

            endmodule

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

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

            以下是代碼片段:

            `timescale 1ns/1ns

            module normal_keys_detect_tb;

            reg Clk;

            reg Rst_n;

            reg [3:0]Key_in;

            wire Key_Flag;

            wire [3:0]Key_Value;

            normal_keys_detect

            #(

            .KEY_WIDTH(4)

            )

            normal_keys_detect_inst1(

            .Clk(Clk),

            .Rst_n(Rst_n),

            .Key_in(Key_in),

            .Key_Flag(Key_Flag),

            .Key_Value(Key_Value)

            );

            initial begin

            Clk = 1;

            Rst_n = 0;

            Key_in = 4'b1111;

            #100;

            Rst_n = 1;

            press_key(0);

            #30000000;

            press_key(1);

            #30000000;

            press_key(2);

            #30000000;

            press_key(3);

            #30000000;

            $stop;

            end

            always #10 Clk = ~Clk;

            task press_key;

            input [1:0]Key;

            begin

            Key_in = 4'b1111;

            /*按下抖動*/

            #100 Key_in[Key] = 0;

            #200 Key_in[Key] = 1;

            #300 Key_in[Key] = 0;

            #400 Key_in[Key] = 1;

            #500 Key_in[Key] = 0;

            #600 Key_in[Key] = 1;

            #700 Key_in[Key] = 0;

            #800 Key_in[Key] = 1;

            #900 Key_in[Key] = 0;

            /*穩(wěn)定期*/

            #22000000;

            /*釋放抖動*/

            #100 Key_in[Key] = 1;

            #200 Key_in[Key] = 0;

            #300 Key_in[Key] = 1;

            #400 Key_in[Key] = 0;

            #500 Key_in[Key] = 1;

            #600 Key_in[Key] = 0;

            #700 Key_in[Key] = 1;

            #800 Key_in[Key] = 0;

            #900 Key_in[Key] = 1;

            end

            endtask

            endmodule

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

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

            以下是代碼片段:

            `timescale 1ns/1ns

            module top_tb;

            reg Clk;

            reg Rst_n;

            reg [3:0]Key_in;

            wire [3:0]Led;

            top top_inst(

            .Clk(Clk),

            .Rst_n(Rst_n),

            .Key_in(Key_in),

            .Led(Led)

            );

            initial begin

            Clk = 1;

            Rst_n = 0;

            Key_in = 4'b1111;

            #100;

            Rst_n = 1;

            press_key(0);

            #30000000;

            press_key(0);

            #30000000;

            press_key(1);

            #30000000;

            press_key(1);

            #30000000;

            press_key(2);

            #30000000;

            press_key(2);

            #30000000;

            press_key(3);

            #30000000;

            press_key(3);

            #30000000;

            $stop;

            end

            always #10 Clk = ~Clk;

            task press_key;

            input [1:0]Key;

            begin

            Key_in = 4'b1111;

            /*按下抖動*/

            #100 Key_in[Key] = 0;

            #200 Key_in[Key] = 1;

            #300 Key_in[Key] = 0;

            #400 Key_in[Key] = 1;

            #500 Key_in[Key] = 0;

            #600 Key_in[Key] = 1;

            #700 Key_in[Key] = 0;

            #800 Key_in[Key] = 1;

            #900 Key_in[Key] = 0;

            /*穩(wěn)定期*/

            #22000000;

            /*釋放抖動*/

            #100 Key_in[Key] = 1;

            #200 Key_in[Key] = 0;

            #300 Key_in[Key] = 1;

            #400 Key_in[Key] = 0;

            #500 Key_in[Key] = 1;

            #600 Key_in[Key] = 0;

            #700 Key_in[Key] = 1;

            #800 Key_in[Key] = 0;

            #900 Key_in[Key] = 1;

            end

            endtask

            endmodule

          fpga相關(guān)文章:fpga是什么


          可控硅相關(guān)文章:可控硅工作原理


          比較器相關(guān)文章:比較器工作原理


          led顯示器相關(guān)文章:led顯示器原理


          上拉電阻相關(guā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); })();