FPGA基础入门篇(六) 按键防抖电路实现(一)

FPGA基础入门篇(六) 按键防抖电路实现
本次实验的按键消抖电路实现用Zynq 7000 系列的FPGA实现,时钟频率为500MHz, 按键消抖延时为20ms。
此次电路的实现涉及到如下过程:

  1. 按键作为异步信号输入,需要进行同步处理。可以采用两级以上的异步复位,同步释放的dff进行时钟同步处理。(异步复位,同步释放,可利用多级边沿检测电路
  2. 根据抖动时间和时钟周期,确定计数器位宽:20ms。

关于防抖电路实现的具体例程和用其他方法实现:

具体例程:FPGA基础入门篇(六) 按键防抖电路实现(二)
其他实现方法:FPGA基础入门篇(六) 按键防抖电路实现(三)

一、抖动的产生

按键的示意图如下,一般为低电平有效,当按键由高电平转向低电平的瞬间会有短暂的高阻态,因此电路需要RS触发器存储电路保存电路的当前状态。但是实际的按键并不是理想的按键,当按键按下时中间会产生抖动状态,即产生脉冲的干扰。
FPGA基础入门篇(六) 按键防抖电路实现(一)_第1张图片
抖动的信号如下所示:
FPGA基础入门篇(六) 按键防抖电路实现(一)_第2张图片

二、消抖的方式
  1. Verilog 代码设计实现
module key(
input clk_i, rst_n_i, key_i,
output reg key_state,
output reg key_flag

);

//parameter for satate machine
parameter S1 = 2'b00;   //key=1
parameter S2 = 2'b01;
parameter S3 = 2'b11;
parameter S4 = 2'b10;

//key_edge detect module 边沿检测电路模块。
//
wire data_i;
reg tri_1;
reg tri_2;
wire negedge_o;
wire posedge_o;

always@(posedge clk_i or negedge rst_n_i)
begin
    if (! rst_n_i)
    begin
        tri_1 <= 1'b0;
        tri_2 <= 1'b0;
    end
    else
    begin
        tri_1 <= data_i;
        tri_2 <= tri_1;
    end
end

assign negedge_o = tri_2 & (~tri_1);    // neg_edge detect
assign posedge_o = (~tri_2) & tri_1;    // pos_edge detect
assign data_i = key_i;

//counter module 计数器模块
//
reg [19:0]cnt;
reg en_cnt;     //the enable signal start
reg count_full; //the flag of count is 20ms 
//count
always@(posedge clk_i or negedge rst_n_i)
begin
    if(!rst_n_i)        
        cnt <= 20'b0;
    else if (en_cnt)
        cnt <= cnt + 1'b1;
    else if(count_full)     //2nd set
        cnt <= 20'b0;
    else
        cnt <= 20'b0;   
end
//count_full flag
always@(posedge clk_i or negedge rst_n_i)
begin
    if(!rst_n_i)
    begin
        count_full <= 1'b0;
    end
    else if (cnt == 20'd3_999_999)
            count_full <= 1'b1;
    else
            count_full <= 1'b0;
end

//state machine 状态机模块
//
reg [1:0]state;
//
always@(posedge clk_i or negedge rst_n_i)
begin
    if (!rst_n_i)
    begin 
        en_cnt <= 1'b0;
        state <= S1;
        key_state <= 1'b1;
        key_flag <=  1'b0;
    end
    else
    begin
        case (state)
                S1:     //IDLE 空闲状态
                begin
                    key_state <= 1'b1;
                    key_flag <=  1'b0;
                    if (negedge_o)
                    begin 
                        state <= S2;
                        en_cnt <= 1'b1;
                    end
                    else
                        state <= S1;
                end
                
                S2:     //filter 按下滤波状态等待20ms延时
                begin
                    if (count_full)
                    begin
                        key_state <= 1'b0;
                        key_flag <= 1'b1;
                        en_cnt <= 1'b0;
                        state <= S3;
                    end
                    else if (posedge_o)
                    begin
                        state <= S1;
                        en_cnt <= 1'b0;
                    end
                    else
                        state <= S2;
                end
                
                S3:		//	按下状态,等待抬起
                begin
                        key_flag <= 1'b0;
                        key_state <= 1'b0;
                    if (posedge_o)
                    begin
                        state <=  S4;
                        en_cnt <= 1'b1;
                    end
                    else
                        state <= S3;
                end
                
                S4:		//抬起状态,等待20ms延时
                begin
                    if (count_full)
                    begin
                        key_flag <= 1'b1;
                        key_state <= 1'b1;
                        en_cnt <= 1'b0;
                        state <= S1;
                    end
                    else if (negedge_o)
                    begin
                        state <= S3;
                        en_cnt <= 1'b0;
                    end
                    else
                        state <= S4;
                    
                end
            
                default:
                begin
                    en_cnt <= 1'b0;
                    state <= S1;
                    key_state <= 1'b1;
                    key_flag <=  1'b0;
                end
        endcase
      end
end
endmodule
  1. 测试代码:
`timescale 1ns / 1ps
//
module key_test(

    );

reg clk_i, rst_n_i,key_i;
wire key_state, key_flag;

//instance
key u1(
    .clk_i(clk_i), 
    .rst_n_i(rst_n_i),
    .key_i(key_i),
    .key_state(key_state), 
    .key_flag(key_flag)
);

initial
begin
    clk_i = 1;
    rst_n_i = 0;
    key_i = 1;
    #100
    rst_n_i =1;
    #20
    key_i=0;
    
    repeat(10)
    begin
            #100 key_i= ~key_i; 
    end

    #5000
    key_i=1;
    repeat(10)
    begin
            #100 key_i= ~key_i; 
    end
end

always begin
    #0.001 clk_i = ~ clk_i;
end


endmodule
  1. RTL仿真结果图:
    key_inkey_state 为滤波后的信号。即按键按下时(低电平有效),经过20ms延时,如果仍然低电平则确实是被按下;抬起时,经过20ms的延时仍然高电平,则确实被抬起。整体效果测试结果如下:
    仿真时钟周期采用2ps进行功能验证。
    FPGA基础入门篇(六) 按键防抖电路实现(一)_第3张图片
    当按键按下瞬间:
    FPGA基础入门篇(六) 按键防抖电路实现(一)_第4张图片
    抬起瞬间:
    FPGA基础入门篇(六) 按键防抖电路实现(一)_第5张图片

你可能感兴趣的:(数字IC设计-FPGA)