STM32按键消抖的几种实现方式
创作时间:
作者:
@小白创作中心
STM32按键消抖的几种实现方式
引用
CSDN
1.
https://blog.csdn.net/robottosan/article/details/126800521
一、按键抖动的现象
按键按下和松开的时候,按键金属片之间的贴合、分离有一个过程。给STM32输入的信号并不是理想的0和1切换的过程。而是如下图所示的,按下和松开的一小段时间内按键信号出现抖动(jitter),这种现象称为按键抖动(Button Bouncing)。为了避免程序上出现误动作,需要从硬件或软件上消除按键抖动(Button Debouncing)。
二、 硬件电路消抖
可以从电路设计上消除抖动,常见的有RC滤波电路消抖。但是仅通过RC电路,消抖过程慢,实际效果也并不好,一般会加上施密特触发器。硬件消抖的缺点是要增加额外的元器件,如果有多个需要消抖的输入信号,则会增加较大的成本。
RC电路
RC电路加施密特触发器
三、 软件消抖
3.1 按键状态分析
按键状态变化后,短时间内的状态是抖动的、不可采用的。软件上可延迟一段时间再判断按键的状态。按键的状态机变化如下图所示。
3.2 程序实现
下面通过程序来实现按键的消抖。下例中的开发板MCU为stm32f103RCT6, 按键接在PB12、PB13引脚,LED接在PC0、PC1引脚。程序基于HAL库编写,外设的初始化程序由Stm32CubeMx软件生成,此处不再赘述。
- 循环阻塞判断
int main(void)
{
while (1)
{
if (HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_RESET)
{
printf("Key 1 pressed.\n");
HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);
while(HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_RESET); // 等待按键松开
}
}
}
}
上面的方式,按键松开之前程序一直卡在while循环里,按键松开之后才能处理其他的程序。
- 增加标志位、非阻塞
int main(void)
{
uint8_t Button1PressedFlag = 0;
uint8_t Button2PressedFlag = 0;
while (1)
{
if (Button1PressedFlag == 0 && HAL_GPIO_ReadPin(Button1_GPIO_Port == Button1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_RESET)
{
printf("Key 1 pressed.\n");
HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);
Button1PressedFlag = 1;
}
}
if(Button1PressedFlag == 1 && HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_SET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(Button1_GPIO_Port, Button1_Pin) == GPIO_PIN_SET)
{
printf("Key 1 released.\n");
Button1PressedFlag = 0;
}
}
if (Button2PressedFlag == 0 && HAL_GPIO_ReadPin(Button2_GPIO_Port, Button2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(Button2_GPIO_Port, Button2_Pin) == GPIO_PIN_RESET)
{
printf("Key 2 pressed.\n");
HAL_GPIO_TogglePin(Led2_GPIO_Port, Led2_Pin);
Button2PressedFlag = 1;
}
}
if(Button2PressedFlag == 1 && HAL_GPIO_ReadPin(Button2_GPIO_Port, Button2_Pin) == GPIO_PIN_SET)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(Button2_GPIO_Port, Button2_Pin) == GPIO_PIN_SET)
{
printf("Key 2 released.\n");
Button2PressedFlag = 0;
}
}
}
}
上面实现的是两个按键消抖的处理。非阻塞方式可实现两个LED灯的同时点亮和熄灭,阻塞方式只能一个一个地操作。
- 外部中断方式
①. 将按键GPIO设置为外部中断输入方式,中断捕获类型可根据实际电路设置为上升沿或下降沿,这里我们配置为内部上拉、下降沿中断方式。
②. 设置中断优先级,打开中断
③. 在stm32f1xx_it.c文件中编写中断回调函数
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
} // EXTI15_10_IRQHandler 中断ISR 有CubeMx生成
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_12)
{
printf("Button triggered!\n");
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(Led1_GPIO_Port, Led1_Pin);
printf("Led toggled!\n");
}
}
if(GPIO_Pin == GPIO_PIN_13)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(Led2_GPIO_Port, Led2_Pin);
}
}
} // 中断回调函数 按键按下之后执行的动作由自己编写
⑤. 最后,还需修改一下HAL库中的外部GPIO中断服务函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); 注释此行
HAL_GPIO_EXTI_Callback(GPIO_Pin);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); // 添加此行
}
}
本文原文来自CSDN
热门推荐
过年期间聚餐容易贪杯,解酒饮料怎么选?真的有效吗
小型无人机蜂群和战斗管理:不断演变的战争格局
财政所职能有哪些具体内容?
抬头向西南看!今天金星亮度迎来极值
金丝皇菊的功效与食用方法
新房装修后苯和TVOC超标怎么办?空气净化器选购指南及产品推荐
宝宝为什么吃了就拉?
降脂超过50%的PCSK9抑制剂,国内已上市4种!一文汇总
探索英文第三人称的奥秘:语法与语义的交织
酷洛米Kuromi紅什麼?最可愛反派8件事,與美樂蒂反目成仇、紫黑正義性格超圈粉
最耐寒耐旱的九种树木,来看看它们都是些什么树?
宋明清以文治武:是王朝兴盛的 “妙方” 还是 “毒药”?
爆炒鸡胗的做法是什么?如何做出美味的爆炒鸡胗?
鸣人去小樱家拔萝卜:《火影忍者》中的团结与成长
前端如何测试自己的能力
六星连珠今晚现身爱尔兰夜空,最佳观测指南请收藏!
关系错位,是一个家庭最大的灾难
上海生鲜配送:为城市居民带来便利与新鲜
躺着也能清爽沐浴,公益助洁帮老人过个健康年
怎么缓解鼻炎鼻塞
从《西厢记》到《莺莺传》,爱情悲剧是如何变成喜剧的?
八字命盘术语解析 对照表解读命运密码
历史的尘埃——论《红楼梦》的动物意象
十部灾难大片推荐,每部都堪称巅峰之作!
新疆优化居家社区养老的探索实践
如何面对批评,打造强大的职场韧性
宝可梦大集结互动道具有哪些 宝可梦大集结互动道具玩法
金属材料硬度测试介绍
西甲西班牙人VS巴利亚多利德前瞻分析 西班牙人颇为依赖主场
原神:大剑角色天花板!荒泷一斗全分析,圣遗物与武器推荐