问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

独立按键消抖

创作时间:
作者:
@小白创作中心

独立按键消抖

引用
CSDN
1.
https://blog.csdn.net/m0_66619666/article/details/140571047

独立按键消抖(Debouncing)是电子设备中对按键操作信号进行处理的重要技术,用于消除机械开关接触不良导致的多次触发信号。本文详细介绍了独立按键消抖技术的原理、实现方法和代码验证过程,通过有限状态机理论设计了一个独立按键消抖模块,具有很高的实用价值和参考价值。

前言

独立按键消抖(Debouncing)是指在电子设备中对按键操作信号进行处理,以消除由于机械开关接触不良导致的多次触发信号。机械按键在按下和释放时可能会产生短暂的接触不稳定,导致多个信号被误读。消抖技术可以确保每次按键操作只被识别为一次有效的输入,提高系统的稳定性和可靠性。消抖技术可以防止因为按键抖动产生的重复信号,避免了由于抖动引起的误操作。例如,一个按键被按下时,系统可能会错误地认为按键被按了多次,导致不必要的功能触发。通过消抖处理,按键的响应更加准确和一致,用户在操作设备时不会因为信号错误而感到困惑或不满意,从而提升整体用户体验。常见的消抖方法有硬件消抖(使用电容、RC电路等)和软件消抖(通过编程实现延迟判断、状态监测等)。选择适当的消抖方法取决于具体的应用需求和系统设计。

正文

一、独立按键消抖

1.项目需求

利用有限状态机理论,设计并验证对开发板上集成的独立按键进行消抖处理,使其产生一个标志信号flag表示对按键进行一次操作,同时也产生一个使能信号key_en表示按键稳定保持在低电平。

2.技术介绍

将对按键进行一次操作划分为四个状态,分别为:空闲状态,下抖动状态,稳定状态,上抖动状态。

空闲到下抖动状态的条件为:检测到按键的电压值变化为0。下抖动状态到稳定状态的条件为:延时计数器cnt计数到最大值:假设我们对按键进行检测的时钟频率为1khz,那么最大值为:9;稳定状态到上抖动状态的条件为:检测到按键的电压值变化为1。上抖动状态到空闲状态的条件为:延时计数器cnt计数到最大值。

状态 执行动作

空闲 表示对按键没有操作

下抖动 表示刚开始对按键进行操作

稳定 标志信号flag只拉高一个驱动时钟周期

上抖动 表示对按键进行一次操作马上结束

状态转移图为:

3.顶层架构

cnt_freq模块为分频器,由于常用开发板时钟频率为50MHz,该时钟频率较快,为确保下抖动状态时不产生flag信号,需要一相对较慢的时钟信号,这里选用1kHz时钟信号。jitter_ctrl为独立按键消抖控制模块,利用三段式有限状态机完成消抖处理。

4.端口描述

clk 开发板时钟

rst_n 复位按键(低电平有效)

key 目标按键

flag 按键有效信号

key_en 输出使能(为1时输出有效)

二、代码验证

cnt_freq模块


module cnt_freq(  

    input clk,  

    input rst_n,  

    output reg clk_1khz  

);  

//计数目标信号半个周期0.5ms  

reg [14:0] cnt;  

//开发板时钟50MHz,目标信号1KHz  

//即50_000个时钟信号产生一个目标信号  

//需要的目标信号也是作为下个模块时钟信号  

//占空比50%,即记25_000个时钟信号使目标信号电平翻转一次  

parameter MAX = 15'd25_000;  

always @(posedge clk,negedge rst_n)  

begin  

    if(rst_n == 0)  

        cnt <= 15'd0;  

    else  

        if(cnt < MAX - 1)//记25_000个时钟信号  

            cnt <= cnt + 15'd1;  

        else  

            cnt <= 15'd0;  

end  

always @(posedge clk,negedge rst_n)  

begin  

    if(rst_n == 0)  

        clk_1khz <= 1'b0;  

    else  

        if(cnt == MAX - 1)  

            clk_1khz <= ~clk_1khz;//目标信号电平翻转  

        else  

            clk_1khz <= clk_1khz;  

end  

endmodule  

jitter_ctrl模块


//三段式  

module jitter_ctrl_v2(  

    input clk,  

    input rst_n,  

    input key,  

    output reg flag,  

    output reg key_en  

);  

reg [3:0] n_state;  

reg [3:0] c_state;  

parameter s0 = 4'b0001;//空闲状态  

parameter s1 = 4'b0010;//下抖动状态  

parameter s2 = 4'b0100;//稳定状态  

parameter s3 = 4'b1000;//上抖动状态  

reg [3:0] cnt;  

//FSM1  

always @(posedge clk,negedge rst_n)  

begin  

    if(rst_n == 0)  

        c_state <= s0;  

    else  

        c_state <= n_state;  

end  

//FSM2  

always @(*)//描述状态转移  

begin  

    if(rst_n == 0)  

        n_state <= s0;  

    else  

        case(c_state)  

            s0	:	begin  

                        if(key == 0)//默认按键低电平有效,即=0时按键按下  

                            n_state <= s1;  

                        else  

                            n_state <= s0;  

                    end  

            s1	:	begin  

                        if(cnt == 9)//延时计数器判断  

                            n_state <= s2;  

                        else  

                            n_state <= s1;  

                    end  

            s2	:	begin  

                        if(key == 1)//按键弹起,状态改变  

                            n_state <= s3;  

                        else  

                            n_state <= s2;  

                    end  

            s3	:	begin  

                        if(cnt == 9)//延时计数器判断  

                            n_state <= s0;  

                        else  

                            n_state <= s3;  

                    end  

            default	:	n_state <= s0;  

        endcase  

end  

//FSM3  

always @(posedge clk,negedge rst_n)//状态输出产生flag信号  

begin  

    if(rst_n == 0)  

        begin  

            cnt <= 4'd0;  

            flag <= 1'b0;  

            key_en <= 1'b0;  

        end  

    else  

        case(c_state)  

            s0	:	begin  

                        cnt <= 4'd0;  

                        flag <= 1'b0;  

                        key_en <= 1'b0;  

                    end  

            s1	:	begin  

                        if(cnt < 9)//驱动延时计数器  

                            cnt <= cnt + 4'd1;  

                        else  

                            cnt <= 4'd0;  

                        if(cnt == 9)//延时计数器记满,产生flag  

                            begin  

                                flag <= 1'b1;//flag只产生一个时钟周期  

                                key_en <= 1'b1; //输出使能  

                            end  

                        else  

                            begin  

                                key_en <= 1'b0;  

                                flag <= 1'b0;  

                            end  

                    end  

            s2	:	begin  

                        flag <= 1'b0;  

                        key_en <= 1'b1;  

                        cnt <= 4'd0;  

                    end  

            s3	:	begin  

                        flag <= 1'b0;//状态初始化,准备判断下次按键按下  

                        key_en <= 1'b0;  

                        if(cnt < 9)  

                            cnt <= cnt + 4'd1;  

                        else  

                            cnt <= 4'd0;  

                    end  

            default	:	begin  

                                cnt <= 4'd0;  

                                flag <= 1'b0;  

                                key_en <= 1'b0;  

                            end  

        endcase  

end  

endmodule  

顶层代码


module key_jitter(  

    input clk,  

    input rst_n,  

    input key,  

    output flag,  

    output key_en  

);  

wire clk_1khz;//定义连线  

cnt_freq #(.MAX(5)) cnt_freq_inst(//给分频计数器最大值改5,方便仿真  

            .clk(clk),  

            .rst_n(rst_n),  

            .clk_1khz(clk_1khz)  

);  

jitter_ctrl_v2 jitter_ctrl_inst(  

            .clk(clk_1khz),  

            .rst_n(rst_n),  

            .key(key),  

            .flag(flag),  

            .key_en(key_en)  

);  

endmodule  

仿真代码


`timescale 1ns/1ps  

module key_jitter_tb;  

    reg clk;  

    reg rst_n;  

    reg key;  

    wire flag;  

    wire key_en;  

key_jitter key_jitter_inst(  

            .clk(clk),  

            .rst_n(rst_n),  

            .key(key),  

            .flag(flag),  

            .key_en(key_en)  

);  

initial clk = 1;  

always #10 clk = ~clk;  

//模拟时钟周期为20ns,目标时钟由于分频计数器最值改5后,目标时钟变为200ns  

initial begin  

    rst_n = 0;  

    key = 1;  

    #200  

    rst_n = 1;  

    #200  

    key = 0;//模拟按键按下  

    #240//  

    key = 1;//模拟下抖动状态  

    #230//延时计数器启动  

    key = 0;  

    #213  

    key = 1;  

    #123  

    key = 0;//模拟稳定状态  

    #3000//230+213+123+1234 = 1800 = 200 * 9  

    //即在3000的第1234ns左右时,产生一个flag  

    key = 1;//模拟上抖动状态  

    #213  

    key = 0;  

    #123  

    key = 1;  

    #234  

    key = 0;  

    #231  

    key = 1;  

    #3000  

    $stop;  

end  

endmodule  

三、仿真验证

运行仿真

可以看到,有一个flag信号产生,调出中间信号分析:

flag产生一个时钟周期,满足设计要求

延时计数器记满9后,进入按键按下稳定状态,并且输出flag。

即在3000ns的第1234ns左右时,输出一个flag,满足仿真预设。

参考资料

按键消抖

简易按键消抖

本文原文来自CSDN

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号