关于按键消抖实验的疑问

2019-07-15 23:54发布

//说明:按键消抖实验
//当三个独立按键的某一位被按下后,相应的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后再检测应该是稳定的;也就实现了这个功能,大家觉得我理解的对不对?

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
9条回答
泛爱不懂
1楼-- · 2019-07-16 18:33
来确认按下之后是稳定的状态啊
y990441
2楼-- · 2019-07-16 18:34
你觉得如果是理想的按键(也就是完全没有抖动),你要不要做边沿检测?要吧,第二个边沿检测就是用来干这个的。
dybttkl
3楼-- · 2019-07-16 19:16
第一个应该是分频,第二个是双寄存器防亚稳态

一周热门 更多>