按键扫描

该模块包含按键消抖,输入按键的引脚状态,输出

module KeyScan(
    input       clk,
    input       rst_n,

    input [3:0] KEY,              //按键输入

    output reg [3:0] KEY_state   //每个按键是否按下的状态   
);


parameter KEY_DELAY_COUNT = 20'd5; //按键延时消抖的常量,定义10MS需要计数500_000,这里仿真只是使用5个周期代替,实际的时候自行修改

reg  [19:0] count;           //仿真查看延时计数值
reg  [1:0]  key_down_state;       //仿真按键当前是否按下的状态

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        key_down_state <= 'd0;               //状态标志位清零
        KEY_state <= 'b1111;      //状态标志位复位  
    end
    else
    begin
        //状态标志位为0同时有按键按下的时候
        if(key_down_state == 'd0 && KEY != 'b1111)
        begin
            //将状态标志位置1
            key_down_state <= 'd1;
        end
        //等待延时计数值到达设定值
        else if(key_down_state == 'd1 && count == KEY_DELAY_COUNT)
        begin
            //将状态标志位置2
            key_down_state <= 'd2;
            //将按键状态值获取,这是延时后的状态,是按下后的状态值,这个状态值只会存在一个周期,因为下一个周期就会被最后一个else将将状态标志位复位
            //所以按键按下的状态只会保存一个周期
            KEY_shang_state  <= KEY_shang;
            KEY_jin_state    <= KEY_jin;
            KEY_que_ren_state<= KEY_que_ren;
        end
        //当全部按键抬起的时候,将状态标志位置0,就又可以检测按键是否按下了
        else if(key_down_state == 'd2 && KEY == 'b1111 )
            key_down_state <= 'd0;
        //其他情况将状态标志位复位
        else
        begin
            KEY_state  <= 'b1111;
        end
    end
end

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            count <= 'd0;
        end
    else
        begin
            //按键计数值到了指定数,清零
            if(count == KEY_DELAY_COUNT)
                count <= 'd0;
            //按键状态处于状态1,开始延时计数
            else if(key_down_state == 'd1)
                count <= count + 'd1;
            else 
                count <= count;
        end
end

endmodule