硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5352|回复: 20
收起左侧

[GPIO] V7新版的按键FIFO驱动扩展和移植更简单,组合键也更好用

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
发表于 2019-3-23 02:00:20 | 显示全部楼层 |阅读模式
具体代码和移植方法等下周教程发布后,直接看教程即可。


改成下面的方式,扩展更加方便:
  1. #define HARD_KEY_NUM            8                                         /* 实体按键个数 */
  2. #define KEY_COUNT                    (HARD_KEY_NUM + 2)        /* 8个独立建 + 2个组合按键 */

  3. /* 使能GPIO时钟 */
  4. #define ALL_KEY_GPIO_CLK_ENABLE() {        \
  5.                 __HAL_RCC_GPIOB_CLK_ENABLE();        \
  6.                 __HAL_RCC_GPIOC_CLK_ENABLE();        \
  7.                 __HAL_RCC_GPIOG_CLK_ENABLE();        \
  8.                 __HAL_RCC_GPIOH_CLK_ENABLE();        \
  9.                 __HAL_RCC_GPIOI_CLK_ENABLE();        \
  10.         };

  11. /* 依次定义GPIO */
  12. typedef struct
  13. {
  14.         GPIO_TypeDef* gpio;
  15.         uint16_t pin;
  16.         uint8_t ActiveLevel;        /* 激活电平 */
  17. }X_GPIO_T;

  18. /* GPIO和PIN定义 */
  19. static const X_GPIO_T s_gpio_list[HARD_KEY_NUM] = {
  20.         {GPIOI, GPIO_PIN_8, 0},           /* K1 */
  21.         {GPIOC, GPIO_PIN_13, 0},        /* K2 */
  22.         {GPIOH, GPIO_PIN_4, 0},          /* K3 */
  23.         {GPIOG, GPIO_PIN_2, 0},         /* JOY_U */        
  24.         {GPIOB, GPIO_PIN_0, 0},         /* JOY_D */
  25.         {GPIOG, GPIO_PIN_3, 0},         /* JOY_L */        
  26.         {GPIOG, GPIO_PIN_7, 0},          /* JOY_R */        
  27.         {GPIOI, GPIO_PIN_11, 0},        /* JOY_OK */
  28. };        

  29. /* 定义一个宏函数简化后续代码
  30.         判断GPIO引脚是否有效按下
  31. */
  32. static KEY_T s_tBtn[KEY_COUNT] = {0};
  33. static KEY_FIFO_T s_tKey;                /* 按键FIFO变量,结构体 */

  34. static void bsp_InitKeyVar(void);
  35. static void bsp_InitKeyHard(void);
  36. static void bsp_DetectKey(uint8_t i);

  37. #define KEY_PIN_ACTIVE(id)        

  38. /*
  39. *********************************************************************************************************
  40. *        函 数 名: KeyPinActive
  41. *        功能说明: 判断按键是否按下
  42. *        形    参: 无
  43. *        返 回 值: 返回值1 表示按下(导通),0表示未按下(释放)
  44. *********************************************************************************************************
  45. */
  46. static uint8_t KeyPinActive(uint8_t _id)
  47. {
  48.         uint8_t level;
  49.         
  50.         if ((s_gpio_list[_id].gpio->IDR & s_gpio_list[_id].pin) == 0)
  51.         {
  52.                 level = 0;
  53.         }
  54.         else
  55.         {
  56.                 level = 1;
  57.         }

  58.         if (level == s_gpio_list[_id].ActiveLevel)
  59.         {
  60.                 return 1;
  61.         }
  62.         else
  63.         {
  64.                 return 0;
  65.         }
  66. }

  67. /*
  68. *********************************************************************************************************
  69. *        函 数 名: IsKeyDownFunc
  70. *        功能说明: 判断按键是否按下。单键和组合键区分。单键事件不允许有其他键按下。
  71. *        形    参: 无
  72. *        返 回 值: 返回值1 表示按下(导通),0表示未按下(释放)
  73. *********************************************************************************************************
  74. */
  75. static uint8_t IsKeyDownFunc(uint8_t _id)
  76. {
  77.         /* 实体单键 */
  78.         if (_id < HARD_KEY_NUM)
  79.         {
  80.                 uint8_t i;
  81.                 uint8_t count = 0;
  82.                 uint8_t save = 255;
  83.                
  84.                 /* 判断有几个键按下 */
  85.                 for (i = 0; i < HARD_KEY_NUM; i++)
  86.                 {
  87.                         if (KeyPinActive(i))
  88.                         {
  89.                                 count++;
  90.                                 save = i;
  91.                         }
  92.                 }
  93.                
  94.                 if (count == 1 && save == _id)
  95.                 {
  96.                         return 1;        /* 只有1个键按下时才有效 */
  97.                 }               

  98.                 return 0;
  99.         }
  100.         
  101.         /* 组合键 K1K2 */
  102.         if (_id == HARD_KEY_NUM + 0)
  103.         {
  104.                 if (KeyPinActive(KID_K1) && KeyPinActive(KID_K2))
  105.                 {
  106.                         return 1;
  107.                 }
  108.                 else
  109.                 {
  110.                         return 0;
  111.                 }
  112.         }

  113.         /* 组合键 K2K3 */
  114.         if (_id == HARD_KEY_NUM + 1)
  115.         {
  116.                 if (KeyPinActive(KID_K2) && KeyPinActive(KID_K3))
  117.                 {
  118.                         return 1;
  119.                 }
  120.                 else
  121.                 {
  122.                         return 0;
  123.                 }
  124.         }

  125.         return 0;
  126. }
复制代码


多次组合键不会出错了:
QQ截图20190323015828.jpg
回复

使用道具 举报

36

主题

2039

回帖

2147

积分

至尊会员

积分
2147
发表于 2019-3-23 12:01:07 | 显示全部楼层
我的板子到了,回头来个V5,V6,V7全家福
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

33

主题

203

回帖

302

积分

高级会员

积分
302
发表于 2019-3-23 14:20:37 | 显示全部楼层
扫描按键?为什么不用中断触发呢?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2019-3-23 14:54:26 | 显示全部楼层
diiiiiii 发表于 2019-3-23 14:20
扫描按键?为什么不用中断触发呢?

从裸机的角度分析
    中断方式:中断方式可以快速地检测到按键按下的,并执行相应的按键程序,但实际情况是由于按键的机械抖动特性,在程序进入中断后必须进行滤波处理才能判定是有效的按键事件。如果每个按键都是独立的接一个IO引脚,需要我们给每个IO都设置一个中断,程序中过多的中断会影响系统的稳定性,中断方式跨平台移植困难。
    查询方式:查询方式有一个最大的缺点就是需要程序定期的去执行查询,耗费一定的系统资源。实际上耗费不了多大的系统资源,因为这种查询方式也只是查询按键是否按下,按键事件的执行还是在主程序里面实现。

从OS的角度分析
    中断方式:在OS中要尽可能少用中断方式,因为在RTOS中过多的使用中断会影响系统的稳定性和可预见性(抢占式调度的OS基本没有可预见性)。只有比较重要的事件处理需要用中断的方式。
    查询方式:对于用户按键推荐使用这种查询方式来实现,现在的OS基本都带有CPU利用率的功能,这个按键FIFO占用的还是很小的,基本都在%1以下
回复

使用道具 举报

33

主题

203

回帖

302

积分

高级会员

积分
302
发表于 2019-3-23 17:46:15 | 显示全部楼层
eric2013 发表于 2019-3-23 14:54
从裸机的角度分析
    中断方式:中断方式可以快速地检测到按键按下的,并执行相应的按键程序,但实际情 ...

谢谢回复。我之前认为在大多数时间里按键都是空闲的,即没有按下。再占用定时器去不断扫描会浪费资源。
回复

使用道具 举报

609

主题

3049

回帖

4896

积分

至尊会员

积分
4896
发表于 2019-3-24 19:55:54 | 显示全部楼层
这个按键扫描方法,支持 单个按键 双击,3击 扫描检测不  ?

如果不支持,该如何修改啊 ??
回复

使用道具 举报

4

主题

140

回帖

152

积分

初级会员

积分
152
发表于 2019-3-24 21:08:49 | 显示全部楼层
工程上基本都是定时扫描,放后台或者某个优先级低的定时里面做就行。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2019-3-25 02:41:46 | 显示全部楼层
hpdell 发表于 2019-3-24 19:55
这个按键扫描方法,支持 单个按键 双击,3击 扫描检测不  ?

如果不支持,该如何修改啊 ??

这种要求的话,程序无需修改,仅需在按键按下后记录当前时刻,下次再按下时求个差值就行。
回复

使用道具 举报

609

主题

3049

回帖

4896

积分

至尊会员

积分
4896
发表于 2019-3-25 09:30:22 | 显示全部楼层
eric2013 发表于 2019-3-25 02:41
这种要求的话,程序无需修改,仅需在按键按下后记录当前时刻,下次再按下时求个差值就行。

好的,我试试看
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2020-9-25 09:40:55 | 显示全部楼层
我把按键个数改成2, GPIO和PIN定义那里改成我的按键,然后打印键值。两个按键键值相同,也不知道咋回事?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2020-9-25 10:45:48 | 显示全部楼层
晚起的鸟 发表于 2020-9-25 09:40
我把按键个数改成2, GPIO和PIN定义那里改成我的按键,然后打印键值。两个按键键值相同,也不知道咋回事?

上修改后的代码看看。
回复

使用道具 举报

12

主题

176

回帖

212

积分

高级会员

积分
212
发表于 2020-9-28 09:51:41 | 显示全部楼层
晚起的鸟 发表于 2020-9-25 09:40
我把按键个数改成2, GPIO和PIN定义那里改成我的按键,然后打印键值。两个按键键值相同,也不知道咋回事?

这个问题就是下面这段代码的问题:
除了组合键之外,其他按键同时只能检测一个按键
static uint8_t IsKeyDownFunc(uint8_t _id)
{
        /* 实体单键 */
        if (_id < HARD_KEY_NUM)
        {
                uint8_t i;
                uint8_t count = 0;
                uint8_t save = 255;
               
                /* 判断有几个键按下 */
                for (i = 0; i < HARD_KEY_NUM; i++)
                {
                        if (KeyPinActive(i))
                        {
                                count++;
                                save = i;
                        }
                }
               
                if (count == 1 && save == _id)
                {
                        return 1;        /* 只有1个键按下时才有效 */
                }               

                return 0;
        }
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2020-9-29 05:23:57 | 显示全部楼层
gallop020142 发表于 2020-9-28 09:51
这个问题就是下面这段代码的问题:
除了组合键之外,其他按键同时只能检测一个按键
static uint8_t IsK ...

他说的是检查到的两个按键的键值相同,跟这个没关系。
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2022-2-24 09:53:25 | 显示全部楼层
有BUG,长按一个按键的时候,去单击另一个按键会识别成长按的按键单击
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2022-2-24 10:32:37 | 显示全部楼层
核弹 发表于 2022-2-24 09:53
有BUG,长按一个按键的时候,去单击另一个按键会识别成长按的按键单击

自己的程序里面加个简单的变量处理即可,检测到长按后设置变量,其它按键检查到次变量设置读取出来的消息不错处理,
本质原因是这个按键FIFO没有做长按+另一个键的消息处理。
回复

使用道具 举报

19

主题

62

回帖

119

积分

初级会员

积分
119
发表于 2022-2-24 19:26:51 | 显示全部楼层
本帖最后由 mojinpan 于 2022-2-25 11:20 编辑

我提供一个更精简的按键驱动,支持各种单击,双击,长按,shift按键等多种功能,而且支持到最多64个按键全并发处理
https://github.com/mojinpan/keykey.h
  1. /** ****************************************************************************
  2. * @file         key.h
  3. * @author         mojinpan
  4. * @copyright (c) 2018 - 2020 mojinpan
  5. * @brief         按键驱动
  6. *
  7. * @par 功能说明
  8. * @details
  9. * 1.支持最大64个按键(数量可配置)
  10. * 2.支持按键消抖处理(可滤掉小于2个扫描周期的毛刺)
  11. * 3.支持按键环形缓冲区(长度可配置)
  12. * 4.支持4种不同按键模式:A:短按键 B:shift键 C:长按单发 D:长按连发
  13. * 5.短按键    :短按直接输出键值
  14. * 6.shift键  :点击后除了输出一次短按键外,还将后续所有其他按键的键值改为,shift键+按键值(包括长短按键)
  15. * 7.长按连发  :长按一定时间后连续输出按键键值
  16. * 8.长按单发  :长按一定时间后反码输出键值(仅一次)
  17. * 9.4种不同按键模式可相互叠加使用,所有按键功能都能并发输出
  18. *
  19. * @par 移植说明
  20. * @details
  21. * 1.根据具体情况编写KeyIOread()和KeyInit().
  22. * 2.每20ms~50ms调用KeyScan()扫描按键,调用KeyGetBufLen()判断是否有按键,调用KeyGet()获得按键值.
  23. *******************************************************************************/
  24. #ifndef __KEY__
  25. #define __KEY__

  26. /*******************************************************************************
  27.                               Header Files        头文件
  28. *******************************************************************************/
  29. #include "bsp.h"
  30. #include "stdbool.h"
  31. #include "stdint.h"
  32. /*******************************************************************************
  33.                                Key Scancode        按键扫描码
  34. *******************************************************************************/
  35. ///* @brief 按键键值,每个按键占1bit,不得重复
  36. typedef enum
  37. {
  38.     KEY_UP             = 0x0001,
  39.     KEY_DN             = 0x0002,     
  40.     KEY_LT             = 0x0004,
  41.     KEY_RT             = 0x0008,  
  42.     KEY_ENT            = 0x0010,
  43.     KEY_ESC            = 0x0020,
  44.     KEY_INC            = 0x0040,
  45.     KEY_DEC            = 0x0080,
  46.     KEY_FUN            = 0x0100
  47.        
  48.     KEY_UP_L          = 0xFFFE,       
  49.     KEY_DN_L          = 0xFFFD,
  50.        
  51.     KEY_UP_SF    = 0x0101,
  52.     KEY_DN_SF    = 0x0102,
  53.     KEY_LT_SF    = 0x0104,
  54.     KEY_RT_SF    = 0x0108,  
  55.     KEY_ENT_SF   = 0x0110,
  56.     KEY_ESC_SF   = 0x0120,
  57.     KEY_INC_SF   = 0x0140,
  58.     KEY_DEC_SF   = 0x0180       
  59. } KEY_value;
  60. /*******************************************************************************
  61.                                 Drive Config        驱动配置
  62. *******************************************************************************/
  63. #define KEY_MAX_NUM       11                       //定义最大按键数量(1~64)
  64. #define KEY_BUF_SIZE      8                        //定义按键缓冲区大小(2,4,8,16,32,64,128,256)
  65. #define KEY_LONG_EN       1                        //定义是否支持长按键(1 or 0)
  66. #define KEY_SHORT_SHIFT   KEY_FUN            //定义shift键,短按有效(0 or 按键扫描码)

  67. #if KEY_LONG_EN > 0
  68. #define KEY_PRESS_DLY     40                   //定义长按键延时n个扫描周期开始判定有效值(1~256)
  69. #define KEY_PRESS_TMR     5                        //定义长按键n个扫描周期为1次有效扫描值(1~256)
  70. #define KEY_LONG_SHIFT    KEY_UP|KEY_DN  //长按键反码输出(仅一次),未定义的长按连续输出(0 or 按键扫描码)
  71. #endif
  72. /*******************************************************************************
  73.                                                                 Function declaration 函数声明
  74. *******************************************************************************/
  75. void KeyInit(void);               //按键初始化函数
  76. void KeyScan(void);               //按键扫描函数,20ms~50ms定时调用
  77. uint8_t KeyGetBufLen(void);       //按键判断函数,判断是否有按键按下
  78. uint32_t KeyGet(void);            //按键获得函数,获取具体按键值,无按键时返回0
  79. void KeyFlush(void);                          //清空按键buf
  80. #endif
复制代码

key.c
  1. /** ****************************************************************************
  2. * @file                 key.c
  3. * @author         mojinpan
  4. * @copyright (c) 2018 - 2020 mojinpan
  5. * @brief                 按键驱动
  6. *
  7. * @version         V0.1
  8. * @date                 2011-3-2
  9. * @details
  10. * 1.支持矩阵键盘和IO按键两种
  11. * 2.支持长按键和短按键两种触发方式。
  12. *
  13. * @version         V0.2
  14. * @date                 2011-3-5
  15. * @details
  16. * 1.最大按键数量16个,可继续扩充至64个.
  17. * 2.支持长按键和短按键并行触发.
  18. * 3.增加短按键部分改为按键释放时返回.
  19. *
  20. * @version         V0.3
  21. * @date                 2013-11-4
  22. * @details
  23. * 1.重写按键获取的逻辑,长按键算法不成熟,暂时去掉
  24. * 2.矩阵按键没用到,暂时去掉
  25. * 3.增加按键消抖算法
  26. *
  27. * @version         V0.4
  28. * @date                 2013-11-6
  29. * @details
  30. * 1.增加环形buf
  31. * 2.重写接口函数,便于在OS环境中调用,当然裸奔也支持.
  32. * c_cpp_properties.json
  33. * @version         V0.5
  34. * @date                 2013-11-6
  35. * @details
  36. * 1.增加长按键的支持
  37. * 2.增加shift键的支持
  38. * 3.增加按键数量的定义,定义后根据按键数量选择合适的数据类型,从而节省ram和rom
  39. * 4.处于兼容性的考虑,将最大按键支持数量由64个缩减至32个
  40. *
  41. * @version         V0.6
  42. * @date                 2013-11-24
  43. * @details
  44. * 1.修正长按键输出后,还输出短按键的bug
  45. * 2.修改的KeyScan()的逻辑,将长按键细分为长按键连续输出和长按键反码输出(仅一次)两种方式
  46. * 3.shift键按下时也提供按键值输出,方便应用程序判断shift键的状态
  47. * 4.由于第3点的修改,短按键和shift键不在冲突,即长按键/短按键/shift键相互独立
  48. * 5.将无按键返回0xff,改成返回0
  49. * 6.增加一个KeyFlush()函数,用于清空buf
  50. *
  51. * @version         V0.7
  52. * @date                 2019-04-26
  53. * @details
  54. * 1.参照liunx上kfifo的代码优化环形buf的算法.
  55. * 2.将KeyHit()函数重命名为KeyBufLen()函数,将返回有无按键改为返回按键缓冲数量.
  56. * 3.KEY_TYPE 改为使用stdint.h中的数据类型定义,并重新启用64个按键的支持
  57. *******************************************************************************/

  58. #include "bsp.h"
  59. #include "key.h"

  60. /*******************************************************************************
  61.                            Macro Definition    宏定义
  62. *******************************************************************************/
  63. #if   KEY_MAX_NUM > 32
  64. #define KEY_TYPE    uint64_t
  65. #elif   KEY_MAX_NUM > 16
  66. #define KEY_TYPE    uint32_t
  67. #elif KEY_MAX_NUM > 8
  68. #define KEY_TYPE    uint16_t
  69. #else
  70. #define KEY_TYPE    uint8_t
  71. #endif
  72. /*******************************************************************************
  73.                             Global Variables    全局变量
  74. *******************************************************************************/
  75. static  KEY_TYPE PreScanKey  = 0;               //前次按键扫描值      
  76. static  KEY_TYPE PreReadKey  = 0;               //前次按键读取值        
  77. static  KEY_TYPE KeyShift    = 0;               //shift按键记录
  78. static  KEY_TYPE KeyMask     = 0;               //按键掩码
  79. #if LONG_KEY_EN > 0
  80. static  uint8_t  KeyPressTmr = 0;                           //长按键判断周期
  81. #endif

  82. static KEY_TYPE KeyBuf[KEY_BUF_SIZE];           //环形buf
  83. static uint8_t  KeyBufInIdx  = 0;               //buf入指针                  
  84. static uint8_t  KeyBufOutIdx = 0;               //buf出指针
  85. /** ****************************************************************************
  86. @brief  按键扫描函数,需根据实际硬件情况进行移植
  87. @note   所有按键均必须高电平有效
  88. *******************************************************************************/
  89. __weak static KEY_TYPE  KeyIOread( void )
  90. {
  91.     KEY_TYPE KeyScanCode=0;
  92.    
  93.         KeyScanCode |= GPIO_IN(K_UP ) ? 0 : KEY_UP ;
  94.         KeyScanCode |= GPIO_IN(K_DN ) ? 0 : KEY_DN ;
  95.         KeyScanCode |= GPIO_IN(K_LT ) ? 0 : KEY_LT ;
  96.         KeyScanCode |= GPIO_IN(K_RT ) ? 0 : KEY_RT ;
  97.         KeyScanCode |= GPIO_IN(K_ENT) ? 0 : KEY_ENT;
  98.         KeyScanCode |= GPIO_IN(K_ESC) ? 0 : KEY_ESC;
  99.         KeyScanCode |= GPIO_IN(K_INC) ? 0 : KEY_INC;
  100.         KeyScanCode |= GPIO_IN(K_DEC) ? 0 : KEY_DEC;
  101.         KeyScanCode |= GPIO_IN(K_FUN) ? 0 : KEY_FUN;
  102.        
  103.   return KeyScanCode;
  104. }

  105. /** ****************************************************************************
  106. @brief  从buf中获得一个按键值
  107. @return 返回按键值,无按键返回0xFF
  108. *******************************************************************************/
  109. static KEY_TYPE KeyBufOut (void)
  110. {
  111.     if(KeyBufOutIdx == KeyBufInIdx) return 0;            //buf空
  112.     return KeyBuf[KeyBufOutIdx++ & (KEY_BUF_SIZE- 1)];   //返回按键值
  113. }
  114. /** ****************************************************************************
  115. @brief  将按键值放入buf中
  116. @param  code: 需放入buf的按键值
  117. *******************************************************************************/
  118. static void  KeyBufIn (KEY_TYPE code)
  119. {                        
  120.     if(KeyBufInIdx - KeyBufOutIdx == KEY_BUF_SIZE)
  121.     {
  122.         KeyBufOutIdx++;//buf满则放弃最早的一个按键值
  123.     }

  124.     KeyBuf[KeyBufInIdx++ & (KEY_BUF_SIZE- 1)] = code ;
  125. }

  126. /** ****************************************************************************
  127. @brief  按键扫描
  128. @details
  129. 1.功能说明
  130.   a.按键消抖
  131.   b.捕捉长按键和短按键
  132.   c.根据设置将按键分成短按键/长按连续建/短按shift键/长按shift键4种方式写入buf
  133. 2.算法说明
  134.   a.按键获取算法
  135.     1).NowKey & PreKey                                : 电平触发
  136.     2).NowKey ^ PreKey                                : 边缘触发
  137.     3).NowKey & (NowKey ^ PreKey)或(~PreKey) & NowKey : 上升沿触发
  138.     4).PreKey & (NowKey ^ PreKey)或PreKey & (~NowKey) : 下降沿触发
  139.   b.滤波算法
  140.     1).PreScanKey & NowScanKey                        : 电平触发
  141.     2).PreReadKey & (PreScanKey ^ NowScanKey)         : 采样保持
  142.     3).NowReadKey = 1) | 2)                           : 带采样保持的电平触发
  143. 3.调用说明
  144.   a.对下调用的KeyIOread()中,有效按键必须为高电平,且每个bit表示一个按键值
  145.   b.应用调用该函数的间隔应该在20ms~50ms,在调用间隔内的毛刺均可滤除。
  146. *******************************************************************************/
  147. void KeyScan(void)
  148. {
  149.   KEY_TYPE NowScanKey   = 0;                                //当前按键值扫描值
  150.   KEY_TYPE NowReadKey   = 0;                                //当前按键值
  151. //KEY_TYPE KeyPressDown = 0;                                //按键按下                                    
  152.   KEY_TYPE KeyRelease   = 0;                                //按键释放                                                           
  153.   NowScanKey  = KeyIOread();
  154.   NowReadKey  = (PreScanKey&NowScanKey)|                    //电平触发
  155.                  PreReadKey&(PreScanKey^NowScanKey);        //采样保持(即消抖)

  156. //KeyPressDown  = NowReadKey & (NowReadKey ^ PreReadKey);   //上升沿触发  
  157.   KeyRelease    = PreReadKey & (NowReadKey ^ PreReadKey);   //下降沿触发   

  158. #if LONG_KEY_EN > 0                                         
  159.   if(NowReadKey == PreReadKey && NowReadKey)                                 //用电平触发做长按键的有效判据
  160.   {              
  161.     KeyPressTmr++;
  162.     if(KeyPressTmr >= KEY_PRESS_TMR)                                                //长按判断周期到,保存相应长按键值
  163.         {                       
  164.       if(NowReadKey & ~(KEY_LONG_SHIFT))                                        //长按键模式一
  165.           {                  
  166.         KeyBufIn(NowReadKey | KeyShift);                    //长按键重复输出
  167.       }
  168.       else if(NowReadKey & (KEY_LONG_SHIFT) & ~KeyMask )        //长按键模式二
  169.           {         
  170.         KeyBufIn(~(NowReadKey | KeyShift));                 //长按键反码输出作为第二功能键      
  171.       }
  172.       KeyPressTmr = 0;                                                  //重置连按周期,准备获取下1个长按键
  173.       KeyMask = NowReadKey;
  174.     }
  175.   }
  176.   else{
  177.     KeyPressTmr = KEY_PRESS_DLY;                            //按键变化,重置按键判断周期
  178.   }
  179. #endif

  180.   if(KeyRelease)
  181.   {                                                                           //短按键判断
  182.       if(KeyRelease &(~KeyMask)&& !NowReadKey)
  183.           {
  184.         KeyShift ^= (KeyRelease & (KEY_SHORT_SHIFT));       //shift按键码(边缘触发)
  185.         KeyBufIn(KeyRelease | KeyShift | PreReadKey);
  186.       }
  187.           else
  188.           {
  189.         KeyMask = 0;
  190.       }
  191.   }
  192.   
  193.   PreScanKey = NowScanKey;
  194.   PreReadKey = NowReadKey;
  195. }

  196. /** ****************************************************************************
  197. @brief  按键初始化
  198. *******************************************************************************/
  199. __weak void KeyInit( void )
  200. {
  201.         //按键初始化,输入,浮空,低速
  202.         GpioInit2Input(K_UP  ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  203.         GpioInit2Input(K_DN  ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);               
  204.         GpioInit2Input(K_LT  ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  205.         GpioInit2Input(K_RT  ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  206.         GpioInit2Input(K_ENT ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  207.         GpioInit2Input(K_ESC ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  208.         GpioInit2Input(K_INC ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  209.         GpioInit2Input(K_DEC ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);       
  210.         GpioInit2Input(K_FUN ,GPIO_NOPULL,GPIO_SPEED_FREQ_LOW);            
  211. }

  212. /** ****************************************************************************
  213. @brief  从buf中获得一个按键值
  214. @return 回按键值,无按键返回0xFF
  215. *******************************************************************************/
  216. uint32_t  KeyGet(void)
  217. {                        
  218.   return (uint32_t)KeyBufOut();
  219. }     

  220. /** ****************************************************************************
  221. @brief  判断是否有按键按下
  222. @return buf中按键的数量
  223. *******************************************************************************/
  224. uint8_t  KeyGetBufLen (void)
  225. {
  226.    return KeyBufInIdx - KeyBufOutIdx;
  227. }

  228. /** ****************************************************************************
  229. @brief  清空buff中所有按键值
  230. *******************************************************************************/
  231. void KeyFlush(void)
  232. {
  233.    KeyBufOutIdx = KeyBufInIdx;
  234. }
复制代码



回复

使用道具 举报

9

主题

42

回帖

69

积分

初级会员

积分
69
QQ
发表于 2024-2-21 18:59:18 | 显示全部楼层
eric2013 发表于 2022-2-24 10:32
自己的程序里面加个简单的变量处理即可,检测到长按后设置变量,其它按键检查到次变量设置读取出来的消息 ...

这个功能是否可以规范到现在的按键处理函数中。因为用的按键都是不能自恢复的,会使用同时几个按键按下的情况处理
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2024-2-22 09:01:28 | 显示全部楼层
wgco98 发表于 2024-2-21 18:59
这个功能是否可以规范到现在的按键处理函数中。因为用的按键都是不能自恢复的,会使用同时几个按键按下的 ...

好的,如果后面还有机会的话,升级个新版本。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2024-3-21 20:58:32 | 显示全部楼层
请问如果按键按下时,是低电平,即按键按下时,io口接地,这个程序要怎么改?
/* GPIO和PIN定义 */
static const X_GPIO_T s_gpio_list[HARD_KEY_NUM] = {
        {GPIOA, GPIO_PIN_0, 1},                /* K1 */
        {GPIOC, GPIO_PIN_13, 1},        /* K2 */       
        {GPIOG, GPIO_PIN_13, 0},                /* K3 */
        {GPIOG, GPIO_PIN_14, 0},                /* K4 */       
};       

是只需要将这里的激活状态设置为0嘛?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106685
QQ
 楼主| 发表于 2024-3-22 08:55:03 | 显示全部楼层
桃子不逃 发表于 2024-3-21 20:58
请问如果按键按下时,是低电平,即按键按下时,io口接地,这个程序要怎么改?
/* GPIO和PIN定义 */
stati ...

对,就是这个。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2024-4-14 23:20:02 | 显示全部楼层
FREETROS  系统下的  按键FIFO  八个串口FIFO  例程有吗?  
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-30 00:04 , Processed in 0.378480 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表