新聞中心

        EEPW首頁 > 嵌入式系統 > 牛人業話 > 小梅哥和你一起深入學習FPGA之獨立按鍵檢測(上)

        小梅哥和你一起深入學習FPGA之獨立按鍵檢測(上)

        作者: 時間:2015-03-28 來源:網絡 收藏

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

        本文引用地址:http://www.104case.com/article/271738.htm

          一、 實驗目的

          實現4個獨立按鍵的抖動檢測實驗,并通過4個獨立按鍵控制4個led燈亮滅狀態的翻轉。

          二、 實驗原理

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

          

         

          圖2-1 輕觸按鍵實物圖

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

          

         

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

          三、 硬件設計

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

          

         

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

          四、 架構設計

          本實驗由總共四個模塊組成,分別為LED驅動模塊、獨立模塊、控制模塊和頂層模塊,其架構如下:

          

         

          

         

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

          以下是代碼片段:

          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; /*按鍵狀態變化標志信號*/

          localparam cnt1_TOP = 1_000_000;

          /*-------存儲按鍵狀態的上一個狀態---------------*/

          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

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

          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: /*按下檢測*/

          //沒有電平變化,且按鍵輸入狀態不全為1

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

          begin

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

          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;

          /*沒有電平變化,且按鍵輸入狀態全為1*/

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

          begin

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

          begin

          cnt1 <= 0;

          state <= 0;

          end

          else

          cnt1 <= cnt1 + 1'b1;

          end

          else

          begin

          cnt1 <= 0;

          state <= 1;

          end

          end

          endcase

          end

          endmodule

          七、 測試平臺設計

          本實驗主要對的結果進行觀察和分析,通過仿真,驗證設計的正確性和合理性。按鍵消抖模塊的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;

          /*穩定期*/

          #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中使用了一個任務(task),該任務模擬按鍵抖動的過程,給按鍵按下和釋放時增加抖動,調用時只需要輸入需要按下的按鍵編號,該任務便可自動完成按下抖動、穩定、松開抖動的過程。

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

          以下是代碼片段:

          `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;

          /*穩定期*/

          #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相關文章:fpga是什么


        可控硅相關文章:可控硅工作原理


        比較器相關文章:比較器工作原理


        led顯示器相關文章:led顯示器原理


        上拉電阻相關文章:上拉電阻原理


        關鍵詞: FPGA 按鍵檢測

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 台湾省| 体育| 铜川市| 麻栗坡县| 庄河市| 广饶县| 油尖旺区| 天峻县| 瓮安县| 新田县| 开平市| 安福县| 新民市| 合水县| 林州市| 行唐县| 舞钢市| 焉耆| 舟山市| 五寨县| 莱州市| 天柱县| 吐鲁番市| 新巴尔虎右旗| 缙云县| 新建县| 佛冈县| 南溪县| 和政县| 宜良县| 班戈县| 尼玛县| 金阳县| 天柱县| 化州市| 东宁县| 宣化县| 东方市| 遂平县| 页游| 扶风县|