STM32的HAL中实现单按、长按和双按功能

2024-01-07

我正在尝试实现单击、双击和长按功能来执行不同的功能。到目前为止,我已经理解了单击和长按的逻辑,但我不知道如何检测双击。至于代码,我使用计数器实现了单击和长按,但代码仅停留在第一个 if 条件上。

          bool single_press = false;
      bool long_press = false;

      if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13))
      {

          HAL_TIM_Base_Start(&htim2);
          if ((TIM2->CNT == 20) && (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)))
          {
              single_press = true;
              long_press = false;
          }
          else if ((TIM2->CNT == 799) && (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)))
          {
              single_press = true;
              long_press = true;
          }
          HAL_TIM_Base_Stop(&htim2);
      }

      if (single_press == true && long_press == false)
      {
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 1);
          HAL_Delay(1000);
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
      }
      else if (single_press == true && long_press == true)
      {
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 1);
          HAL_Delay(1000);
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 0);
      }
  }

我正在尝试实现一种情况,如果我按下按键 20 毫秒(单击一次),PB0 将变高一秒钟,如果我按下按键 800 毫秒,PB7 将变高一秒钟。然而,在运行程序时,当我按下按钮时,无论我按住按钮多长时间,PB0 都会变高,而 PB7 会保持低电平。所以我想我有两个问题:

  • 如何编辑我的代码,使得单按 PB0 变高,长按 PB7 变高?
  • 如何实现双击功能?

Thanks!


不要使用延迟作为开始。在您处于延迟状态的整个过程中,您看不到按钮正在做什么(或做任何其他对此有用的事情)。相反,您需要连续轮询(或使用中断)按钮状态,当状态发生变化时,为其添加时间戳,并根据时间做出操作决策。

首先,您需要具有去抖功能的强大按钮状态检测。有多种方法。一个例子:

bool buttonState()
{
    static const uint32_t DEBOUNCE_MILLIS = 20 ;
    static bool buttonstate = HAL_GPIO_ReadPin( GPIOC, GPIO_PIN_13 ) == GPIO_PIN_SET ;
    static uint32_t buttonstate_ts = HAL_GetTick() ;

    uint32_t now = HAL_GetTick() ;
    if( now - buttonstate_ts > DEBOUNCE_MILLIS )
    {
        if( buttonstate != HAL_GPIO_ReadPin( GPIOC, GPIO_PIN_13 ) == GPIO_PIN_SET )
        {
            buttonstate = !buttonstate ;
            buttonstate_ts = now ;
        }
    }
    return buttonstate ;
}

So buttonState()始终立即返回 - 无延迟,但在状态更改后重新读取按钮会延迟 20 毫秒,以防止将开关弹跳误解为多个状态更改。

然后,您需要一个按钮状态轮询功能来检测按钮按下和按钮弹起事件的时间。这样:

     ____________________________
____|                            |_____________
     <----long-press min-->
                           ^
                           |_Long press detected
     ______     _____
____|      |___|     |_________________________
                     ^
                     |_Double press detected
     ______
____|      |___________________________________
           <------->
              ^    ^
              |    |_Single press detected
              |_ Double press gap max.

请注意,单次按下是在按钮弹起后过了太长时间才检测到的,因此不能算是双击。以下可能需要一些调试(未经测试)作为说明:

typedef enum
{
    NO_PRESS,
    SINGLE_PRESS,
    LONG_PRESS,
    DOUBLE_PRESS
} eButtonEvent ;

eButtonEvent getButtonEvent()
{
    static const uint32_t DOUBLE_GAP_MILLIS_MAX = 250 ;
    static const uint32_t LONG_MILLIS_MIN = 800 ;
    static uint32_t button_down_ts = 0 ;
    static uint32_t button_up_ts = 0 ;
    static bool double_pending = false ;
    static bool long_press_pending = false ;
    static bool button_down = false ; ;

    eButtonEvent button_event = NO_PRESS ;
    uint32_t now = HAL_GetTick() ;

    // If state changed...
    if( button_down != buttonState() )
    {
        button_down = !button_down ;
        if( button_down )
        {
            // Timestamp button-down
            button_down_ts = now ;
        }
        else
        {
            // Timestamp button-up
            button_up_ts = now ;

            // If double decision pending...
            if( double_pending )
            {
                button_event = DOUBLE_PRESS ;
                double_pending = false ;
            }
            else
            {
                double_pending = true ;
            }

            // Cancel any long press pending
            long_press_pending = false ;
        }
    }

    // If button-up and double-press gap time expired, it was a single press
    if( !button_down && double_pending && now - button_up_ts > DOUBLE_GAP_MILLIS_MAX )
    {
        double_pending = false ;
        button_event = SINGLE_PRESS ;
    }
    // else if button-down for long-press...
    else if( !long_press_pending && button_down && now - button_down_ts > LONG_MILLIS_MIN )
    {
        button_event = LONG_PRESS ;
        long_press_pending = false ;
        double_pending = false ;

    }

    return button_event ;
}

最后你需要轮询按钮事件频繁地:

int main()
{
    for(;;)
    {
        // Check for button events
        switch( getButtonEvent() )
        {
            case NO_PRESS :     { ... } break ;
            case SINGLE_PRESS : { ... } break ;
            case LONG_PRESS :   { ... } break ;
            case DOUBLE_PRESS : { ... } break ;
        }

        // Do other work...
    }
}

了解如何没有延迟,允许您检查按钮事件并执行其他工作即时的。显然,“其他工作”也必须在没有过度延迟的情况下执行,否则会扰乱您的按钮事件计时。例如,要在单次按键上实现 1 秒输出,您可能需要:

            case SINGLE_PRESS :
            {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 1);
                single_press_ts = now ;

            } break ;

然后在 switch/case 之后:

    if( now - single_press_ts > 1000 )
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, 0);
    }

如果这是一个问题,那么您需要考虑使用中断进行按钮事件处理 - 将其与去抖动处理相结合,或者使用 RTOS 调度程序并轮询任务中的按钮事件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32的HAL中实现单按、长按和双按功能 的相关文章

  • 在 C/C++ 中读取和写入二进制文件的中间部分

    如果我有一个大的二进制文件 假设它有 100 000 000 个浮点数 C 或 C 有没有办法打开文件并读取特定的浮点数 而不必将整个文件加载到内存中 即我如何快速找出第 62 821 214 个浮点是什么 第二个问题 有没有办法更改文件中
  • C# 中的密码恢复工具不起作用

    嗨 我对此还很陌生 我创建了一个门户 用户可以登录并在其中查看我制作的其他程序 问题是密码恢复似乎不起作用 我没有收到任何错误消息 我只是收到消息 我们无法访问您的信息 请重试 我已经正确设置了 ASP NET 配置 并使用不同的用户和权限
  • 了解子表单何时关闭

    我有一个带有按钮的 Form1 当您单击按钮时 将执行以下代码块 Form2 frm new Form2 frm Name Form musteriNumarasi ToString frm Text Kullan c musteriNum
  • 验证码怎么写?

    我正在开发一个注册表 我想放置验证码 我生成一个随机字符串 但如何将其转换为图像 否则我如何开发验证码或任何参考 谢谢 Try out 验证码 http recaptcha net plugins aspnet 或查看博客文章 使用 Asp
  • DPI 图形屏幕分辨率像素 WinForm PrintPageEventArgs

    对于运行我的应用程序的任何显示器 Dpi 点与像素有何关系 int points Screen primary public Form1 InitializeComponent points 1 primary null void OnPa
  • 如何使用 PowerShell 使用 C# DLL 中存在的类的 New-Object

    例如 我有一个 C 类 public class MyComputer PSObject public string UserName get return userName set userName value private strin
  • c++1y 模式下的 Clang >= 3.3 无法解析 标头

    我有一个项目可以在 g 4 8 1 和 c 11 模式下 clang gt 3 3 下正确编译和运行 然而 当我切换到实验时 std c 1y模式下 clang 3 3 但不是 g 在
  • 如何将文本框中删除的字符替换为0

    在winforms中 如何用零替换删除的字符 例如 文本框中为 12 45 如果我们删除小数点后 它应该变成12 00 同样的方法删除前面的000 45 默认值应为 000 00 Use a 蒙版文本框 http msdn microsof
  • ReportViewer“缺少 URL 参数:名称”

    在一个网络应用程序中 我正在处理 ReportViewer 时不断出现错误 缺少 URL 参数 名称 我找到了原因 但没有找到解决方案 导致报告查看器出现异常的 url Reserved ReportViewerWebControl axd
  • C 中经过的时间

    include
  • 在大型数据绑定 ObservableCollection 中添加/删除许多项目,而无需冻结 GUI

    我和我的团队正在开发一个 WPF 应用程序 该应用程序显示多个并发 XamDataChart 控件 由 Infragistics 提供 每个图表都绑定到不同的 ObservableCollection 最多可包含 200 万个点 对于每个图
  • 在 C 中使用另一个结构中的二维结构数组的编码问题

    我正在使用一个二维结构数组 它是另一个结构的一部分 这不是我做过很多事的事情 所以我遇到了问题 该函数在接近末尾的 测试 for 循环后最终失败 它在出现段错误之前正确打印出一行 我的代码中将数据读入虚拟二维结构数组的部分工作得很好 所以它
  • 弹出窗口或弹出窗口显示附加信息

    我想在我的应用程序顶部显示带有附加信息的弹出窗口 我的信息是Listview大约 500 个项目我都尝试过 有问题flyout gt 它里面可能有scrollViewer 所以我的列表视图不能正确虚拟化 其他一切都可以 有我的代码 Flyo
  • 如何存储将被多个不同类访问的字符串常量? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 关于堆栈溢出有太多不同的答案 声明一个命名空间 并在 hpp 文件中将所有字符串标记为 extern const 并在 cpp 文件中放置它们的
  • 如果键不是映射中的初始化键,STL map[key] 返回什么? [复制]

    这个问题在这里已经有答案了 这是一些示例代码 include
  • STL(标准模板库)中使用的设计模式

    我正在学习STL和设计模式 我想知道是否有任何文档或链接可以解释如何在 STL 中实现设计模式 我做了谷歌但无法获得太多数据 我希望你的意思是 哪些设计模式可以在STL中识别 STL 堆栈是一个容器适配器 适配器是一种设计模式 迭代器也是一
  • 将 KeyUp 作为参数传递 WPF 命令绑定文本框

    我有一个文本框 KeyUp 事件触发器连接到 WPF 中的命令 我需要将按下的实际键作为命令参数传递 该命令执行得很好 但处理它的代码需要知道按下的实际键 记住这可能是一个回车键或不仅仅是一个字母的任何键 所以我无法从 TextBox te
  • 如何在 C# 中读取 Visio 文档内容

    我的DLL库代码如下 using System using IVisio Microsoft Office Interop Visio namespace Emix public class Visio protected String p
  • 如何在 MVC 5 中设置自定义 ClaimsPrincipal?

    我创建了一个自定义主体类 public class FacebookPrincipal ClaimsPrincipal public JObject Data get set 我想用它 当用户登录时 我尝试设置 var fbP new Fa
  • scanf() 不等待用户输入[重复]

    这个问题在这里已经有答案了 我正在使用 c 中的双向链表来制作树 我在该函数中使用递归调用 但不知何故它不起作用 我的代码是 struct node int data struct node right struct node left s

随机推荐

  • 如何在 C# 中表示共轭表

    我正在为法语文本设计一个语言分析器 我有一个 XML 格式的字典 如下所示
  • 使用 pytest 管理测试数据的正确方法是什么?

    我需要为多个相关应用程序创建自动化测试 并面临测试之间的测试数据管理问题 问题是相同的数据必须在多个应用程序和 或不同的 API 之间共享 现在我有了 pytest 的下一个结构 它对我很有用 但我怀疑在 conftest py 中使用测试
  • 在 PyCharm 中保存时自动添加换行符?

    PyCharm 5 抱怨文件末尾缺少换行符 如何告诉 PyCharm 在保存文件时自动添加换行符 如果丢失 这可以在Editor gt General设置 从 下的文件菜单中 选择Settings 然后选择Editor gt General
  • SSAS - 显示行上的度量

    总的来说 我对 MDX 和 SSAS 很陌生 我正在尝试以漂亮的表格形式获取所有措施和日期 所以像这样 Measure Date Value Meas1 D1 3 Meas1 D2 8 Meas1 D3 9 Meas2 D1 7 Meas2
  • 在 iOS 5 中使用 -webkit-overflow-scrolling 进行滚动的问题

    我有一个高度固定的 HTML 页面div它应该是可滚动的 仅垂直 在 iOS 5 中 这可以通过以下方式实现 overflow y auto webkit overflow scrolling touch The div包含一个大约有 10
  • 是否可以对 mysql SELECT 语句中返回列的顺序进行排序?

    想象一下在线调查中的两个问题 你喜欢苹果吗 结果存储在 mysql 数据库列 q1 中 1对于 是 或0 for No 你喜欢橙子吗 结果存储在 mysql 数据库列 q2 中 1对于 是 或0 for No 想象一下以下 SELECT 语
  • 使用 CGContext 绘制线条

    我想在表视图单元格中画线 以便可以将文本字段和开关放置在单个单元格中 我增加了单元格的高度 如何在单元格中画线 我有 UIView 的子类 其中包含以下代码 Get the CGContext from this view CGContex
  • 围绕轴标签绘制彩色框

    考虑这个简单的例子 library tidyverse tibble x as factor c good neutral bad y as factor c bad neutral bad gt ggplot aes x x y y ge
  • 在emacs中使用pdb时如何指定路径?

    我正在尝试在 emacs 中使用 pdb 我需要更改路径PYTHONPATH lib 但是当我输入时 Run pdb like this PYTHONPATH lib pdb pychess Emacs 给我一个错误 说找不到文件 PYTH
  • sqlQuery 的 RODBC 错误处理

    我没有找到任何好的错误测试函数来测试结果sqlQuery这让我很惊讶 在文档中 http www inside r org packages cran rodbc docs sqlQuery http www inside r org pa
  • 使用 PHP 显示 MySQL 数据库中的所有表?

    我正在尝试显示数据库中的所有表 我试过这个 sql SHOW TABLES result conn gt query sql tables result gt fetch assoc foreach tables as tmp echo t
  • _var 和 self.var 之间的区别

    随着所有这些新的 ARC 内容 不属于 NDA 的出现 处理属性的默认设置似乎是在实现文件中显式设置没有 ivar 的属性 直到您使用以下内容综合它 synthesize var var 设置变量的最佳实践是什么 我知道之间的区别var a
  • 将 [(key: String, value: String)] 转换为 [String:String]

    我想将 key String value String 转换为 String String 可以吗 如果是的话我怎么做 谢谢 var KeyValuePair key String value String key 2017 01 04 v
  • 检查输入时出错:预期dense_input的形状为(21,),但得到的数组的形状为(1,)

    如何修复输入数组以满足输入形状 我尝试转置输入数组 如上所述here https stackoverflow com questions 50336110 valueerror error when checking expected de
  • ACE oleDb 驱动程序无法处理巨大的 Excel 文件

    ACE OLEDB 驱动程序对于较大的文件是否存在任何已知问题 我使用下面的代码来检索 400Mb xls 文件中的工作表 public string GetWorkSheets var connectionString Provider
  • C# 中 (int) 和 Convert.toint32 之间的区别

    当我将对象转换为 int 时 int object 然后当对象值为 0 时 他会给我错误 指出特定的强制转换无效 当我将对象转换为 int 时 convert toint32 object 然后他工作并给我 0 意味着演员阵容有效 我想知道
  • 如何在 C++ 中逐行读取文件中的整数组

    我有一个文本文件 每一行都有一个或多个整数 用空格分隔 我怎样才能用 C 优雅地阅读这个内容 如果我不关心行 我可以使用 cin gt gt 但整数在哪一行很重要 输入示例 1213 153 15 155 84 866 89 48 12 1
  • WP REST API 自定义 POST 端点不工作,404 错误

    我正在编写一个插件 但我在使用自定义端点时遇到了一些问题 该端点从应用程序前端 Angular 接收数据 并将向其传递另一个函数来过滤一些数据 我对产品数据库的 GET 请求工作得很好 但 POST 只返回 404 错误 如果我在 Inso
  • 使用淡入淡出动画重绘 UIView?

    In TwUI 有一个方法叫做redraw on TUIView 它强制视图重绘 但它还带有视图的新旧状态之间的自由淡入淡出动画 我想知道在正常情况下是否可能发生类似的事情UIView 基本上 我如何重绘视图 setNeedsDisplay
  • STM32的HAL中实现单按、长按和双按功能

    我正在尝试实现单击 双击和长按功能来执行不同的功能 到目前为止 我已经理解了单击和长按的逻辑 但我不知道如何检测双击 至于代码 我使用计数器实现了单击和长按 但代码仅停留在第一个 if 条件上 bool single press false