zoukankan      html  css  js  c++  java
  • [笔记].一种独立键盘消抖的Verilog写法

    图1 KEY原理图

    图1 KEY原理图

    图2 LED原理图

    图2 LED原理图

    key_led.v

    module key_led(
      input            CLOCK_50,
      input            Q_KEY,
      input      [4:1] KEY,
      output reg [4:1] LED
    );  
    
    //++++++++++++++++++++++++++++++++++++++
    // 获取键值 开始
    //++++++++++++++++++++++++++++++++++++++
    wire [4:1] key_val;                     // 键值
    
    key_debounce u0(
      .i_clk            (CLOCK_50),
      .i_rst_n          (Q_KEY),
      .i_key            (KEY),
      .o_key_val        (key_val)           // 按下为0,松开为1
    );  
    //--------------------------------------
    // 获取键值 结束
    //--------------------------------------
    
    
    //++++++++++++++++++++++++++++++++++++++
    // 按下键后开关LED 开始
    //++++++++++++++++++++++++++++++++++++++
    always @ (posedge CLOCK_50, negedge Q_KEY)
      if (!Q_KEY)
        LED <= 4'hF;                        // 0灭1亮
      else
        case (1'b0)
          key_val[1] : LED[1] <= ~LED[1];
          key_val[2] : LED[2] <= ~LED[2];
          key_val[3] : LED[3] <= ~LED[3];
          key_val[4] : LED[4] <= ~LED[4];
          default    : LED    <=  LED   ;   // 缺省亮灭情况不变
        endcase 
    //--------------------------------------
    // 按下键后开关LED 结束
    //--------------------------------------
    
    endmodule

    key_debounce.v

    module key_debounce(
      input            i_clk,
      input            i_rst_n,
      input      [4:1] i_key,               // 按下为0,松开为1
      output reg [4:1] o_key_val            // 键值
    );  
    
    //++++++++++++++++++++++++++++++++++++++
    reg [4:1] key_samp1, key_samp1_locked;
    
    // 将i_key采集至key_samp1
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n) 
        key_samp1 <= 4'hF;
      else         
        key_samp1 <= i_key;
    
    // 将key_samp1锁存至key_samp1_locked
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n) 
        key_samp1_locked <= 4'hF;
      else         
        key_samp1_locked <= key_samp1;
    //--------------------------------------
    
    //++++++++++++++++++++++++++++++++++++++
    wire [4:1] key_changed1;
    
    // 当key_samp1由1变为0时
    // key_changed1由0变为1,只维持一个时钟周期
    assign key_changed1 = key_samp1_locked & (~key_samp1); 
    //--------------------------------------
    
    
    //++++++++++++++++++++++++++++++++++++++
    reg [19:0] cnt;
    
    // 一旦有按键按下,cnt立即被清零
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n)
        cnt <= 20'h0;
      else if(key_changed1)
        cnt <= 20'h0;
      else
        cnt <= cnt + 1'b1;
    //--------------------------------------
    
    
    //++++++++++++++++++++++++++++++++++++++
    reg [4:1] key_samp2, key_samp2_locked;
    
    // 只有当按键不变化(不抖动),且维持20ms以上时
    // 才将i_key采集至key_samp2
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n)
        key_samp2 <= 4'hF;
      else if(cnt == 20'hF_FFFF)            // 0xFFFFF/50M = 20.9715ms
        key_samp2 <= i_key;
    
    // 将key_samp2锁存至key_samp2_locked
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n)
        key_samp2_locked <= 4'hF;
      else
        key_samp2_locked <= key_samp2;
    //--------------------------------------
    
    //++++++++++++++++++++++++++++++++++++++
    wire [4:1] key_changed2;
    
    // 当key_samp2由1变为0时
    // key_changed2由0变为1,只维持一个时钟周期
    assign key_changed2 = key_samp2_locked & (~key_samp2); 
    //--------------------------------------
    
    
    //++++++++++++++++++++++++++++++++++++++
    // 每次按键稳定后,输出键值
    // 按下为0,松开为1
    always @ (posedge i_clk, negedge i_rst_n)
      if(!i_rst_n)
        o_key_val <= 4'hF;
      else
        o_key_val <= ~key_changed2;
    //--------------------------------------
    
    endmodule 

    HDL思路

    3cdd09ff-062d-4e68-85e7-697eab9c0e22

    图3 按键抖动

    如图3所示,按键在按下和释放的时候都会有一定的抖动。本代码仅消除了按下抖动,没有对释放抖动进行处理。

    代码中使用了一个计数器来实现延时。只要这个计数器正常计数到20'hF_FFFF,我们就采样一个值key_samp2,并将其锁存进key_samp2_locked。一旦有下降沿来临,就输出按键改变值key_changed2。同时,该模块也在使用高频时钟i_clk不停地采集键值到key_samp1,并锁存进key_samp1_locked;一旦下降沿存在,输出按键变化值key_changed1,这样计数器就会被清零。假设没有key_changed1,我们将0xFFFFF/50M = 20.9715ms取样一次键值,并检测其下降沿,输出键值。但是由于抖动的原因,采用高频时钟i_clk采样的key_samp1就有可能导致key_changed1为一,进而使得低频的20.9715ms采样延时执行。也就是说,只有按键处于稳定的状态时,key_samp2才被正常采样,才有可能检测到key_changed2。

    参考资料

    1. 特权.基于verilog按键消抖设计

    http://group.ednchina.com/1375/21132.aspx

  • 相关阅读:
    【一月の飞雪】(小年快乐!)
    【十二月の博雅闻道】(元旦快乐!)
    【十一月の期中考试总结】
    【十月のA Letter to 后辈菌】
    【九月の文化课生活】(国庆快乐!)
    OI回忆录(流水账)
    SDOI 2017 Round2 滚粗了
    【BZOJ 3456】城市规划
    【Vijos 1998】【SDOI 2016】平凡的骰子
    【HDU 3662】3D Convex Hull
  • 原文地址:https://www.cnblogs.com/yuphone/p/1684999.html
Copyright © 2011-2022 走看看