微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 关于按键消抖实验的疑问

关于按键消抖实验的疑问

时间:10-02 整理:3721RD 点击:
//说明:按键消抖实验
//当三个独立按键的某一位被按下后,相应的Led被点亮;
//再次按下后,LED熄灭,按键控制LED亮灭;//
//
module key_handle(
            clk_20M,rst_n,
            sw1_n,sw2_n,sw3_n,
            led_d1,led_d2,led_d3
              );
input clk_20M;  //主时钟信号,20MHz
input rst_n;//复位信号,低电平有效
input sw1_n,sw2_n,sw3_n;// 三个独立按键,低表示被按下
output led_d1,led_d2,led_d3;//发光二极管,分别由按键控制

//------------------------NOTE:两个寄存器不要放在一个always语句里面---------------------------------------
reg[2:0] key_rst; //对后面20ms计数器的一个复位的操作
always @(posedge clk_20M or negedge rst_n)
     if(!rst_n) key_rst <= 3'b111;
     else key_rst <= {sw3_n,sw2_n,sw1_n};
reg[2:0] key_rst_r; //每个时钟周期的上升沿将上次锁存的按键值key_rst锁存到key_rst_r中
always @(posedge clk_20M or negedge rst_n)
      if(!rst_n) key_rst_r <= 3'b111;
      else key_rst_r <= key_rst;
//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
wire [2:0] key_an;

assign key_an = key_rst_r & (~key_rst); //边沿检测技术
/*下面表示的一个按键的状态
key_rst    1 1 1 0 0 1  //按键从1变为0
~key_rst   0 0 0 1 1 0
key_rst_r    1 1 1 0 0 1
key_an       0 0 1 0 0  //key_an会变为1,且高电平保持一个时钟周期
*/
//-------------------------------------------------------
reg [19:0] cnt;//cnt用来计数20ms 2^20~=20ms;按键按下的时间差不多为20ms
always @(posedge clk_20M or negedge rst_n)
      if(!rst_n) cnt <= 20'd0;
      else if(key_an) cnt <= 20'd0;//如果检测到有键按下,那么就将计数器清0,从新开始计数
      else cnt <= cnt + 1'b1;
reg[2:0] low_sw;
always @(posedge clk_20M or negedge rst_n)
      if(!rst_n) low_sw <= 3'b111;
      else if (cnt == 20'hfffff)        // 每20ms将按键值锁存到寄存器low_sw中
         low_sw <= {sw3_n,sw2_n,sw1_n}; //这里存的值是稳定的(下一个脉冲的某一个时刻)
                                        //这个值是滤除抖动后的稳定值
//-----------------------------------------------------------
reg [2:0] low_sw_r;
always @(posedge clk_20M or negedge rst_n)
       if(!rst_n) low_sw_r <= 3'b111;
       else low_sw_r <= low_sw;            //每一个时钟采集一次low_sw的状态值
                                           //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
/*low_sw    111  111  111  110 110 110
~low_sw   000  000  000  001 001 001
low_sw_r       111  111  111 110 110 110
led_sw_r       000  000  001 000 000
*/

// 当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期     
wire[2:0] led_ctrl = low_sw_r[2:0] & (~low_sw[2:0]);      

//   --------------------------------------------------------
reg d1;
reg d2;
reg d3;

always @(posedge clk_20M or negedge rst_n)
      if(!rst_n) begin
          d1 <= 1'b0;
          d2 <= 1'b0;
          d3 <= 1'b0;
         end
       else begin                 ////某个按键值变化时,LED将做亮灭翻转
          if(led_ctrl[0]) d1<=~d1;
          if(led_ctrl[1]) d2<=~d2;
          if(led_ctrl[2]) d3<=~d3;
        end
assign led_d3 = d1 ? 1'b1:1'b0;    //LED翻转输出
assign led_d2 = d2 ? 1'b1:1'b0;
assign led_d1 = d3 ? 1'b1:1'b0;

endmodule
这是特权同学的程序代码,基本上我都能搞清楚是什么意思,low_sw是存放按键稳定后的按键值;心里老感觉模模糊糊的;就我自己理解的,首先用key_an来标志是否有键按下。有键按下,cnt计数器清零,这个键不管是正常按下还是抖动,计数20ms以后都应该是稳定的值low_sw;我不理解的地方就是第二个边沿检测是用来做什么的;按键消抖从软件上实现应该就是检测到按键按下后,一段时间20ms后再检测应该是稳定的;也就实现了这个功能,大家觉得我理解的对不对?

是的,可以这样理解~

可以解释一下第二个脉冲边沿检测是干嘛的不

可以解释一下第二个脉冲边沿检测是干嘛的不

最讨厌看那些没有一点注释的程序。

我这个勉强过得去吧

韦东山貌似是搞Arm-Linux的...

来确认按下之后是稳定的状态啊

你觉得如果是理想的按键(也就是完全没有抖动),你要不要做边沿检测?要吧,第二个边沿检测就是用来干这个的。

第一个应该是分频,第二个是双寄存器防亚稳态

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top