利用软件定时器实现按键消抖

前言

首先铺垫一个场景,研发需求是用户通过按下按键来和屏幕上的UI画面进行交互,这里我就以按下按键后按键值自增为例。我们定义了一个KeyCount计数值来统计按下按键的次数,如果我们在主进程之中检测按键连接的GPIO口的电平变化,毫无疑问按键计数值的自增会有延迟,因为While循环的执行需要机器时间。这时自然而然联想到中断检测IO口,但新的问题产生了,因为按键的机械触点在按下后会产生简谐振动,电平的变化会有一段毛刺。放任不管的话我们按下一次按键,可能计数值跳变了三次。从硬件角度来解决可以考虑并联一个滤波电容,而从软件角度来讲,我们需要定时器延时让这段电平毛刺结束,这里我来给大家介绍软件定时器。

虽然叫软件但是也还是需要依赖SysTick系统滴答计时器(一个Tick用时1ms的那位),因为这样比while循环里面定义变量自减精准太多了。精确程度排名:SysTick系统滴答计时器>TIM计时器>>纯软件计时器,因为SysTick系统滴答计时器的时钟源直接来自ARM内核。

肯定有读者老爷要说了番茄你又在Ⅹ上雕花了,你直接用HAL_Delay不行么?

(参考拙作stm32外部中断-优快云博客里的实验,ok我承认这是回旋镖来的最快的一集)

还真不行,按键的机械触点振动时间可能在5~10ms之间,单纯的delay死等可能会严重影响使用体验,尤其是涉及到和屏幕复杂UI交互的场景(比如游戏手柄和主机之间的通信)。咱们这儿可以利用编程控制超时时间的绝对值(当然是借鉴了RTOS里面vTaskDealyUntil的思路不是我自创)。

废话不多说,下面开启正文。

需求梳理

我们的实验目的是让单片机准确地把按下按键电平跳变的次数打印在屏幕之上,且不依赖阻塞延时死等解决。所以我们就需要构造一个“虚拟外设”,叫做软件定时器。在当前场景下,它的内部应该至少包含着一个变量用来存储溢出时间,以及一个用来和GPIO输入中断进行交互的接口函数。(这个接口函数里面至少要做到两件事,第一是按键值的自增(业务逻辑),第二是将延时时间恢复至默认状态。)参考网上C语言实现面向对象的方法,很容易联想到用struct构造结构体来包含这个数值变量和接口函数,具体的结构体成员我们需要在下文继续分析。

本质上来讲这个功能的实现是依靠System Tick中断嵌套GPIO输入中断,System Tick中断每1ms发生一次的时候对定时时间的溢出发起质询(注意这个质询下文有用),如果定时时间的溢出发生了(即当前实际Tick值超出了软件定时器的溢出时间),那么软件定时器执行交互接口函数。这个定时时间的来源是GPIO输入中断,一旦GPIO口检测到了上升沿/下降沿,那么中断回调函数里面会触发修改定时时间的函数,先获取当前的Tick数值同时加上想要延时的时间。注意GPIO输入中断优先级此时应该高于System Tick中断,按键的频次再怎么高也不会超过1ms。

下面开始介绍详细步骤。

第一步自然是设置GPIO为输入中断模式,咱们按下按键后IO口检测到电平变化,我这里上升/下降边

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值