按键进阶使用:短按、长按、连续、双击、组合键实现

[复制链接]
 楼主| zeshoufx 发表于 2022-10-24 21:17 | 显示全部楼层 |阅读模式
本帖最后由 zeshoufx 于 2022-10-24 21:19 编辑

一、按键的运用
按键作为人机交互使用最多的一种交互方式,有时候一个按键有多个功能,有时候需要多个
按键组合,实现复杂的功能,比如CTRL+C和CTRL+V,有的时候需要按下去使调节量一直
持续变化,有的时候单击和双击也在功能上做区分。

二、实现方法
通过定时器同步,根据实际需要调整不同动作的按键定时更新个数,区分各动作,并作出响应

三、关键代码
定时器初始化
  1. void timer_base_set(u16 per,u16 psc)
  2. {
  3.         timer_parameter_struct base_timer_structure;
  4.         
  5.         rcu_periph_clock_enable(RCU_TIMER6);
  6.         
  7.         base_timer_structure.alignedmode=TIMER_COUNTER_EDGE;
  8.         base_timer_structure.clockdivision=TIMER_CKDIV_DIV1;
  9.         base_timer_structure.counterdirection=TIMER_COUNTER_UP;
  10.         base_timer_structure.period=per;
  11.         base_timer_structure.prescaler=psc;
  12.         base_timer_structure.repetitioncounter=0;
  13.         
  14.         timer_init(TIMER6,&base_timer_structure);
  15.         
  16.         timer_interrupt_enable(TIMER6,TIMER_INT_UP);
  17.         nvic_irq_enable(TIMER6_IRQn,2,2);
  18.         
  19.         timer_enable(TIMER6);
  20. }
各按键动作占用定时器周期数
  1. #define     SHORT_KEY_DELAY     2                // 短按延时
  2. #define     LONG_KEY_DELAY      200                // 长按延时
  3. #define     DOUBLE_KEY_DELAY          30                // 双击两次触发之间的最大延时
  4. #define     CNTINUS_KEY_DELAY          20                // 连续触发延时

  5. #define     HW_KEYS_NUM   5 // 支持按键数量(包括独立按键+组合按键)

  6. #define     NOKEY_INPUT_VALUE   0x00 // 没有按键按下时get_key_input()的返回值
  7. #define     KEY1_INPUT_VALUE    0x01
  8. #define     KEY2_INPUT_VALUE    0x02
  9. #define     KEY3_INPUT_VALUE    0x04
  10. #define     KEY4_INPUT_VALUE    0x05
  11. #define     KEY1_2_INPUT_VALUE  (KEY1_INPUT_VALUE | KEY2_INPUT_VALUE)  // KEY1+KE2组合键
按键按下和释放的处理
  1. /**
  2. * @brief: 处于按下状态的处理:检测长按键,连续按是否有效
  3. * @author: lusd
  4. * @param [in] new_input,当前的按键输入
  5. * [url=home.php?mod=space&uid=266161]@return[/url] 按键有效则返回相应键值,无效则返回KEY_NONE
  6. */
  7. static uint8_t key_pressed_handle(uint16_t new_input)
  8. {
  9.     uint8_t res = KEY_NONE;

  10.     if (key.id < HW_KEYS_NUM)
  11.         {
  12.         key.cnt++;
  13.         if (new_input == key.last_input)
  14.                 {
  15.             if (SHORT_KEY_DELAY == key.cnt)
  16.                         {
  17.                 key.pressed = 1; // 标记按键按下生效
  18.             }
  19.                         else if (keys_info[key.id].long_cnt == key.cnt)
  20.                         { // 长按达到2秒钟
  21.                 res = keys_info[key.id].long_key_val; // 长按键值
  22.             }
  23.                         else if ((keys_info[key.id].long_cnt + CNTINUS_KEY_DELAY) == key.cnt)
  24.                         {
  25.                 // 长按2秒之后,每持续0.2秒返回一次键值
  26.                 key.cnt = keys_info[key.id].long_cnt;
  27.                 res = keys_info[key.id].cntinus_key_val; // 一直按,连续触发的键值
  28.             }
  29.         }
  30.     }
  31.     return res;
  32. }

  33. /**
  34. * @brief: 按键释放时,判定是否返回短按值或双击键值
  35. * @author: lusd
  36. * @param none.
  37. * [url=home.php?mod=space&uid=266161]@return[/url] 可能返回短按值(对不支持双击的按键),
  38. *         或双击键值(对支持双击的按键),
  39. *         无效则返回KEY_NONE
  40. */
  41. static uint8_t key_release_handle(void)
  42. {
  43.     uint8_t res = KEY_NONE;

  44.     if (key.pressed)
  45.         {
  46.         if (key.id < HW_KEYS_NUM)
  47.                 {
  48.             if (key.cnt < keys_info[key.id].long_cnt)
  49.                         { // 按下的时长,小于长按判定时间
  50.                 res = keys_info[key.id].short_key_val; // 短按键值.
  51.                 // 如果当前按键支持双击
  52.                 if (KEY_NONE != keys_info[key.id].double_key_val)
  53.                                 {
  54.                     if (key.wait_double[key.id])
  55.                                         {
  56.                         key.wait_double[key.id] = 0; // 清除等待双击标志
  57.                         key.double_timeout[key.id] = 0;
  58.                         res = keys_info[key.id].double_key_val; // 双击键值
  59.                     }
  60.                                         else
  61.                                         {
  62.                         key.wait_double[key.id] = 1; // 设置等待双击标志
  63.                         key.double_timeout[key.id] = DOUBLE_KEY_DELAY; // 设置超时时间
  64.                         key.wait_double_flag = 1;
  65.                         res = KEY_NONE;
  66.                     }
  67.                 }
  68.             }
  69.         }
  70.     }
  71.     key.cnt = 0;
  72.     key.pressed = 0;
  73.     key.last_input = NOKEY_INPUT_VALUE;

  74.     return res;
  75. }
双击
  1. /**
  2. * @brief: 判定等待双击是否超时,超时则返回短按值
  3. * @author: lusd
  4. * @param none.
  5. * @return 等待双击超时则返回短按键值,无效则返回KEY_NONE
  6. */
  7. static uint8_t key_wait_double_timeout_handle(void)
  8. {
  9.     uint8_t res = KEY_NONE;
  10.     uint8_t i;

  11.     key.wait_double_flag = 0;
  12.     for (i = 0; i < HW_KEYS_NUM; i++)
  13.         {
  14.         if (key.double_timeout[i])
  15.                 {        // 如果按键正在等待双击
  16.             key.double_timeout[i]--;
  17.             key.wait_double_flag = 1;
  18.             if (0 == key.double_timeout[i])
  19.                         { // 减到0的时刻,表示等待超时了
  20.                 key.wait_double[i] = 0; // 清除等待双击标志
  21.                 return (keys_info[i].short_key_val); // 返回该键的短按值
  22.             }
  23.         }
  24.     }
  25.     return res;
  26. }



四、开源地址和视频
【一个开源的按键处理程序-可以实现短按、长按、双击、组合】 https://www.bilibili.com/video/BV1uK411D7cq?share_source=copy_web&amp;vd_source=7f0cb9c0f09b768583faf157910eb515
视频

开源地址:
游客,如果您要查看本帖隐藏内容请回复



迟到的火车 发表于 2022-10-25 23:29 | 显示全部楼层
下载看看,是否自己需要
 楼主| zeshoufx 发表于 2022-10-26 15:26 | 显示全部楼层
迟到的火车 发表于 2022-10-25 23:29
下载看看,是否自己需要

希望对你有帮助
Rivenrealsense 发表于 2022-10-26 16:26 | 显示全部楼层
赞一个
 楼主| zeshoufx 发表于 2022-10-26 19:29 | 显示全部楼层
rgjinxuan 发表于 2022-10-26 20:10 | 显示全部楼层
感谢分享
 楼主| zeshoufx 发表于 2022-10-26 20:40 | 显示全部楼层

希望对大家有帮助,,
新下级学 发表于 2022-10-26 20:58 | 显示全部楼层
实话说我很不喜欢这种用一个键“发电报”。速度慢、容易错。类似的还有用一个灯不同闪烁表示不同信息。
 楼主| zeshoufx 发表于 2022-10-27 08:50 | 显示全部楼层
新下级学 发表于 2022-10-26 20:58
实话说我很不喜欢这种用一个键“发电报”。速度慢、容易错。类似的还有用一个灯不同闪烁表示不同信息。
...

在一些仪表里还是比较常用,,,手机好像也有,,开机键短按熄屏、长按关机或开机,音量键和开机键组合进入刷机模式
qqq_147258 发表于 2022-10-27 18:42 来自手机 | 显示全部楼层
谢谢分享,收藏备用。
imsapp 发表于 2022-10-28 00:23 | 显示全部楼层
谢谢分享
 楼主| zeshoufx 发表于 2022-10-28 08:37 | 显示全部楼层
qqq_147258 发表于 2022-10-27 18:42
谢谢分享,收藏备用。

希望对你有用
 楼主| zeshoufx 发表于 2022-10-28 20:36 | 显示全部楼层
qqq_147258 发表于 2022-10-27 18:42
谢谢分享,收藏备用。

希望对你有用
sonicll 发表于 2022-10-31 10:38 | 显示全部楼层
非常实用,感谢分享
 楼主| zeshoufx 发表于 2022-10-31 21:54 | 显示全部楼层
sonicll 发表于 2022-10-31 10:38
非常实用,感谢分享

希望对你有用
yuzhexian1 发表于 2022-11-3 11:38 | 显示全部楼层
下载看看,是否自己需要
mnynt121 发表于 2022-11-3 22:01 | 显示全部楼层
这个抬起的处理代码是怎么实现的?
tpgf 发表于 2022-11-4 17:04 | 显示全部楼层
楼主是如何处理短按情况下的防抖呢
everyrobin 发表于 2022-11-5 10:03 | 显示全部楼层
如何把这些函数和代码关联起来呢?
yorkbarney 发表于 2022-11-5 10:20 | 显示全部楼层
是否需要内部时钟对按键的时间进行判断呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

67

主题

1989

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部