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

  • 相关阅读:
    使用C#实现DHT磁力搜索的BT种子后端管理程序+数据库设计(开源)
    便携版WinSCP在命令行下同步文件夹
    ffmpeg (ffprobe)分析文件关键帧时间点
    sqlite删除数据或者表后,回收数据库文件大小
    ubuntu 20.04下 freeswitch 配合 fail2ban 防恶意访问
    ffmpeg使用nvenc编码的结论记录
    PC版跑跑卡丁车 故事模式 亚瑟传说章节 卡美洛庆典 2阶段 心灵之眼 攻略
    There was an error loading or playing the video
    Nvidia RTX Voice 启动报错修复方法
    火狐浏览器 关闭跨域限制
  • 原文地址:https://www.cnblogs.com/yuphone/p/1684999.html
Copyright © 2011-2022 走看看