当前位置: 首页 > news >正文

软件按键消抖的几种方式(HAL库教程)

按键消抖的几种方式说明

此工程是:1.按键中断消抖 2.按键定时器中断

软件按键消抖实现方式1

  • 循环阻塞判断(浪费CPU资源)
    这个比较简单,就不记录具体操作了
    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);      // 等待按键松开}}}
    }
    

软件按键消抖实现方式2

  • EXTI外部中断
    1.将按键GPIO设置为外部中断输入方式,中断捕获类型可根据实际电路设置为上升沿或下降沿,这里我们配置为内部上拉、下降沿中断方式。
    2.设置中断优先级,打开中断
    3.写中断回调函数(小心有坑)
    我实际测试效果不太好,不知道为什么
    //-----------------------KEY2  EXTI外部中断消抖()-------------------------------//
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {if (GPIO_Pin == KEY2_Pin) { // 判断是KEY2引脚触发的中断delay_ms(10); // 简单延时消抖(阻塞方式)if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) {// 按键确认按下,执行相应操作HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 切换LED状态}}
    }
    
  • 另一种方案,将延时放在中断服务函数中
    那问题来了,通过上面一步一步分析HAL库的I/O中断处理过程,就知道在用户处理函数之前的“HAL_GPIO_EXTI_IRQHandler()”确认中断端口中就已经将中断标志位消除了(在用户处理函数之前),意味着抖动仍然能触发中断。然后再通过阅读相关文档,发现STM32中断是依靠向量表机制,也就是说只要触发了中断,一般情况下总是要去响应和清除相应的中断标志位。所以我认为在用户处理函数这么做可能可以解决问题,但以我个人经验,效果并不是很好,原因就是解决问题的方法不太对。
    个人认为更正确的做法是在清除标志位之前延迟等待抖动消失,防止因抖动在此将中断标志位置为有效。即需要修改HAL库(Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c)中的“HAL_GPIO_EXTI_IRQHandler”函数。如图,在“__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);”之前添加延迟“Delay_ms((uint32_t)20);”

软件按键消抖实现方式3

  • 定时器中断(最推荐的方法)
    使用定时器每隔10ms读取一次按键的状态,然后进行判断。
    注意代码中定时器中断不要忘记开启!
    GPIO配置为输入,根据原理图选择上拉下拉
    在这里插入图片描述
    配置定时器
    在这里插入图片描述
    开启定时器中断
    在这里插入图片描述
// KEY1使用定时器中断方式扫描
// 按键状态枚举
typedef enum {KEY_STATE_RELEASE = 0x00,   // 按键未按下KEY_STATE_SHAKE   = 0x01,   // 按键抖动检测中KEY_STATE_PRESS   = 0x02    // 按键确认按下
} KeyState_TypeDef;// 按键数据结构
typedef struct {GPIO_TypeDef *Port;       // 按键GPIO端口uint16_t Pin;             // 按键GPIO引脚KeyState_TypeDef State;   // 当前状态// void (*PressCallback)(void); // 按下后的回调函数
} Key_TypeDef;Key_TypeDef Key1 = {KEY1_GPIO_Port, KEY1_Pin, KEY_STATE_RELEASE};//-----------------------KEY1 10ms定时器检测+状态机----------------------
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{// 判断是定时器3发生的中断if (htim->Instance == TIM3) { // 假设使用TIM3Key_Scan_Handler(&Key1); // 周期执行按键扫描}
}
// 按键扫描状态机函数(需在定时中断中周期调用,如10ms一次)
void Key_Scan_Handler(Key_TypeDef *Key)
{uint8_t current_level = HAL_GPIO_ReadPin(Key->Port, Key->Pin);switch (Key->State) {// 状态1:初始释放状态case KEY_STATE_RELEASE:if (current_level == GPIO_PIN_RESET) { // 检测到低电平(按下)Key->State = KEY_STATE_SHAKE;        // 转入消抖状态}break;// 状态2:消抖状态case KEY_STATE_SHAKE:if (current_level == GPIO_PIN_RESET) { // 再次确认仍是低电平Key->State = KEY_STATE_PRESS;        //-------------------------------------------- 确认按键有效按下 ,可以执行按键按下的操作HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 切换LED状态} else {Key->State = KEY_STATE_RELEASE; // 是抖动,返回释放状态}break;// 状态3:按下状态case KEY_STATE_PRESS:if (current_level == GPIO_PIN_SET) { // 检测到按键已释放(高电平)Key->State = KEY_STATE_RELEASE;    // 返回释放状态}break;default:Key->State = KEY_STATE_RELEASE;break;}
}

总结

1.中断处理时间越短越好,不然严重浪费CPU资源
2.stm32 hal库 HAL_Delay用的 滴答定时器 延时的,并默认是 优先级最低的,如果外部中断 优先级高于或等于 滴答定时器优先级,会造成中断里面的HAL_Delay无限延时,造成锁死退不出去!
3.保险起见,还是别用HAL_Delay了
4.对于按键中断检测,最推荐定时器中断的方法

http://www.dtcms.com/a/612382.html

相关文章:

  • 怎么做微信网站推广国外做做网站
  • 人才市场官方网站网站版面设计流程包括哪些
  • 威海建设集团官方网站华为应用市场下载安装
  • 沈阳做个网站成本公司简介模板免费doc
  • 一个网站开发团队要什么人房地产公司网站制作
  • 金华网站制作营销个人装修接活app
  • 建设部勘察设计网站wordpress是谁写的
  • 做外贸找工厂货源网站lamp 搭建wordpress
  • 网站里的聊天怎么做广州网站改版哪家好
  • 上海网站微信平台建设wordpress 仿煎蛋妹子图
  • 河南省建设厅官方网站郭风春江西个人网站备案做论坛
  • 本地网站建设的步骤过程宣传平台
  • html做校园网站宁波网站开发服务
  • wordpress旅游网站wordpress+dns预读
  • 宿迁网站推广公司企业网站优化方案
  • 孟州网站百度收录提交接口
  • 中山中小企业网站制作google中文搜索引擎
  • 网站建设情况总结茶网站建设方案
  • 怎么提高自己网站的知名度巨人网络公司简介
  • 网站宣传用了最字网页设计基础实训计划
  • 手机网站建设开什么类型的票网站建设政务新媒体
  • 学做网站丛什么开始免费网上申请注册
  • 一个主机怎么做两个网站如何在网站投放广告
  • 云南建设厅和网站怎么做会员积分网站
  • 免费做网站哪里有平面设计专业哪个学校好
  • wordpress主题的网站模板一键优化ppt
  • 简述网站开发流程 旅游建筑网官网登录入口
  • 南京手机网站开发有没有能帮人快速网站备案的机构
  • 用什么自己做网站可以免费发布信息的网站有哪些
  • 网站logo是什么seo专业优化公司