首页 > 其他分享 >STM32按键消抖的几种实现方式-STM32 Button Debouncing

STM32按键消抖的几种实现方式-STM32 Button Debouncing

时间:2022-09-04 17:11:12浏览次数:63  
标签:HAL PIN Pin Button 消抖 STM32 按键 GPIO Port

一、按键抖动的现象

按键按下和松开的时候,按键金属片之间的贴合、分离有一个过程。给STM32输入的信号并不是理想的0和1切换的过程。而是如下图所示的,按下和松开的一小段时间内按键信号出现抖动(jitter),这种现象称为按键抖动(Button Bouncing)。为了避免程序上出现误动作,需要从硬件或软件上消除按键抖动(Button Debouncing)。
button bouncing


二、 硬件电路消抖

可以从电路设计上消除抖动,常见的有RC滤波电路消抖。但是仅通过RC电路,消抖过程慢,实际效果也并不好,一般会加上施密特触发器。硬件消抖的缺点是要增加额外的元器件,如果有多个需要消抖的输入信号,则会增加较大的成本。

  • RC电路

    RC debounce circuit
  • RC电路加施密特触发器

三、 软件消抖

3.1 按键状态分析

按键状态变化后,短时间内的状态是抖动的、不可采用的。软件上可延迟一段时间再判断按键的状态。按键的状态机变化如下图所示。
button state

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);     // 添加此行
  }
}

关于中断消抖的方式,有几个需要注意的点。以上只是实现过程的描述,具体细节下一篇更新

标签:HAL,PIN,Pin,Button,消抖,STM32,按键,GPIO,Port
From: https://www.cnblogs.com/xyw-blog/p/16655450.html

相关文章

  • 使用STM32控制TMC5160驱动步进电机
      首先先来了解一下TMC5160的3种工作模式TMC5160通过两个引脚来控制它的工作模式:SD_MODE和SPI_MODE。1、当SD_MODE接地,SPI_MODE拉高,TMC5160即工作在模式1(SPI......
  • 小程序-转发功能,使用button开放功能open-type="share
    标签: 微信小程序   页面内发起转发通过给 button 组件设置属性 open-type="share",可以在用户点击按钮后触发 Page.onShareAppMessage 事件,相关组件:button。......
  • STM32CubeIDE和ITM SWV实现printf调试信息的打印
    STM32CubeIDE+ITMSWV实现printf调试信息的打印STM32开发时,使用printf函数来打印信息是一种方便的调试方法。不需要像使用断点来中断程序运行即可方便地查看想要的信息......
  • STM32串口乱码问题
    1:修改文件stm32f4xx.h中的HSEVALUE;defineHSE_VALUE((uint32_t)25000000)---#defineHSE_VALUE((uint32_t)8000000)2:修改完还有乱码,则修改system_stm32f4xx.......
  • easyui-switchbutton 默认 选中
    默认选中主要是在 html 加入  checked<tdstyle="width:65px;">创建时间:</td><td><inputid="switch_date_entered"class="easyui-switchbutton"style="wid......
  • STM32F769NI-Discovery开发笔记(二)UART
    开发环境:开发板:STM32F769NI-DiscoveryKEIL版本:5.33STM32CubeMX版本:6.3.0 本篇主要讲STM32F769NI的串口实现STM32F769NI-Discovery开发板的usb接口带有stlink与串口,......
  • stm32c8t6的定时器中断
    采用的定时器为TIM3(TIM1和TIM2已经被用于产生PWM波了),TIM3对应的是APB1Timerclocks,时钟频率Tclk为72MHz。溢出时间\(Tout=\frac{(arr+1)*(psc+1)}{Tclk}\)......
  • 兼容树莓派引脚定义,适配多种模块--米尔百变STM32MP1开发板演示
    大家好,我是米尔的工程师,今天给大家带来一款全新的米尔板卡标杆产品:MYD-YA15XC-T。今天的文章将分成两部分来介绍这块基于STM32MP1处理器开发的板卡。一、百变开发板MYD-Y......
  • 按钮控件Button
    Button由TextView派生而来,它们的区别有以下几点Button有默认的按钮背景,TextView默认无背景Button中的文本默认居中显示,TextView中的文本默认靠左显示Button中文本默认......
  • stm32 在arduino平台上开启非默认外设
    起初原因是我试图编译fsmc,但始终无法编译。在C:\Users\kyo\.platformio\packages\framework-arduinoststm32\system\STM32F1xx\stm32f1xx_hal_conf_default.h里看到这个 ......