基础项目基于尖峰脉冲的按键消抖程序设计讲解
Posted mengyi1989
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础项目基于尖峰脉冲的按键消抖程序设计讲解相关的知识,希望对你有一定的参考价值。
写在前面的话
我们通常所用的按键开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会马上断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了避免这种现象造成的干扰而作的措施就是按键消抖。
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保智能单元对按键的一次闭合仅作一次处理,必须消除键抖动。在按键闭合稳定时读取键的状态,并且必须判别到按键释放稳定后再作处理。按键的消抖,可用硬件或软件两种方法,梦翼师兄这里主要介绍一下软件的消除方法。
基于尖峰脉冲的按键消抖
尖峰脉冲是电路设计中非常重要的一种信号,很多层次化设计中模块间的握手信号一般都会使用尖峰脉冲,正确的应用尖峰脉冲信号,可以有效的减少系统的逻辑冗余,提高系统稳定性和执行效率。本节,我们就来学习如何利用尖峰脉冲实现按键消抖。
项目需求
用一个按键控制数码管显示,数码管显示的数值为按键的次数,每按一次按键,数码管显示的数值加一,数值从0-F循环显示。
误区排除
由于数码管在之前的章节中已经有很详细的论述,所以这里我们忽略数码管驱动部分,把注意力放在按键次数的累加模块。说到这里,很多人的脑海中可能会出现下述代码:
always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin sum <= 1‘b0; //赋初值 end else begin if (!key_in) //有按键按下 sum <= sum + 1; //计数器加1 else sum <= sum; //计数值不变 end end |
这个always块的主要意思是如果检测到按键变为低电平,则说明有按键按下,然后就开始计数累加。这是最容易想到的一种错误方式,假设我们按键按下的时间特别长,那么key_in就会一直保持为低电平,我们的sum计数值也就会因此而不断累加。这与我们每按键一次,计数值只加一的目标是不相符的,而且这种方式并不能处理电路中遇到的抖动。
那么,我们该如何是好呢?分析上述电路,我们发现计数值不断累积加的原因在于每次按键按下,key_in都会保持多个周期的低电平。那么我们是否能产生这样一个信号呢-每次按键按下,不管按键时间如何,该信号能且仅能维持一个时钟周期的高电平。如果可以产生出这样的尖峰脉冲,那么我们就可以实现每次按键,计数值加且只加一的结果。
设计思路
为了证实上述想法的可行性,接下来我们设计流程图如下:
结构说明:当检测到有按键按下时,为了消除抖动,我们启动延时计数器,如果按键保持低电平的时间足够长,那么计数值一定会满足我们设置好的延时条件,否则计数清零,等待下次按键到来。如果延时计数满足条件,说明确定有按键按下,那么我们就可以输出一个尖峰脉冲,从而控制sum累加。
系统框架
顶层端口描述
端口名 |
端口说明 |
Clk |
系统50MHz时钟输入 |
rst_n |
系统低电平复位 |
key_in |
系统外部按键输入 |
Sum |
输出按键累加值 |
6.6.8 代码解释
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:按键消抖模块 *****************************************************/ 01 module pulse( 02 //系统输入 03 clk,//系统50MHZ时钟输入 04 rst_n,//低电平复位信号输入 05 key_in,//外部按键输入 06 //系统输出 07 sum//按键次数计数器 08 ); 09 10 //-----------------系统输入--------------------- 11 input clk;//系统50MHZ时钟输入 12 input rst_n;//低电平复位信号输入 13 input key_in;//外部按键输入 14 15 //-----------------系统输出--------------------- 16 output reg [3:0]sum;//按键次数计数器 17 18 //------------------寄存器定义------------------ 19 reg [10:0]counter;//消抖延时计数器 20 reg state;//状态寄存器 21 reg pos_flag;//尖峰脉冲寄存器 22 23 //----------按键消抖以后产生尖峰脉冲------------ 24 always@(posedge clk or negedge rst_n) 25 begin 26 if(!rst_n) 27 begin 28 counter<=0; //消抖延时计数器清零 29 state<=0; //状态寄存器清零 30 pos_flag<=0;//尖峰脉冲寄存器清零 31 end 32 else 33 begin 34 case(state) 35 0:begin 36 if(counter<10)//消抖延时计数器未开始计数 37 begin /*key_in==0,说明有按键按下*/ 38 if(!key_in) 39 begin 40 /*消抖延时计数器开始计数*/ counter<=counter+1; 41 end 42 //key_in==1,说明按键放开,而此时计数值未满, 43 //说明刚才的“按键”是抖动 44 else 45 begin 46 /*消抖延时计数器清零*/ counter<=0; 47 end 48 end 49 else//计数值满,说明确定有按键按下 50 begin 51 //尖峰脉冲寄存器置为高电平 52 pos_flag<=1; 53 counter<=0;//消抖延时计数器清零 54 state<=1;//跳转到下一状态 55 end 56 end 57 1:begin 58 pos_flag<=0;//尖峰脉冲寄存器置为低电平 59 //key_in==1,说明按键放开(一次按键动作完整结束) 60 if(key_in) 61 state<=0;//状态返回,等待下次按键到来 62 end 63 default:state<=0;//状态返回 64 endcase 65 end 66 end 67 //-----------------------累计尖峰脉冲出现次数----------------------- 68 always@(posedge clk or negedge rst_n) 69 begin 70 if(!rst_n) 71 begin 72 sum<=0;//按键计数器清零 73 end 74 else 75 begin 76 if(pos_flag)//尖峰脉冲到来,说明按键按下 77 sum<=sum+1;//按键计数器累加 78 end 79 end 80 endmodule |
当检测到有按键按下时,延时计数器开始计数,在计数的这段时间如果检测到按键是放开的,我们认为是按键抖动,计数器清零,等待下一次的按键按下,如果按键一直按下并满足我们预先设置的最大计数值,我们认为是真正有按键按下,延时计数器清零,pos_flag 信号拉高,状态向下跳转。在下一个状态 pos_flag 信号拉低,如果检测到按键放开,状态跳转到上一个状态等待下一次按键按下。这样就产生了一个周期的尖峰脉冲。从第68行到结束,当检测到一个尖峰脉冲的时候,按键计数器加1。
编写测试代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:按键消抖测试模块 *****************************************************/ 01 `timescale 1ns/1ps 02 03 module tb; 04 05 //-----------------------系统输入----------------------- 06 reg clk;//系统50MHZ时钟输入 07 reg rst_n;//低电平复位信号输入 08 reg key_in;//外部按键输入 09 10 //-----------------------系统输出----------------------- 11 wire [3:0]sum;//按键次数计数器 12 13 //-----------------------产生测试激励------------------- 14 initial 15 begin 16 clk=0; 17 rst_n=0; 18 key_in=1; 19 # 1000.1 rst_n=1; 20 //-------------------模拟按键动作------------------- 21 # 1000 key_in=0; 22 # 1000 key_in=1; 23 # 100 key_in=0; 24 # 100 key_in=1; 25 # 300 key_in=0; 26 # 300 key_in=1; 27 # 100 key_in=0; 28 # 200 key_in=1; 29 # 1000 key_in=0; 30 # 900 key_in=1; 31 # 1000 key_in=0; 32 # 800 key_in=1; 33 # 1000 key_in=0; 34 # 1000 key_in=1; 35 //---------------------------------------------- 36 end 37 38 always #10 clk=~clk;//50MHZ晶振 39 40 //----------------实例化被测试模块---------------- 41 pulse pulse ( 42 //系统输入 43 .clk(clk),//系统50MHZ时钟输入 44 .rst_n(rst_n),//低电平复位信号输入 45 .key_in(key_in),//外部按键输入 46 //系统输出 47 .sum(sum)//按键次数计数器 48 ); 49 endmodule |
仿真分析
我们再放大标示线区域:
由上述波形可以看出,当按键按下以后,计数器首先开始计数,当计数值不满足时,计数器清零并等待下一次按键按下。当计数值满足以后,才会输出一个时钟周期的尖峰脉冲,而按键次数寄存器sum也会在尖峰脉冲的作用下开始累加。每次按键按下,只会出现一次尖峰脉冲,说明我们的设计是正确的。
注:本设计中,我们只是消除了按键按下时候的抖动,而按键放开时候的抖动我们并没有处理,梦翼师兄希望大家可以自行将改代码填充完整。
以上是关于基础项目基于尖峰脉冲的按键消抖程序设计讲解的主要内容,如果未能解决你的问题,请参考以下文章
09B-独立按键消抖实验02——小梅哥FPGA设计思想与验证方法视频教程配套文档