参考——单片机_外部中断_按键消抖

                尝试过清除标志位和延时,前者没有什么用,后者又会增加ISR的时间,影响后台任务。由于使用的是外部中断,状态机的方法又不适合。

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
      __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
      Delay();//阻塞式的延时
      HAL_GPIO_EXTI_Callback(GPIO_Pin);//处理任务

  }
}

  于是呢,决定参考状态机的设计,使用另类的延时来解决抖动问题。

        具体而言,就是按下按键第一次进入中断后,由于会抖动,那么可能会进入第2次。为了避免抖动的影响,需要在抖动这段时间内(一般10~20ms)不做任何操作。所以延时的设计的场景就是由于抖动而进入两次中断,第一次进入检测状态同时执行回调任务,第二次进入消抖状态,只有计时时间大于抖动时间才会执行回调任务,然后回到第一种状态。由此避免了抖动的影响——很短的时间间隔内连续进入两次。于是就有

enum {
    PRESSED,
    DEBOUNCE,
};

uint8_t keyState = PRESSED;
uint32_t tickCount = 0;
#define DEBOUNCE_TIME 20
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
      __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
      switch(keyState)
      {
          case PRESSED:
              keyState = DEBOUNCE;
              tickCount = HAL_GetTick(); // 记录开始时间,开始检测
              HAL_GPIO_EXTI_Callback(GPIO_Pin);//处理任务
              break;

          case DEBOUNCE:
              // 检查去抖动时间是否足够
              if ((HAL_GetTick() - tickCount) >= DEBOUNCE_TIME)
              {
                  keyState = PRESSED;//时间足够长,则重新进入检测
              }
              break;

          default:
              // 不应该到达的默认情况
              break;
      }

  }
}

        可是实际情况是,有时会进入1次,有时候会进入2次,次数并不能确定,而且按键的时机也不确定。比如说,第一次按下按键只进入了1次中断,然后隔了很长的时间后又按下了按键,由于这个tickcount是32位的,范围有限,时间足够长的话(大概3.27年)会重新计数,使用上面的延时方法,则会导致状态紊乱。虽然不大可能会超过3.27年,但是不够优雅。

        于是得让它每次按下按键至少得进入两次,那么按键的外部中断应该设为上升沿和下降沿触发。

void KEY_EXTI_init()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    __HAL_RCC_GPIOF_CLK_ENABLE();

    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Mode =GPIO_MODE_IT_RISING_FALLING;//触发方式
    GPIO_InitStruct.Pin =KEY_Pin;
    HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);

    HAL_NVIC_SetPriority( EXTI15_10_IRQn , 0xF, 0x00);
    HAL_NVIC_EnableIRQ( EXTI15_10_IRQn );

    HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0xF, 0x00);
    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}

  按下按键,由于下降沿会先进入一次中断,此时进入PRESSED状态,然后等待200ms(这个比较玄学,可能40、100就够了,需要实测,过大会导致状态紊乱),200ms后的上升沿再进入一次中断重置状态。在这200ms期间间的抖动不去理会。

        在设置合理的情况下,这个时间设大了会有迟滞感,同时由于前面按键设的触发模式,会在松开时执行回调任务(原因未知,有时间再来看看)

enum {
    PRESSED,
    RELEASE,
};

uint8_t keyState = PRESSED;
uint32_t tickCount = 0;
#define DEBOUNCE_TIME 200
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
      __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
      switch(keyState)
      {
          case PRESSED:
              keyState = RELEASE;
              tickCount = HAL_GetTick(); // 记录开始时间,开始检测
              HAL_GPIO_EXTI_Callback(GPIO_Pin);//处理任务
              break;

          case RELEASE:
              // 检查去抖动时间是否足够
              if ((HAL_GetTick() - tickCount) >= DEBOUNCE_TIME)
              {
                  keyState = PRESSED;//时间足够长,则释放按键,重新进入检测
              }
              break;

          default:
              // 不应该到达的默认情况
              break;
      }

  }
}

仅供参考

相关推荐

  1. 参考——单片机_外部中断_按键

    2024-06-06 04:34:03       30 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-06 04:34:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-06 04:34:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-06 04:34:03       82 阅读
  4. Python语言-面向对象

    2024-06-06 04:34:03       91 阅读

热门阅读

  1. 从0到1学Binder-Binder驱动初始化

    2024-06-06 04:34:03       21 阅读
  2. Yshop框架的小程序登录

    2024-06-06 04:34:03       25 阅读
  3. Appium框架

    2024-06-06 04:34:03       28 阅读
  4. 东方博宜1957 - 求三个数的平均数

    2024-06-06 04:34:03       25 阅读
  5. 数字取证技术(Digital Forensics Technology)实验课II

    2024-06-06 04:34:03       31 阅读
  6. 【tansformers库】LLM基本过程 & 模型加载

    2024-06-06 04:34:03       33 阅读
  7. Redis 常用基本命令

    2024-06-06 04:34:03       30 阅读
  8. 正大国际期货:内盘与外盘的区别

    2024-06-06 04:34:03       24 阅读
  9. 在Github找自己想要的的项目

    2024-06-06 04:34:03       31 阅读
  10. Docker简介

    2024-06-06 04:34:03       25 阅读
  11. 纯C++做多项式拟合

    2024-06-06 04:34:03       33 阅读
  12. 密码算法学习笔记

    2024-06-06 04:34:03       22 阅读
  13. PostgreSQL的视图pg_stat_activity

    2024-06-06 04:34:03       30 阅读
  14. 550. 游戏玩法分析 IV

    2024-06-06 04:34:03       32 阅读