FPGA project - ax_debounce

This page is a note of FPGA key check.

`timescale 1ns / 1ps
//
// 
// Create Date: 2023/12/02 14:44:05
// Module Name: ax_debounce
// Tool Versions: Vivado2022.2
// 
//

module ax_debounce(
    input                   clk                 ,                   //system clock 50Mhz on board
    input                   rst_n               ,                   //reset input, low active
    
    input                   button_in           ,                   //button sign input
    output  reg             button_en                               //button sign output
);

parameter   N           =   32  ;                                   //time count wide
parameter   FREQ        =   50  ;                                   //clock frequency(Mhz)
parameter   MAX_TIME    =   20  ;                                   //delay time(ms)

localparam  TIMER_MAX_VAL   =   MAX_TIME * 1000 * FREQ;             //time count sign

//wire define
wire                        q_add               ;                   //button dithering add sign
wire                        q_reset             ;                   //signal keep sign

//reg define
reg                         DFF1                ;                   //the first reg to catch button_in
reg                         DFF2                ;                   //the second reg to catch button_in
reg                         button_out          ;                   //the first button dithering reg to catch sign 
reg                         button_out_d0       ;                   //the second button dithering reg to catch sign
reg [N-1 : 0]               q_reg               ;                   //button dithering time count reg
reg [N-1 : 0]               q_next              ;                   //together to q_reg in order to add button dithering time

//assign define
//if q_reg less than TIMER_MAX_VAL then q_add is high level
//if q_reg equal to TIMER_MAX_VAL then q_add is low level
assign  q_add = ~(q_reg == TIMER_MAX_VAL)   ;
//if signal changed then set q_reset high level
//if signal keep then q_reset is low level
assign  q_reset = (DFF1 ^ DFF2)               ;

always@(q_reset , q_add , q_reg) begin
    case({q_reset , q_add})
//if signal keep and q_reg equal to TIMER_MAX_VAL then q_reg stop add
        2'b00: begin
            q_next <= q_reg;
        end
//if signal keep and q_reg less than TIMER_MAX_VAL then q_reg add one        
        2'b01: begin
            q_next <= q_reg + 1'b1;
        end
//if any error happen empty reg q_next        
        default: begin
            q_next <= {N{1'b0}};
        end
    endcase
end

//use two reg DFF1 and DFF2 to catch the sigal from button_in
//load q_next into q_reg
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        DFF1 <= 1'b0;
        DFF2 <= 1'b0;
        q_reg <= {N{1'b0}};
    end
    else begin
        DFF1 <= button_in;
        DFF2 <= DFF1;
        q_reg <= q_next;
    end
end

//when finish button dithering load DFF2 to button_out
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        button_out <= 1'b1;
    end
    else if(q_reg == TIMER_MAX_VAL) begin
        button_out <= DFF2;
    end
    else begin
        button_out <= button_out;
    end
end

//indeed there two button dithering
//the first button dithering data in the button_out_d0 is low level
//when the second button dithering finish is load high level into button_out_d0
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        button_out_d0 <= 1'b1;
        button_en <= 1'b0;
    end
    else begin
        button_out_d0 <= button_out;
        button_en <= button_out_d0 & ~button_out;
    end
end

endmodule

Please follow me to understand this method.

As we all know we should catch the button edge change and check whether this is just a button dithering. So we need a cnt to count time when this singal is changed and if time count enough time we think this is a truly button click.

I use two regs DFF1 and DFF2 to catch sigal from button_in. If DFF1 is same to DFF2 means no edge change, q_reset will be 0(q_reset = DFF1 ^ DFF2). And whether button_in from 0 to 1 or 1 to 0, q_reset will be 1 and empty the time_cnt(q_reg). q_add means if q_reg is less than TIMER_MAX_VAL, it will be 1 and count time unless q_reg equal to TIMER_MAX_VAL.

Now you may could understand the code below.

//if q_reg less than TIMER_MAX_VAL then q_add is high level
//if q_reg equal to TIMER_MAX_VAL then q_add is low level
assign  q_add = ~(q_reg == TIMER_MAX_VAL)   ;
//if signal changed then set q_reset high level
//if signal keep then q_reset is low level
assign  q_reset = (DFF1 ^ DFF2)               ;

always@(q_reset , q_add , q_reg) begin
    case({q_reset , q_add})
//if signal keep and q_reg equal to TIMER_MAX_VAL then q_reg stop add
        2'b00: begin
            q_next <= q_reg;
        end
//if signal keep and q_reg less than TIMER_MAX_VAL then q_reg add one        
        2'b01: begin
            q_next <= q_reg + 1'b1;
        end
//if any error happen empty reg q_next        
        default: begin
            q_next <= {N{1'b0}};
        end
    endcase
end

//use two reg DFF1 and DFF2 to catch the sigal from button_in
//load q_next into q_reg
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        DFF1 <= 1'b0;
        DFF2 <= 1'b0;
        q_reg <= {N{1'b0}};
    end
    else begin
        DFF1 <= button_in;
        DFF2 <= DFF1;
        q_reg <= q_next;
    end
end

Now we need to think how can we output enable just for one cycle.

We know reg can storage sigal for a cycle, so we can use this to output.

//when finish button dithering load DFF2 to button_out
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        button_out <= 1'b1;
    end
    else if(q_reg == TIMER_MAX_VAL) begin
        button_out <= DFF2;
    end
    else begin
        button_out <= button_out;
    end
end

//indeed there two button dithering
//the first button dithering data in the button_out_d0 is low level
//when the second button dithering finish is load high level into button_out_d0
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        button_out_d0 <= 1'b1;
        button_en <= 1'b0;
    end
    else begin
        button_out_d0 <= button_out;
        button_en <= button_out_d0 & ~button_out;
    end
end

At first button_out and button_out_d0 both be 1, when we consider button is clicked 0 will be written in to button_out. However there is a cycle button_out is 0 but button_out_d0 is 1, and after this cycle button_out_d0 will be written 0 from button_out_d0. So sigal button_en just output one cycle.

This is a method in usual case to check button click I guess.

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值