转载请说明出处。
接上文STM32–矩阵键盘的设计实现。
按键抖动
成功扫描到按键按下后,由于按键本身有着不可避免的抖动问题,一般我们会设置一段延时,延时过后再次判断按键是否按下。
这是使用逻辑分析仪捕捉的一个按键从按下到松开的过程(高电平为按下)。可以发现,在按下的一瞬间,按键的电平发生了一段无规律跳动,这个就是抖动。
很多在学校的小伙伴可能对这种现象不以为然。当然,设置一小段时间的delay的确可以解决这个问题。但在一些公司的项目开发中,是不允许使用任何的延时函数的,这会造成主程序的阻塞(即使是几毫秒的延时阻塞也不允许),用按键触发的外部中断或者用while来判断按键松开也会对主函数造成一瞬间的阻塞(不松开按键主程序就无法继续执行那种),这也是不允许的。
那么,不允许使用延时函数来过滤抖动信号,还有什么方法来解决这个问题呢?
很多小伙伴应该会立马给出一个答案:定时器。
定时器的确可以完美解决这个问题。将定时器配置为每1ms触发一次定时器中断,或者每5ms、10ms触发一次,通过这个设置计时标志,只需要检测这个计时标志是否到达所需要的时间,到了之后再检测按键是否按下。期间不会对主程序造成阻塞,程序会一直循环执行。
比如我们配置一个定时器TIM2
static void MX_TIM2_Init(void)
{
//Tout = ((10 Period)*(7200 Prescaler))/72000000 Hz(外部高速时钟) = 0.001s
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7200-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 10-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
每1ms触发一次计数溢出中断,函数外部设置一个全局变量,在中断回调函数中每触发一次对这个值进行自增。
uint16_t ShakeTime = 0; //全局变量
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance == htim2.Instance){
ShakeTime++;
//这个的作用是防止计数溢出。对这个全局变量清零的比较频繁的话可以不用这段代码
if (ShakeTime >= 32768){
ShakeTime = 0;
}
}
}
每1ms触发一次计数溢出中断,也就是说这个全局变量每1ms自增一次。
在检测到按键按下后,把这个值清零,之后在每一轮的程序循环中,只需要检测这个全局变量是否自增到了某个数字,到了之后再对按键电平进行检测即可。
特殊情况
我们对这个按键抖动的问题一般只对按下时进行解决而已,但有没有想过,在松开的瞬间,按键是否也会产生抖动?
答案是有的,不过松开按键产生抖动的情况可能会比按下按键的情况少一点,但在项目开发中,如果对产品设计严格一点的话,这也是一个不允许被忽略的问题。
从图中我们可以看到,按键按下跟松开时都有一段时间的抖动。比如按键操作一个LED灯,结合上述提出的情况,这段松开按键的过程如果不做任何处理的话,很有可能会造成一瞬间的一亮一灭,然后又会点亮。在严格一点的项目开发中是不允许这种情况出现的。
什么,你说松开的一瞬间即使抖动,由于LED被操作了一次,这段抖动也可以被开头的消抖操作给自动过滤掉,没问题啊?
那么我们再看一下这个
(没想到吧)
这种现象我估计在按键使用过久老化之后才会出现的多(你啪啦啪啦瞎乱按一通也可能会出现),不对这个进行处理的话,产品使用久了,按键抖动的厉害,可能就会导致操作失误。
解决办法倒也简单,检测到按键松开时再进行抖动检测就好,跟上面按下时检测抖动的步骤基本一样。