【问题标题】:Can STM32 Discovery differentiate between short and long push of a buttonSTM32 Discovery可以区分短按和长按按钮吗
【发布时间】:2019-01-11 07:58:40
【问题描述】:

如果我可以在我的项目中实现长按和短按按钮,它会派上用场。我正在使用 STM32F4 Discovery Kit 并用 C 对其进行编程。我准备了一个引脚作为外部输入,我修改了中断处理程序。

架构:

我现在将它设置为在下降和上升时触发。我看不到如何检测长短推的明显方法。有什么办法吗?

【问题讨论】:

  • 我不会对按钮使用边缘中断,它们是有弹性的方式。使用轮询,然后也更容易弄清楚时间。
  • 这不是一个真正的编程问题。
  • @r_ahlskog:使用中断来检测边缘很好,但当然还不够。
  • @ThomasJager:这只不过是一个软件问题。但它太宽泛了。
  • 硬件具备所有条件来做到这一点。阅读数据表,更多关于嵌入式软件的实践也不会受到伤害。

标签: c stm32f4discovery


【解决方案1】:

1.我想创建一个不会中断主回流和长短推状态的按钮阅读结构。那不是为此按下的按钮吗?保存数据集的 BT_User_State 变量,按钮长按,短按?我已经定义了两个单独的 BT_User_Flag_ShortPress 和 BT_User_Flag_LongPress 变量来保存数据,以及一个 BT_User_Time 变量,它将在持续时间内保存。

typedef enum{
Flag_Reset,
Flag_Set
}   Button_Flag;

typedef enum{
Button_Released,
Button_Pressed
}   Button_State;

Button_State    BT_User_State = Button_Released;
Button_Flag     BT_User_Flag_ShortPress = Flag_Reset;
Button_Flag     BT_User_Flag_LongPress = Flag_Reset;
uint16_t        BT_User_Time = 0;

2.每1ms还有一个Timer。完成此操作后,计时器溢出:

if(HAL_GPIO_ReadPin(BT_User_GPIO_Port, BT_User_Pin) == GPIO_PIN_SET)
{
   BT_User_State = Button_Pressed;
   BT_User_Time++;
} 
else 
{
   if(BT_User_Time >= 750)
{
    BT_User_Flag_LongPress = Flag_Set;
} 
else if (BT_User_Time >= 50) 
{
    BT_User_Flag_ShortPress = Flag_Set;
}
BT_User_Time = 0;
BT_User_State = Button_Released;
}

3.如果在剪切发生时按下按钮,我将按钮状态更改为已打印并添加了保存持续时间的变量 1。 如果在剪切发生时未按下按钮,我首先检查保存该值的变量,从较大的值开始并设置必要的标志。我终于重置了保存持续时间的变量并将按钮状态更改为 Dropped。

在主循环中:

    if(BT_User_Flag_ShortPress == Flag_Set && BT_User_State == Button_Released)
    {
        HAL_GPIO_TogglePin(LD_Blue_GPIO_Port, LD_Blue_Pin);
        BT_User_Flag_ShortPress = Flag_Reset;
    }

    if(BT_User_Flag_LongPress == Flag_Set && BT_User_State == Button_Released)
    {
        HAL_GPIO_TogglePin(LD_Red_GPIO_Port, LD_Red_Pin);
        BT_User_Flag_LongPress = Flag_Reset;
    }

【讨论】:

    【解决方案2】:

    是的,这是可行的,这是 STM32 上的中断处理程序中的解决方案。

    全局变量:

    static uint32_t lastUserButtonI = 700;
    static uint32_t lastUserButtonRisingI = 700;
    static uint32_t lastUserButtonFallingI = 700;
    

    HAL_GPIO_EXTI_Callback():

      uint32_t now = HAL_GetTick();
      uint8_t rising = HAL_GPIO_ReadPin(Button_GPIO_Port, pButton);
      if ((lastEdge == rising) ||
          (rising == 0 && ((now - lastUserButtonFallingI) <= 200)) ||
          (rising == 1 && ((now - lastUserButtonRisingI) <= 200))) {
        DBG_PRINTF("CANCELLING, %u\n", (uint)now);
      } else {
        if (rising == 1) {
          DEBUG_MSG("RISING\n");
          lastUserButtonRisingI = now;
        } else {
          DEBUG_MSG("FALLING\n");
          lastUserButtonFallingI = now;
        }
        DBG_PRINTF("Button Press Gesture, %u\n", (uint)now);
        uint32_t diff = lastUserButtonFallingI - lastUserButtonRisingI;
        if (rising == 0 && diff >= 10 && diff <= 500) {
          // Single press
          DEBUG_MSG("SINGLE PRESS\n");
        }
        if (rising == 0 && diff >= 2000 && diff <= 8000) {
          // Long press
          DEBUG_MSG("LONG PRESS\n");
        }
      }
      lastEdge = rising;
      lastUserButtonI = now;
    

    【讨论】:

      【解决方案3】:

      一个选项是在按下按钮后立即启动计时器,在释放按钮后停止计时器。根据计时器经过的滴答数,您可以采取正确的操作,但是您需要确定阈值滴答数以区分长按和短按。

      作为对上述建议的改进。您可以配置为 IO 中断源,而不是将按钮连接到的引脚配置为 GPIO。此方法也有助于您解决谴责问题。

      【讨论】:

        【解决方案4】:

        第一个 EXTI 中断对按钮非常不利。您应该使用定时器中断并定期检查按钮的状态。即使您有一个电容器,使用老化按钮也可能不足以消除抖动。

        您可以看到我的按钮库 - 长按、短按和双击,任意数量的按钮

        https://www.diymat.co.uk/arm-three-function-click-double-and-long-click-button-library-timer-interrupt-driven/

        【讨论】:

        • EXTI 适用于按钮。如果您必须尽可能多地节省电力,它们也是一种方式。也不需要电容器(不是说小电容器会造成伤害,但 EMI 比去抖更有趣)。
        • @toohonestforthissite EXTI 对按钮不友好。唤醒是不同的 - 从按钮唤醒,然后是计时器
        • 为什么EXTI中断不好?因为需要去抖动?轮询似乎会更糟,尤其是在需要设备休眠的情况下。
        • '您应该使用定时器中断并定期检查按钮的状态'。对我来说,这意味着投票。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-17
        • 1970-01-01
        • 2021-06-23
        • 2011-11-22
        相关资源
        最近更新 更多