知识图谱之波形设计举例

部署运行你感兴趣的模型镜像

 按键消抖

1.1  为什么需要按键消抖

如图所示,我们所使用的按键开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。原理如图所示

图 16-1

图 16-2

抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保控制器对按键的一次闭合仅作一次处理,必须去除按键的抖动。在按键闭合稳定时读取按键的状态,并且必须判别到按键释放稳定后再作处理。

消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响。按键的消抖,可用硬件或软件两种方法。

硬件消抖:

在按键个数较少时可用硬件方法消除键抖动。如图所示的RS触发器为常用的硬件去抖。图中两个与非门构成一个RS触发器。当按键未按下时,输出为0;当键按下时,输出为1。此时即使用按键的机械性能,使按键因弹性抖动而产生瞬时断开(抖动跳开B),只要按键不返回原始状态A,双稳态电路的状态不改变,输出保持为0,不会产生抖动的波形。也就是说,即使B点的电压波形是抖动的,但经双稳态电路之后,其输出为正规的矩形波。这一点通过分析RS触发器的工作过程很容易得到验证。

图 16-3

软件消抖:

如果按键个数较多,常用软件方法去抖,即检测出按键闭合后执行一个延时程序,根据抖动的时间为5ms~10ms,我们产生一个20ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。

1.2  按键去抖动的实现

1.2.1  功能简介

        前面已经分析了按键抖动的机理和消除按键抖动的几种方案,我们知道硬件消抖会使用一些额外的器件占用电路板上的空间,从而在一定程度上增加了PCB布局布线的复杂度,所以我们用软件消抖的方式来实现去抖动的操作,去抖动后的效果是当按键按被下后能够准确检测到按键被按下了一次,而不会因机械抖动发生按键重复多次按下的现象。

1.2.2  模块设计

        因为我们要计数过滤掉按键抖动的时间,所以计数器是必不可少的,所以我们设计的模块一定会用到时序电路,所以时钟sys_clk和复位sys_rst_n信号一定先加上,而且是输入信号,另外还有一个输入信号就是按键的输入key_in,我们最终要实现的就是对输入的key_in信号进行去抖动,输出信号为去抖动后的稳定的按键信号key_flag。根据上面的分析设计出的Visio框图如图 16-4所示。

图 16-4

端口列表与功能总结如表 16-1所示。

表 16-1

信号

位宽

类型

功能描述

sys_clk

1Bit

Input

工作时钟,频率50Mhz

sys_rst_n

1Bit

Input

复位信号,低电平有效

key_in

1Bit

Input

按键的输入

key_flag

1Bit 

Output

去抖后按键被按下的标志信号

1.2.3  波形设计

首先我们从实际问题出发,分析抖动的本质,再想办法去消除抖动。我们先把波形图的三个输入信号画好,抖动我们就模拟和真实中的情况一样,即当按键被按下和按键被释放时都会有抖动,也就是有前抖动和后抖动,这两种抖动都会对我们的设计产生一定的影响,会让我们的系统误判为按键被多次按下。我们需要做的就是要准确判断出稳定的按下的那一次状态。

图 16-5

按键的抖动会产生如图 16-5所示的毛刺,毛刺中会有低电平的情况,但是因为机械抖动的原因很快又回拉高了,如果我们把其中的每次的低电平和高电平都采集到,那么相当于是按键被按下了好多次,而不是我们想要的一次,所以我们一定要把这段抖动给滤除掉,这段抖动的时间我们通过前面的分析是已知的,抖动的时间是小于10ms的,而当有20ms的时间内都没有抖动就说明按键已经处于稳定状态了,也就是说我们可以做一个计数器来进行计数,计数20ms的时间,也就是说只要20ms的时间内都没有抖动产生,那结果是什么电平就是什么,我们需要做的是找到最后一次抖动的时间是在什么时候,才能够开启这20ms的计数,否则这20ms内不能够保证都是我们的安全时间。当然有的同学可能会说我在单片机的设计中都是检测第一次按键为低电平了就开始计数,然后延时一段大于30ms的时间后再检测得到的按键电平就是稳定的按键信号,难道这种方式不可以吗?这种方式虽然也是可以的,但不是最好的,因为这会浪费我们的不必要时间,也就是说虽然抖动的时间理论上不会大于10ms,但是具体是多少可能每次按键实验的结果都不相同,如果我们每次都按照最大的抖动时间10ms来计算无疑会“多”考虑了一些时间,所以我们采用一种更“节约”时间的方法,我们添加一个名为cnt_20ms用于计数20ms时间的计数器,每当系统检测到按键输入信号为低电平时cnt_20ms计数器就开始计数,在cnt_20ms计数器计数期间内,如果再次检测到按键为高电平则说明上次检测到的低电平一定是个抖动,那么我们就将这个计数器清零,总结为简单的一句话就是:当系统检测到按键为低电平时cnt_20ms计数器就计数,当检测到按键为高电平时cnt_20ms计数器就清零。讲到这里主要问题我们就已经解决了,然后要考虑cnt_20ms计数器计数个和计数满了后该怎么处理以及滤除抖动后的输出信号key_flag什么时候拉高、拉低的问题。

首先是考虑计数器的问题,根据我们使用的50Mhz的晶振来计算,cnt_20ms计数器计数20ms时间所需要计数的个数为999_999,计数器计数满后我们习惯先清零,如果有问题我们根据分析再进行修改。而key_flag信号则是一个脉冲信号,也就是只有一个时钟周期的高电平,且当cnt_20ms计数器计数到999_999时才拉高,而这个高电平只能存在一个。按照cnt_20ms计数器计数到999_999时清零来分析,其波形图如图 16-6所示,按键会因为低电平的时间太久,会存在多个20ms的时间,cnt_20ms计数器计数满清零多次,这样就会有多个计数值为999_999的情况,从而导致key_flag信号产生多次脉冲,这显然是我们不想要的结果。那我们需要分析是cnt_20ms计数器清零的问题还是key_flag信号拉高时间的问题。经分析key_flag信号即使不是在cnt_20ms计数器计数到999_999时拉高而在其他时间拉高也会出现同样的问题,所以那只能怀疑是cnt_20ms计数器清零的条件不对了。刚开始的时候cnt_20ms计数器清零已经有一个条件了,那就是当输入信号key_in只要为高电平就将cnt_20ms计数器清零,那这里我们就让cnt_20ms计数器计数满后保持为999_999而不清零,等待输入信号key_in为高电平的时候再清零。

图 16-6

修改cnt_20ms计数器清零后的结果如图 16-7所示,我们可以发现key_flag信号确实不会产生多个了,而是出现了新的问题,key_flag信号也不是脉冲了,是一个长长的电平信号,这也不是我们想要的结果,其根本原因是cnt_20ms计数器计数到999_999后保持在999_999的时间太久导致的。

图 16-7

针对上面的探索,我们最终灵机一动,发现cnt_20ms计数器计数到999_998的次数只有一个,而且最接近999_999,在既保证去抖动时间的前提下使key_flag信号只产生一个脉冲信号。最终的波形结果如图 16-8所示。

图 16-8

1.2.4  代码编写

//--------------------------------------------------

01module    key_filter

02#(

03    parameter CNT_MAX =20'd999_999

04)

05(

06    input    wire    sys_clk    ,    //系统时钟50Mhz

07    input    wire    sys_rst_n    ,    //全局复位

08    input    wire    key_in        ,    //按键输入信号

09    

10    output    reg        key_flag        //key_flag为1时表示消抖后检测到按键被按下,key_flag为0时表示没有检测到按键被按下

11);

12

13reg    [19:0]    cnt_20ms;

14

15//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数

16always@(posedge sys_clk ornegedge sys_rst_n)

17    if(sys_rst_n ==1'b0)    

18        cnt_20ms <=< span="">20'b0;

19    else    if(key_in ==1'b1)    

20        cnt_20ms <=< span="">20'b0;

21    else    if(cnt_20ms == CNT_MAX && key_in ==1'b0)

22        cnt_20ms <=< span=""> cnt_20ms;

23    else

24        cnt_20ms <=< span=""> cnt_20ms +1'b1;                        

25

26//key_flag:当计数满20ms后产生按键有效标志位,且key_flag在999_999时拉高,维持一个时钟的高电平                            

27always@(posedge sys_clk ornegedge sys_rst_n)

28    if(sys_rst_n ==1'b0)

29        key_flag <=< span="">1'b0;

30    else    if(cnt_20ms == CNT_MAX -1'b1)

31        key_flag <=< span="">1'b1;

32    else

33        key_flag <=< span="">1'b0;

34                            

35endmodule

//--------------------------------------------------

1.2.5  仿真文件编写

//--------------------------------------------------

01module    tb_key_filter();

02

03reg            sys_clk;

04reg            sys_rst_n;

05reg            key_in;

06

07wire        key_flag;

08

09reg    [21:0]    tb_cnt;        

10

11//为了缩短仿真时间,我们将参数化的时间值改小,但位宽依然定义和参数名的值保持一致,也可以将这些参数值改成和参数名的值一致

12parameter CNT_1MS  =20'd19;    

13parameter CNT_11MS =21'd69;

14parameter CNT_41MS =22'd149;

15parameter CNT_51MS =22'd199;

16parameter CNT_60MS =22'd249;

17

18//初始化系统时钟、全局复位和输入信号

19initial    begin

20    sys_clk    =1'b1;

21    sys_rst_n <=< span="">1'b0;

22    key_in     <=< span="">1'b0;

23    #20         

24    sys_rst_n <=< span="">1'b1;

25end

26

27//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50Mhz

28always#10 sys_clk =~sys_clk;

29

30//tb_cnt:按键过程计数器,通过该计数器的计数时间来模拟按键的抖动过程

31always@(posedge sys_clk ornegedge sys_rst_n)

32    if(sys_rst_n ==1'b0)

33        tb_cnt <=< span="">22'b0;

34    else    if(tb_cnt == CNT_60MS)    //计数器计数到CNT_60MS完成一次按键从按下到释放的整个过程

35        tb_cnt <=< span="">22'b0;

36    else    

37        tb_cnt <=< span=""> tb_cnt +1'b1;

38

39//key_in:产生输入随机数,模拟按键的输入情况        

40always@(posedge sys_clk ornegedge sys_rst_n)

41    if(sys_rst_n ==1'b0)

42        key_in <=< span="">1'b1;        //按键未按下时的状态为高电平

43    else    if((tb_cnt >= CNT_1MS && tb_cnt <=< span=""> CNT_11MS)||(tb_cnt >= CNT_41MS && tb_cnt <=< span=""> CNT_51MS))    //在该计数区间内产生非负随机数0、1来模拟10ms的前抖动和10ms的后抖动

44        key_in <=< span="">{$random}%2;    

45    else    if(tb_cnt >= CNT_11MS && tb_cnt <=< span=""> CNT_41MS)

46        key_in <=< span="">1'b0;                //按键经过10ms的前抖动后稳定在低电平,持续时间需大于CNT_MAX

47    else

48        key_in <=< span="">1'b1;                

49

50//------------------------key_filter_inst------------------------

51 key_filter

52#(

53    .CNT_MAX    (20'd24    )    //修改的CNT_MAX值一定要小于(CNT_41MS - CNT_11MS),否则就会表现为按键一直处于“抖动状态”而没有“稳定状态”,无法模拟出按键消抖的效果

54)

55 key_filter_inst(

56    .sys_clk    (sys_clk    ),    //input    sys_clk

57    .sys_rst_n    (sys_rst_n    ),  //input    sys_rst_n

58    .key_in    (key_in    ),  //input    key_in

59                        

60    .key_flag    (key_flag    )    //output    key_flag

61);

62                        

63endmodule    

//--------------------------------------------------

1.2.6  仿真波形分析

 Testbench编写完成后,我们启动ModelSim进行功能仿真验证,我们让波形跑了10us,通过图 16-9所示的波形我们可以观察到,我们模拟了完整的两次按键按下与释放抖动的情况,通过cnt_20ms计数器计数来滤除抖动,且是最终的输出的按键脉冲key_flag信号完美的表达出无抖动的按键效果,完全符合我们预期的设计。

图 16-10、图 16-11和图 16-12为按键消抖模块局部仿真波形图,分别为前抖动部分、稳定部分和后抖动部分的仿真波形。由整体和局部仿真波形可以看出,模块仿真波形和绘制波形图,各信号波形变化一致,模块通过仿真验证。

图 16-9

图 16-10

图 16-11

图 16-12

1.2.7  上板验证测试

虽然都说按键需要消抖,用示波器是可以抓到消抖之前和消抖之后的波形变化的,但是如果没有示波器该怎么来看消抖之前和之后变化的效果呢?大家不妨做一个小实验,前面我们也学习了计数器,不过计数的加“1”是通过时钟来实现的,这里为了让按键抖动的效果体现出来我们用按键来实现计数的加“1”操作,做一个二进制的4bit加法器,刚好我们的板子上也有4个led灯,就让我们来验证一下。

1.2.8  本章小结   

通过本例我们可以发现在画波形图时不一定可以保证100%正确,根据分析,我们可以适当的调整,这也是设计之前画波形图的意义所在,而不是一抹黑的、漫无目的的调试代码。

其实在项目的设计过程中并不是一番风顺的,往往会遇到各种各样的问题,通过经过思考与探索尝试使我们最终得出正确的结果。如果总是站在上帝视角去考虑问题,而抛弃分析真理的过程,这对于学习来说将是巨大的损失。

希望学习者能深入体会设计中遇到的问题并掌握设计分析的方法,养成一个善于思考敢于尝试的习惯。

您可能感兴趣的与本文相关的镜像

Wan2.2-T2V-A5B

Wan2.2-T2V-A5B

文生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

MATLAB主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性内容概要:本文主要介绍了一种在MATLAB环境下实现的主动噪声和振动控制算法,该算法针对较大的次级路径变化具有较强的鲁棒性。文中详细阐述了算法的设计原理与实现方法,重点解决了传统控制系统中因次级路径动态变化导致性能下降的问题。通过引入自适应机制和鲁棒控制策略,提升了系统在复杂环境下的稳定性和控制精度,适用于需要高精度噪声与振动抑制的实际工程场景。此外,文档还列举了多个MATLAB仿真实例及相关科研技术服务内容,涵盖信号处理、智能优化、机器学习等多个交叉领域。; 适合人群:具备一定MATLAB编程基础和控制系统理论知识的科研人员及工程技术人员,尤其适合从事噪声与振动控制、信号处理、自动化等相关领域的研究生和工程师。; 使用场景及目标:①应用于汽车、航空航天、精密仪器等对噪声和振动敏感的工业领域;②用于提升现有主动控制系统对参数变化的适应能力;③为相关科研项目提供算法验证与仿真平台支持; 阅读建议:建议读者结合提供的MATLAB代码进行仿真实验,深入理解算法在不同次级路径条件下的响应特性,并可通过调整控制参数进一步探究其鲁棒性边界。同时可参考文档中列出的相关技术案例拓展应用场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值