FPGA设计——按键去抖

按键的去抖,是指按键在闭合或者松开的瞬间伴随一连串的抖动,这样的抖动将直接影响设计系统的稳定性,降低相应的灵敏度。因此,必须对抖动进行处理,及消除抖动的影响。在实际工程中有很多消抖的方案,如RS触发器消抖,电容充放电消抖,软件消抖。本章利用FPGA内部来设计消抖,即采用软件消抖。

按键的机械特性,决定着按键的抖动时间,一般抖动时间在5ms~10ms。消抖,也意味着,每次在按键闭合或者松开期间,跳过这段抖动时间,在检测按键的状态。只要通过简单的延时就可以实现按键的消抖。

1.1硬件介绍

本设计有两个用户按键分别为BTN0和BTN1。BTN0用来复位,BTN1用来控制四个用户led。BTN1每按一次,对应的LED灯反转一次。即检测按键是否有闭合和断开的过程,如果有,第一次则LED灯点亮,第二次,则LED灯熄灭。

1.2 时序设计

由于按键固有的特性,在每次闭合和断开时,经过抖动-稳定-抖动-稳定的过程。因此,检测按键是否有按下的过程,则需要进行两次消抖处理。通过检测按键输入的值,当检测到BTN1为低电平时,启动计数器,做10ms延时,在检测一次,若BTN1依然为低,则说明,BTN1被按下,设置按键按下标志(low_flag)。在检测BTN1,若BTN1为高,做10ms延迟,第二次检测,若依然为高电平,则说明BTN1已断开,设置BTN1断开标志(high_flag)。通过这两个标志位,可以判断,BTN1已经完成了一次闭合到断开的过程,则led反转一次。

采用状态机实现上面的流程是非常的方便的。通过状态机的切换,按键每次由闭合到断开的过程中,分别产生low_flag和high_flag,当这两个标志同时为高时,led灯反转一次。

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/10/22 21:07:25
// Design Name: 
// Module Name: key_jitter
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module key_jitter(
    input   clk_i,
    input   rst_n_i,
    input   key_i,
    output [3:0] led_o
    );
    
    localparam delay_param = 19'd499_999;
    
    reg [3:0] led_o_r;
    
    (*KEEP = "TRUE"*) reg [18:0] div_cnt;//10毫秒去抖时间计数器
    
    always@ (posedge clk_i or negedge rst_n_i)
    begin
        if(!rst_n_i) 
            div_cnt <= 19'd0;
        else if (div_cnt< delay_param)
            div_cnt <= div_cnt + 1'b1;
        else
            div_cnt <= 0;
    end
    
    wire    delay_10ms =(div_cnt==delay_param)?1'b1:1'b0;
    //按键检测
    localparam detecter1  = 3'b000;
    localparam detecter2  = 3'b001;
    localparam detecter3  = 3'b010;
    localparam detecter4  = 3'b011;
    localparam led_dis  = 3'b100;
        
    reg low_flag;
    reg high_flag;
    reg [2:0] key_state;
    
    always @(posedge clk_i or negedge rst_n_i)
    begin
        if(!rst_n_i)
            begin
                key_state<= detecter1;
                low_flag <= 0;
                high_flag <= 0;
                led_o_r <=4'b1111;       
            end
        else if(delay_10ms)
            begin
                case(key_state)
                    detecter1:
                        begin
                            if(key_i!=1'b1)
                                key_state <= detecter2;
                            else
                                key_state <= detecter1;
                        end
                    detecter2:
                        begin
                            if(key_i!=1'b1)
                                begin
                                    low_flag <= 1'b1;
                                    key_state <= detecter3;
                                end
                            else
                                begin
                                    key_state <= detecter1;
                                    low_flag <= low_flag;
                                end
                        end
                    detecter3:
                        begin
                            if(key_i==1'b1)
                                key_state <= detecter4;
                             else
                                key_state <= detecter3;
                        end
                    detecter4:
                        begin
                            if(key_i == 1'b1)
                                begin
                                    high_flag <= 1'b1;
                                    key_state <= led_dis;
                                end
                             else
                                begin
                                    high_flag <= high_flag;
                                    key_state <= detecter3;
                                end
                        end
                     led_dis:
                        begin
                            if(high_flag & low_flag)
                                begin
                                    key_state <= detecter1;
                                    led_o_r <= ~led_o_r;
                                    high_flag <= 1'b0;
                                    low_flag <= 1'b0;
                                end
                             else
                                begin
                                    led_o_r <=led_o_r;
                                    key_state <= key_state;
                                    high_flag <= high_flag;
                                    low_flag <= low_flag;
                                end
                        end
                    default:
                        begin
                            key_state <= detecter1;
                            led_o_r <= 0;
                            high_flag <= 0;
                            low_flag <= 0;
                        end
                endcase
            end
        else
            begin
                led_o_r <=led_o_r;
                key_state <= key_state;
                high_flag <= high_flag;
                low_flag <= low_flag;    
            end           
    end
        
 assign led_o = led_o_r;
 
endmodule

1.4 程序分析

程序中定义了div_cnt 计数器,实现10ms消抖延时操作;

程序中定义了key_state一段式状态机,该状态机包括5个状态。其中前4个位按键闭合与断开检测,在完成前4个状态后,通过led灯的反转来表现按键的闭合与断开。

程序中定义了两个标志位,分别位low_flag和high_flag。low_flag表示检测到按键按下,high_flag表示检测到按键弹起。当两个标志同时为1时,表示按键完成一次闭合与断开。

程序中,对状态机做了循环,来回不停检测按键状态,且每次状态的切换时间是10ms,状态的切换时间,也是按键消抖的过程。

你可能感兴趣的:(FPGA设计)