硬汉嵌入式论坛

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

[客户分享] 【按键检测-功能大全】基于硬汉程序思想-进行深度优化

  [复制链接]

3

主题

16

回帖

25

积分

新手上路

积分
25
发表于 2019-12-31 17:14:27 | 显示全部楼层 |阅读模式
本帖最后由 czm_hyt@163.com 于 2020-6-17 17:22 编辑

本人刚学习STM32开发,最近看了硬汉的按键检测程序,进行了架构的深度优化,所以跟大家分享一下:本人使用的STM32F103,有6个独立的按键;A、B、C、D、OK、Power,目前实现的功能如下:

1:单键短按,长按,连发,双击,3连击。。。。。最多不限制;

2:各种组合按键,组合按键的短按,长按,连发,组合按键的双击,连击;

3:这些功能都可以随意配置;

性能测试,STM32使用内部时钟,64M,有按键的时候,按键扫描函数执行时间是12us;

程序先不跟大家分享了,分享一下我对按键扫描的理解和实现的大概流程:

*********************************************************************************************************
*        虚拟按键扫描功能说明:V1.0-2019.12.30

按键定义:单键/多键;单击/组合(连击);短按/长按;连发;

注:对于应用层来说,组合也是单击,不需要标识出来。A和B组合生效,可以单键A和单键B组合,也可以是多键AB单击;

定义说明:
1: 单键/多键:只有1个按键变化;多键:2个及以上的按键同变化(变化的时间接近即可,底层滤波自动处理,总线滤波参数控制);
    后文中提到的“按键”,包括单键或者多键,多键也可以称之为一个按键!!!,大家认为的组合按键的双击,我们称之为多键连击;
    “不同的按键”不能有相同的部分,如单键A,和多键AB不是不相同的按键;

2: 单击:设定的时间内,有按键(单键或多键)按下1次;如不支持连击/组合,单击:有按键(单键或多键)按下1次;

3: 组合:设定的时间内,有多个不同的按键(单键或者多键)按下1次;单键和单键,单键和多键,多键和多键都可以组合;

4: 连击:设定的时间内,相同的按键(单键或多键)按下2次及以上;

5: 长按:单击/组合/连击发生后,并且持续稳定的时间超过设定的时间阈值;

6: 连发:单击/组合/连击长按之后,按照设定的周期,不断的产生单击/组合/连击事件;

注:设定的时间内,要么发生连击,要么发生不同的按键进行组合,两者为互斥事件;
    按照时间顺序排列,有几个按键(单键还是多键),是单击还是组合还是连击,稳定之后是长按,还是短按,长按之后是否连发;


按键扫描流程:
1: 将物理按键映射到逻辑按键上,多个按键映射成并口的数据通道,按键检测,转换成采集通道上的数据。

2:  某一个数据线上不用独立滤波,而是进行总线数据滤波。也就是多个按键一起滤波;

3: 组合/连击:总线上有数据时(有按键按下后),开始定时,发生数据变化时(又有按键按下),判断是组合,还是连击,
    连击是只指相同的按键,组合是指不同的按键;    连击时,按键次数增加,组合时,有效按键个数增加,组合和连击,只能发生一个;

4: 连击时,可以复位定时器,组合时,可以不复位,也可以复位,正常不需要复位;

*********************************************************************************************************


欢迎各位群友交流讨论,共同进步!

  1. /*******************************************************************************
  2. * Copyright (C), 1993-2012, Liming Comm. Co., Ltd.
  3. * @file    :RM_KEY.c
  4. * @brief   :虚拟按键扫描
  5. * @author  :czm_hyt@163.com
  6. * @version :V1.0
  7. * @date    :2019-11-15
  8. * @time    :20:22:35
  9. *

  10. ******************************************************************************
  11. * 函数列表   
  12. *            
  13. * 1. Enter the name of the  first function
  14. * 2. Enter the name of the second function
  15. ******************************************************************************
  16. * 修改历史   
  17. *
  18. * 2019-11-15                 czm                  建立文件     
  19. *******************************************************************************/

  20. /*
  21. *********************************************************************************************************
  22. *   虚拟按键扫描功能说明:V1.0-2019.12.30

  23. 按键定义:单键/多键;单击/组合(连击);短按/长按;连发;

  24. 注:对于应用层来说,组合也是单击,不需要标识出来。A和B组合生效,可以单键A和单键B组合,也可以是多键AB单击;

  25. 定义说明:
  26. 1: 单键/多键:只有1个按键变化;多键:2个及以上的按键同变化(变化的时间接近即可,底层滤波自动处理,总线滤波参数控制);
  27.     后文中提到的“按键”,包括单键或者多键,多键也可以称之为一个按键!!!,大家认为的组合按键的双击,我们称之为多键连击;
  28.     “不同的按键”不能有相同的部分,如单键A,和多键AB不是不相同的按键;

  29. 2: 单击:设定的时间内,有按键(单键或多键)按下1次;如不支持连击/组合,单击:有按键(单键或多键)按下1次;

  30. 3: 组合:设定的时间内,有多个不同的按键(单键或者多键)按下1次;单键和单键,单键和多键,多键和多键都可以组合;

  31. 4: 连击:设定的时间内,相同的按键(单键或多键)按下2次及以上;

  32. 5: 长按:单击/组合/连击发生后,并且持续稳定的时间超过设定的时间阈值;

  33. 6: 连发:单击/组合/连击长按之后,按照设定的周期,不断的产生单击/组合/连击事件;

  34. 注:设定的时间内,要么发生连击,要么发生不同的按键进行组合,两者为互斥事件;
  35.     按照时间顺序排列,有几个按键(单键还是多键),是单击还是组合还是连击,稳定之后是长按,还是短按,长按之后是否连发;


  36. 按键扫描流程:
  37. 1: 将物理按键映射到逻辑按键上,多个按键映射成并口的数据通道,按键检测,转换成采集通道上的数据。

  38. 2:  某一个数据线上不用独立滤波,而是进行总线数据滤波。

  39. 3: 组合/连击:总线上有数据时(有按键按下后),开始定时,发生数据变化时(又有按键按下),判断是组合,还是连击,
  40.     连击是只指相同的按键,组合是指不同的按键;    连击时,按键次数增加,组合时,有效按键个数增加,组合和连击,只能发生一个;

  41. 4: 连击时,可以复位定时器,组合时,可以不复位,也可以复位,正常不需要复位;
  42.   
  43. *********************************************************************************************************
  44. */

  45. #include "RM_KEY.h"

  46. static RM_KEY_CONFIG_T s_RM_KEY_CFG = {0};

  47. // RM 硬件键实时运行状态
  48. static RM_KEY_RUN_DATA_T s_tRmKeyRunData = {0};

  49. //  硬件按键GPIO和PIN定义
  50. static const RM_KEY_GPIO_DEF_T s_atRmKeyGpioDef[RM_HARD_KEY_NUM] =
  51. {
  52.     // 按键都是高电平有效 TRUE
  53.     {GPIOA, GPIO_Pin_4,  TRUE},     // KEY A    按键 PA4
  54.     {GPIOC, GPIO_Pin_0,  TRUE},     // KEY B    按键 PC0
  55.     {GPIOC, GPIO_Pin_15, TRUE},     // KEY C    按键 PC15
  56.     {GPIOC, GPIO_Pin_5,  TRUE},     // KEY D    按键 PC5
  57.     {GPIOC, GPIO_Pin_14, TRUE},     // KEY OK   按键 PC14
  58.     {GPIOA, GPIO_Pin_0,  TRUE},     // Power    按键 PA0
  59. };

  60. /**
  61. * @brief 虚拟按键转化表,将所有实体按键都转换成一个bit
  62. */
  63. static const u8 s_auKeyBitDef[RM_HARD_KEY_NUM] =
  64. {
  65.     // 单按键定义 A、B、C、D、OK、Power
  66.     0x01, 0x02, 0x04, 0x08, 0x010, 0x20,
  67.     // 组合按键定义
  68. };

  69. // 可以用于LCD 没有操作时息屏 有操作时亮屏
  70. ///* 用于按键超时进入屏保 */
  71. //static int32_t s_KeyTimeOutCount = 0;
  72. //static uint8_t s_LcdOn = 1;



  73. /**
  74. * @brief   计算8位数据中1的个数
  75. *
  76. * @param [in] uData       需要计算的数据,8位
  77. *
  78. * @return  数据中1的个数
  79. * @author  
  80. * @since   trunk.00001
  81. * @bug
  82. */
  83. u8 Ones8(u8 uData)
  84. {
  85.     uData -= ((uData >> 1) & 0x55);
  86.     uData  = (((uData >> 2) & 0x33) + (uData & 0x33));
  87.     uData += (uData >> 4);

  88.     return (uData & 0x0F);
  89. }



  90. /**
  91. * @brief   判断单独按键管脚是否有效 对上屏蔽底层 对上TRUE就是有效,FALSE就是弹开
  92. *
  93. * @param [in] nKeyID       按键ID 0 ~ RM_HARD_KEY_NUM-1
  94. *
  95. * @return  TRUE:按键有效;FALSE:按键无效
  96. * @author  
  97. * @since   trunk.00001
  98. * @bug
  99. */
  100. static BOOL RM_KEY_IsActive(RM_KEY_ID_E nKeyID)
  101. {
  102.     BOOL bPinLevel;

  103.     // 判断按键管脚IO电平 TRUE:高电平
  104.     if (s_atRmKeyGpioDef[nKeyID].ptGpio->IDR & s_atRmKeyGpioDef[nKeyID].u2Pin)
  105.     {
  106.         bPinLevel = TRUE;
  107.     }
  108.     else
  109.     {
  110.         bPinLevel = FALSE;
  111.     }

  112.     if (bPinLevel == s_atRmKeyGpioDef[nKeyID].bActiveLevel)
  113.     {
  114.         return TRUE;
  115.     }
  116.     else
  117.     {
  118.         return FALSE;
  119.     }

  120. }

  121. // A和B如果几乎同时按下 滤波时间会增加2倍数,此时认为AB是同时按下的

  122. /**
  123. * @brief   更新按键管脚状态 带逻辑整体滤波 非物理
  124. * @brief   将每一个实体按键转化成1 bit,便于虚拟按键映射
  125. *
  126. * @param [in] nKeyID       按键ID 0 ~ RM_HARD_KEY_NUM-1
  127. *
  128. * @return  TRUE:按键有效;FALSE:按键无效
  129. * @author  
  130. * @since   trunk.00001
  131. * @bug
  132. */
  133. // 需要优化
  134. static void RM_KEY_Update(void)
  135. {
  136.     static u8 s_uRmKeyBusData   = 0;    // 上一次Key总线数据
  137.     u8 uRmKeyBusData_New        = 0;    // 最新Key总线数据
  138.     u8 uTemp                    = 0;
  139.    

  140.     // 按键按下,对应比特置1,物理按键转逻辑按键
  141.     for (uTemp = 0; uTemp < RM_HARD_KEY_NUM; uTemp++)
  142.     {   
  143.         if (RM_KEY_IsActive(uTemp))
  144.         {
  145.             uRmKeyBusData_New |= s_auKeyBitDef[uTemp];
  146.         }   
  147.     }

  148.     // 滤波的定义:相同状态持续设置的阈值 状态就生效
  149.     if (s_uRmKeyBusData == uRmKeyBusData_New)     // 最新状态与上次的状态相同,计数判断稳定时间
  150.     {
  151.         if (s_RM_KEY_CFG.uFilterCtr > s_tRmKeyRunData.uFIlterCount)
  152.         {
  153.             s_tRmKeyRunData.uFIlterCount++;
  154.         }        
  155.         else if (s_RM_KEY_CFG.uFilterCtr == s_tRmKeyRunData.uFIlterCount)    // 稳定时间达到滤波阈值
  156.         {
  157.             s_RM_KEY_CFG.uRmKeyBusData  = uRmKeyBusData_New;    // 更新最新的按键状态
  158.             s_RM_KEY_CFG.uKeyBusDataCnt = Ones8(s_RM_KEY_CFG.uRmKeyBusData);
  159.             s_tRmKeyRunData.uFIlterCount++;     // 只更新一次
  160.         }
  161.         // 按键总线数据稳定后,也要判断是否与记录的状态同步
  162.         else if (uRmKeyBusData_New != s_RM_KEY_CFG.uRmKeyBusData)
  163.         {
  164.             s_tRmKeyRunData.uFIlterCount = 0;   // 状态不同步 启动滤波更新
  165.         }
  166.     }
  167.     else    // 状态只要发生变化,就启动一次状态更新
  168.     {
  169.         s_tRmKeyRunData.uFIlterCount = 0;           // 启动一次状态更新 带滤波      
  170.         s_uRmKeyBusData = uRmKeyBusData_New;        // 状态发生变化 更新保存
  171.     }
  172. }


  173. /**
  174. * @brief   将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
  175. *
  176. * @param [in] nKeyMsgCode       按键代码
  177. *
  178. * @return 无
  179. * @author  
  180. * @since   trunk.00001
  181. * @bug
  182. */
  183. void RM_KEY_PutKeyMsg(u16 u2KeyMsgCode)
  184. {
  185.     // 有按键按下 可以开屏幕背光 进行省点相关操作
  186.    
  187.     s_tRmKeyRunData.u2MsgBuf[s_tRmKeyRunData.uWriteAddr] = u2KeyMsgCode;

  188.     if (RM_KEY_MSG_FIFO_SIZE <= (++s_tRmKeyRunData.uWriteAddr))
  189.     {
  190.         s_tRmKeyRunData.uWriteAddr = 0;
  191.     }
  192.             
  193. //    s_KeyTimeOutCount = GetSleepTimeMinute() * 60 * 100u;  /* 10ms单位 */
  194. }

  195. //{
  196. ////    /* 屏幕熄灭阶段,丢弃唤醒键 */
  197. ////    if (s_LcdOn == 0)
  198. ////    {        
  199. ////        u8 key;
  200. ////        
  201. ////        key = ((_KeyCode - 1) % KEY_MSG_STEP) + 1;
  202. ////        if (key == KEY_1_UP || key == KEY_1_LONG_UP)
  203. ////        {
  204. ////            s_LcdOn = 1;
  205. ////        }        
  206. //////        LCD_DispOn();     
  207. //////        LCD_SetBackLight(BRIGHT_DEFAULT);   /* 打开背光 */            
  208. ////        return;
  209. ////    }
  210. //   
  211. //    s_RM_KEY_CFG.uMsgBuf[s_RM_KEY_CFG.uWriteAddr] = nKeyMsgCode;

  212. //    if (RM_KEY_MSG_FIFO_SIZE <= (++s_RM_KEY_CFG.uWriteAddr))
  213. //    {
  214. //        s_RM_KEY_CFG.uWriteAddr = 0;
  215. //    }
  216. //            
  217. ////    s_KeyTimeOutCount = GetSleepTimeMinute() * 60 * 100u;  /* 10ms单位 */
  218. //}


  219. /**
  220. * @brief   从按键FIFO缓冲区读取一个键值。
  221. *
  222. * @param [in] 无
  223. *
  224. * @return 按键代码
  225. * @author  
  226. * @since   trunk.00001
  227. * @bug
  228. */
  229. u16 RM_KEY_GetKeyMsgA(void)
  230. {
  231.     u16 u2MsgCode = 0x0000;
  232.    
  233.     // 判断是否有按键消息
  234.     if (s_tRmKeyRunData.uWriteAddr != s_tRmKeyRunData.uReadAddrA)
  235.     {
  236.         u2MsgCode = s_tRmKeyRunData.u2MsgBuf[s_tRmKeyRunData.uReadAddrA];
  237.         
  238.         // 读消息地址指针保护
  239.         if (RM_KEY_MSG_FIFO_SIZE <= (++s_tRmKeyRunData.uReadAddrA))
  240.         {
  241.             s_tRmKeyRunData.uReadAddrA = 0;
  242.         }
  243.     }

  244.     return u2MsgCode;
  245. }

  246. /**
  247. * @brief   从按键FIFO缓冲区读取一个键值。
  248. * @brief   两个函数调用不冲突?
  249. *
  250. * @param [in] 无
  251. *
  252. * @return 按键代码
  253. * @author  
  254. * @since   trunk.00001
  255. * @bug
  256. */
  257. u16 RM_KEY_GetKeyMsgB(void)
  258. {
  259.     u16 u2MsgCode = 0x0000;
  260.    
  261.     // 判断是否有按键消息
  262.     if (s_tRmKeyRunData.uWriteAddr != s_tRmKeyRunData.uReadAddrB)
  263.     {
  264.         // 有消息,则读取消息
  265.         u2MsgCode = s_tRmKeyRunData.u2MsgBuf[s_tRmKeyRunData.uReadAddrB];
  266.         
  267.         // 读消息地址指针保护
  268.         if (RM_KEY_MSG_FIFO_SIZE <= (++s_tRmKeyRunData.uReadAddrB))
  269.         {
  270.             s_tRmKeyRunData.uReadAddrB = 0;
  271.         }
  272.     }
  273.     return u2MsgCode;
  274. }


  275. /**
  276. * @brief   读取最新按键状态
  277. *
  278. * @param [in] 无
  279. *
  280. * @return 当前最新按键数据
  281. * @author  
  282. * @since   trunk.00001
  283. * @bug
  284. */
  285. u8 RM_KEY_GetKeyState(void)
  286. {
  287.     return s_RM_KEY_CFG.uRmKeyBusData;
  288. }


  289. /**
  290. * @brief   读取按键的状态
  291. *
  292. * @param [in] nKeyID       // 按键逻辑ID
  293. * @param [in] uCombCtr     // 组合、连击
  294. * @param [in] uLongCtr     // 长按
  295. * @param [in] uRepeatCtr   // 连发
  296. *
  297. * @return 无
  298. * @author  
  299. * @since   trunk.00001
  300. * @bug
  301. */
  302. void RM_KEY_SetKeyParam(u8 uFilterCtr, u8 uCombCtr, u8 uClickCtr,  u8 uLongCtr, u8 uRepeatCtr, u8 uIdleCtr)
  303. {
  304.     s_RM_KEY_CFG.uFilterCtr = uFilterCtr;           // 按键底层总线滤波,按键接近时,可滤波成同时按下,既多键
  305.    
  306.     s_RM_KEY_CFG.uCombCtr   = uCombCtr;             // 组合、连击等待时间阈值 0 表示不支持,最大2.5s
  307.     s_RM_KEY_CFG.uClickCtr  = uClickCtr & 0x07;     // 连击最大次数,必须支持组合/连击时才生效 最小值2 最大值7
  308.    
  309.     s_RM_KEY_CFG.uLongCtr   = uLongCtr;             // 长按计数器 等待阈值 0 表示不支持,最大2.5s
  310.     s_RM_KEY_CFG.uRepeatCtr = uRepeatCtr;           // 长按连续发送阈值, 0 表示不支持,最大2.5s,必须支持长按时才生效
  311.    
  312.     s_RM_KEY_CFG.uIdleCtr   = uIdleCtr;             // 按键弹开后,如何进入IDLE模式,0:必须没有按键才能进入,其它:延时对应时间,强制进IDLE
  313. }

  314. /**
  315. * @brief   设置按键默认初始化参数
  316. *
  317. * @param [in] 无
  318. *
  319. * @return 当前最新按键数据
  320. * @author  
  321. * @since   trunk.00001
  322. * @bug
  323. */

  324. void RM_KEY_SetKeyParamDefault(void)
  325. {

  326.     s_RM_KEY_CFG.uRmKeyBusData  = 0;
  327.     s_RM_KEY_CFG.uKeyBusDataCnt = 0;
  328.    
  329.     s_RM_KEY_CFG.uFilterCtr = RM_KEY_FILTER_TIME;   // 按键底层总线滤波,按键接近时,可滤波成同时按下,既多键
  330.       
  331.     s_RM_KEY_CFG.uCombCtr   = RM_KEY_COMB_TIME;     // 组合、连击等待时间阈值 0 表示不支持,最大2.5s
  332.     s_RM_KEY_CFG.uClickCtr  = RM_KEY_CLICK_CTR;     // 连击最大次数,必须支持组合/连击时才生效 最小值2 最大值7
  333.    
  334.     s_RM_KEY_CFG.uLongCtr   = RM_KEY_LONG_TIME;     // 长按计数器 等待阈值 0 表示不支持,最大2.5s
  335.     s_RM_KEY_CFG.uRepeatCtr = RM_KEY_REPEAT_TIME;   // 长按连续发送阈值, 0 表示不支持,最大2.5s,必须支持长按时才生效
  336.    
  337.     s_RM_KEY_CFG.uClickCtr  = RM_KEY_IDLE_TIME;     // 单键或组合按键,最多连击的次数


  338.     s_tRmKeyRunData.nGobleState   = 0;
  339.     s_tRmKeyRunData.uRmKeyData    = 0;
  340.     s_tRmKeyRunData.uRmKeyDataCnt = 0;
  341.    
  342.     s_tRmKeyRunData.uFIlterCount  = 0;
  343.    
  344.     s_tRmKeyRunData.uCombCnt   = 0;
  345.     s_tRmKeyRunData.uClickCnt  = 0;
  346.    
  347.     s_tRmKeyRunData.uLongCnt   = 0;
  348.     s_tRmKeyRunData.uRepeatCnt = 0;
  349.    
  350.     s_tRmKeyRunData.uIdleCnt   = 0;

  351.     // 按键消息缓存区清零
  352.     s_tRmKeyRunData.uWriteAddr = 0;
  353.     s_tRmKeyRunData.uReadAddrA = 0;
  354.     s_tRmKeyRunData.uReadAddrB = 0;

  355.    
  356. }



  357. /**
  358. * @brief   清空按键FIFO缓冲区
  359. *
  360. * @param [in] 无
  361. *
  362. * @return 无
  363. * @author  
  364. * @since   trunk.00001
  365. * @bug
  366. */
  367. void RM_KEY_ClearKeyMsg(void)
  368. {
  369.     s_tRmKeyRunData.uReadAddrA = s_tRmKeyRunData.uWriteAddr;
  370. }


  371. // 按键定义:单键/多键;单击/组合(连击);短按/长按;连发;
  372. // 注:对于应用层来说,组合也是单击,不需要标识出来。A和B组合生效,可以单键A和单键B组合,也可以是多键AB单击;

  373. /**
  374. * @brief   读取最新按键状态
  375. *
  376. * @param [in] 无
  377. *
  378. * @return 当前最新按键数据
  379. * @author  
  380. * @since   trunk.00001
  381. * @bug
  382. */
  383. static void RM_KEY_Detect(void)
  384. {
  385.     static u8  s_uRmKeyBusData_Last = 0;    // 记录上一次按键总线上的数据
  386.     static u16 s_u2CombLongFlag     = 0;    // 组合/连击 长按/连发 标志
  387.     u8 uRmKeyBusData_Temp           = 0;

  388.     switch (s_tRmKeyRunData.nGobleState)
  389.     {
  390.     case RM_KEY_STATE_IDLE:
  391.         {        
  392.             // 按键总线上有数据
  393.             if (s_RM_KEY_CFG.uRmKeyBusData)
  394.             {
  395.                 s_u2CombLongFlag            = 0;    // 下面马上要使用到 所以要先初始化
  396.                 s_tRmKeyRunData.uCombCnt    = 0;    // 组合/连击计数器
  397.                 s_tRmKeyRunData.uLongCnt    = 0;    // 长按计数器
  398.                 s_tRmKeyRunData.uRepeatCnt  = 0;    // 连发计数器
  399.                
  400.                 // 记录第一个有效按键的总线数据 单键或多键
  401.                 s_tRmKeyRunData.uRmKeyData    = s_RM_KEY_CFG.uRmKeyBusData;
  402.                 s_tRmKeyRunData.uRmKeyDataCnt = s_RM_KEY_CFG.uKeyBusDataCnt;
  403.                 s_tRmKeyRunData.uClickCnt     = 1;  // 第一次按下

  404.                 // 支持组合/连击
  405.                 if (s_RM_KEY_CFG.uCombCtr)
  406.                 {
  407.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_COMB;   // 进入等待组合/连击模式
  408.                 }
  409.                 else
  410.                 {
  411.                     // 输出单击按键数据
  412.                     RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  413.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_LONG;   // 进入等待长按
  414.                 }
  415.             }
  416.         }
  417.     break;

  418.     // 要么是组合要么是连击 组合:按键个数增加;连击:按键次数增加;
  419.     case RM_KEY_STATE_WAIT_COMB:
  420.         {
  421.             // 定时器超时 判断单击/连击 状态是否维持中,组合也是单击
  422.             if (s_RM_KEY_CFG.uCombCtr <= (++s_tRmKeyRunData.uCombCnt))
  423.             {
  424.                 // 所有的按键必须是按下状态 s_tRmKeyRunData.uRmKeyData记录所有按下过的按键
  425.                 if (s_RM_KEY_CFG.uRmKeyBusData == s_tRmKeyRunData.uRmKeyData)
  426.                 {
  427.                     // 单击/连击 按下,组合也是单击
  428.                     RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  429.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_LONG;                    
  430.                 }
  431.                 else
  432.                 {
  433.                     // 单击/连击 按下,组合也是单击
  434.                     RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  435.                     
  436.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_IDLE;
  437.                     s_tRmKeyRunData.uIdleCnt   = s_RM_KEY_CFG.uIdleCtr;
  438.                 }
  439.             }
  440.             else    // 除了连击 否则不允许有重复的按键按下
  441.             {               
  442.                 // 判断按键发生变化的位置 有可能没有按键按下
  443.                 uRmKeyBusData_Temp = s_RM_KEY_CFG.uRmKeyBusData ^ s_uRmKeyBusData_Last;
  444.                
  445.                 // 判断按键是按下 还是弹开
  446.                 uRmKeyBusData_Temp &= s_RM_KEY_CFG.uRmKeyBusData;

  447.                 // 判断是否有新的按键按下 新的按键跟之前按键的关系 包含 交集 独立?
  448.                
  449.                
  450.                 // 有交集发生 这个交集是中间状态 先判断 进行大的区分
  451.                 if (uRmKeyBusData_Temp & s_tRmKeyRunData.uRmKeyData)
  452.                 {
  453.                     // 判断是否是连击
  454.                     if (uRmKeyBusData_Temp == s_tRmKeyRunData.uRmKeyData)
  455.                     {                        
  456.                         // 按键相同 也没有发生过组合 就是连击
  457.                         if (s_tRmKeyRunData.uRmKeyDataCnt == Ones8(s_tRmKeyRunData.uRmKeyData))
  458.                         {
  459.                             s_tRmKeyRunData.uClickCnt++;
  460.                             s_u2CombLongFlag |= RM_KEY_MASK_DOBLE;    // 连击
  461.                             // 复位定时器
  462.                             s_tRmKeyRunData.uCombCnt = 0;

  463.                             // 更新记录 连击次数
  464.                             s_u2CombLongFlag &= 0xF8FF;
  465.                             s_u2CombLongFlag |= (s_tRmKeyRunData.uClickCnt << 8) & 0x0700;                           
  466.                            
  467.                             if (s_RM_KEY_CFG.uClickCtr <= s_tRmKeyRunData.uClickCnt)   // 判断连击门限值
  468.                             {
  469.                                 RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  470.                                 s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_LONG;
  471.                             }
  472.                         }
  473.                     }
  474.                     else    // 非法的重复按键发生
  475.                     {
  476.                         // 单击/连击 按下,组合也是单击
  477.                         RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  478.                         
  479.                         s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_IDLE;
  480.                         s_tRmKeyRunData.uIdleCnt   = s_RM_KEY_CFG.uIdleCtr;
  481.                     }                    
  482.                 }
  483.                 else    // 没有新的按键按下 或者有新的 但是不是重复的按键按下
  484.                 {
  485.                     if (uRmKeyBusData_Temp)     // 有按键按下
  486.                     {
  487.                         // 有新的按键按下 但是没有发生过连击 那就是组合
  488.                         if (1 == s_tRmKeyRunData.uClickCnt)
  489.                         {
  490.                             // 更新新加入的按键
  491.                             s_u2CombLongFlag |= RM_KEY_MASK_ADD;     // 标志是否发生过组合
  492.                             s_tRmKeyRunData.uRmKeyData |= s_RM_KEY_CFG.uRmKeyBusData;
  493.                         }
  494.                         else    // 发生过连击
  495.                         {
  496.                             // 单击/连击 按下,组合也是单击
  497.                             RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  498.                            
  499.                             s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_IDLE;
  500.                             s_tRmKeyRunData.uIdleCnt   = s_RM_KEY_CFG.uIdleCtr;
  501.                         }                        
  502.                     }
  503.                 }
  504.             }           
  505.         }
  506.     break;
  507.    
  508.     case RM_KEY_STATE_WAIT_LONG:
  509.         {
  510.             // 按键数据保持不变
  511.             if ((s_tRmKeyRunData.uRmKeyData == s_RM_KEY_CFG.uRmKeyBusData) && (0 < s_RM_KEY_CFG.uLongCtr))
  512.             {
  513.                 // 可以加上COMB等待的时间 否则时间过长!!!!!!!
  514.                 // 支持长按 长按消息只发一次
  515.                 if (s_RM_KEY_CFG.uLongCtr > s_tRmKeyRunData.uLongCnt)
  516.                 {
  517.                     if (s_RM_KEY_CFG.uLongCtr <= (++s_tRmKeyRunData.uLongCnt))
  518.                     {
  519.                         // 长发消息
  520.                         s_u2CombLongFlag |= RM_KEY_MASK_LONG;
  521.                         RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  522.                     }
  523.                     
  524.                 }
  525.                 // 支持连发
  526.                 else if (0 < s_RM_KEY_CFG.uRepeatCtr)
  527.                 {
  528.                     if (s_RM_KEY_CFG.uRepeatCtr <= (++s_tRmKeyRunData.uRepeatCnt))
  529.                     {
  530.                         s_tRmKeyRunData.uRepeatCnt = 0;
  531.                         // 连发消息
  532.                         s_u2CombLongFlag |= RM_KEY_MASK_LONG_P;
  533.                         // 长发连发
  534.                         RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag | RM_KEY_MASK_SHORT_D);
  535.                     }                    
  536.                 }
  537.             }
  538.             else
  539.             {
  540.                 s_tRmKeyRunData.nGobleState = RM_KEY_STATE_WAIT_IDLE;
  541.                 s_tRmKeyRunData.uIdleCnt    = s_RM_KEY_CFG.uIdleCtr;
  542.             }        
  543.         }
  544.     break;
  545.    
  546.     // 延时一段时间 然后进入IDLE
  547.     case RM_KEY_STATE_WAIT_IDLE:
  548.         {
  549.             // 延时后直接进入IDLE模式
  550.             if (s_RM_KEY_CFG.uIdleCtr)
  551.             {
  552.                 if (0 < s_tRmKeyRunData.uIdleCnt)
  553.                 {
  554.                     s_tRmKeyRunData.uIdleCnt--;
  555.                     
  556.                     // 没有按键也进入空闲模式
  557.                     if (0 == s_RM_KEY_CFG.uRmKeyBusData)
  558.                     {                    
  559.                         s_tRmKeyRunData.nGobleState = RM_KEY_STATE_IDLE;
  560.                         // 单击/连击 弹起,组合也是单击
  561.                         RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag);
  562.                     }
  563.                 }
  564.                 else
  565.                 {
  566.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_IDLE;
  567.                     // 单击/连击 弹起,组合也是单击
  568.                     RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag);
  569.                 }
  570.             }
  571.             else    // 必须所有按键都弹开之后才能进入IDLE模式
  572.             {
  573.                 if (0 == s_RM_KEY_CFG.uRmKeyBusData)
  574.                 {                    
  575.                     s_tRmKeyRunData.nGobleState = RM_KEY_STATE_IDLE;
  576.                     // 单击/连击 弹起,组合也是单击
  577.                     RM_KEY_PutKeyMsg((u16)s_tRmKeyRunData.uRmKeyData | s_u2CombLongFlag);
  578.                 }
  579.             }
  580.         }
  581.     break;

  582.     default:
  583.     break;
  584.    
  585.     }

  586.     // 记录当前按键状态值
  587.     s_uRmKeyBusData_Last = s_RM_KEY_CFG.uRmKeyBusData;
  588.    
  589. }


  590. /**
  591. * @brief   按键扫描函数 10ms调用一次
  592. *
  593. * @param [in] 无
  594. *
  595. * @return 无
  596. * @author  
  597. * @since   trunk.00001
  598. * @bug
  599. */
  600. void RM_KEY_Scan10ms(void)
  601. {  
  602.     // 更新一次各个按键状态
  603.     RM_KEY_Update();
  604.     RM_KEY_Detect();        

  605. //    if (s_KeyTimeOutCount > 0)
  606. //    {
  607. //        if (--s_KeyTimeOutCount == 0)
  608. //        {
  609. ////            LCD_SetBackLight(0);   /* 关闭背光 */               
  610. ////            LCD_DispOff();
  611. ////            s_LcdOn = 0;    /* 屏幕关闭 */
  612. //        }
  613. //    }
  614. }


  615. /**
  616. * @brief   按键初始化函数
  617. *
  618. * @param [in] 无
  619. *
  620. * @return 无
  621. * @author  
  622. * @since   trunk.00001
  623. * @bug
  624. */
  625. void RM_KEY_Init(void)
  626. {
  627.     GPIO_InitTypeDef GPIO_InitTypeDefStr;

  628.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);   // 使能A、C口时钟

  629.     // Power:PA0 按键初始化,下拉输入
  630.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_P_PIN;
  631.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  632.     GPIO_Init(RM_GPIO_KEY_P, &GPIO_InitTypeDefStr);

  633.     // A:PA4 按键初始化,下拉输入
  634.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_A_PIN;
  635.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  636.     GPIO_Init(RM_GPIO_KEY_A, &GPIO_InitTypeDefStr);

  637.     // B:PC0 按键初始化,下拉输入
  638.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_B_PIN;
  639.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  640.     GPIO_Init(RM_GPIO_KEY_B, &GPIO_InitTypeDefStr);

  641.     // C:PC15 按键初始化,下拉输入
  642.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_C_PIN;
  643.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  644.     GPIO_Init(RM_GPIO_KEY_C, &GPIO_InitTypeDefStr);

  645.     // D:PC5 按键初始化,下拉输入
  646.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_D_PIN;
  647.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  648.     GPIO_Init(RM_GPIO_KEY_D, &GPIO_InitTypeDefStr);
  649.    
  650.     // OK:PC14 按键初始化,下拉输入
  651.     GPIO_InitTypeDefStr.GPIO_Pin       = RM_GPIO_KEY_O_PIN;
  652.     GPIO_InitTypeDefStr.GPIO_Mode      = GPIO_Mode_IPD;
  653.     GPIO_Init(RM_GPIO_KEY_O, &GPIO_InitTypeDefStr);

  654.     // 初始化按键参数
  655.     RM_KEY_SetKeyParamDefault();
  656.         
  657. }

  658. <div class="blockcode"><blockquote>#ifndef _RM_KEY_H_
  659. #define _RM_KEY_H_

  660. /*******************************************************************************
  661. * Copyright (C), 1993-2012, Liming Comm. Co., Ltd.
  662. * @file    :RM_KEY.h
  663. * @brief   :Enter the brief description of this file
  664. * @author  :czm_hyt@163.com
  665. * @version :V1.0
  666. * @date    :2019-11-15
  667. * @time    :20:21:49
  668. *
  669. ******************************************************************************
  670. * 函数列表   
  671. *            
  672. * 1. Enter the name of the  first function
  673. * 2. Enter the name of the second function
  674. ******************************************************************************
  675. * 修改历史   
  676. *
  677. * 2019-11-15                 czm                  建立文件     
  678. *******************************************************************************/
  679. #include "RM_GPIO_DEFS.h"


  680. // 按键滤波检测时间 按下或者弹起都滤波 单位ms
  681. #define RM_KEY_FILTER_TIME          ((u8)3)             // 按键滤波时间,总线稳定后,持续的时间 可以短一些 影响多键的判断
  682. #define RM_KEY_COMB_TIME            ((u8)25)            // 组合按键或者连击等待时间 影响到组合
  683. #define RM_KEY_LONG_TIME            ((u8)80)            // 按键长按判断 1秒钟算长按 可以包含COMB也可以不包含
  684. #define RM_KEY_REPEAT_TIME          ((u8)10)            // 长按后连续触发按键的周期
  685. #define RM_KEY_IDLE_TIME            ((u8)25)            // 按键弹开后,如何进入IDLE模式,0:必须没有按键才能进入,其它:延时对应时间,强制进IDLE

  686. #define RM_KEY_CLICK_CTR            ((u8)7)             // 最多支持多少连击 最小值是2 最大值7,3个bit计数,支持组合时生效,否则不生效
  687.    
  688. #define RM_HARD_KEY_NUM             ((u8)6)             // RM 硬件按键个数

  689. #define RM_KEY_MSG_FIFO_SIZE            ((u8)10)            // 用来存储按键码的缓存FIFO大小


  690. /**
  691. * @enum RM_KEY_ID_E
  692. * @brief 按键的ID号
  693. */
  694. typedef enum _RM_KEY_ID_E
  695. {
  696.     RM_KEY_ID_A = 0x00,             ///< 按键 A
  697.     RM_KEY_ID_B,                    ///< 按键 B
  698.     RM_KEY_ID_C,                    ///< 按键 C
  699.     RM_KEY_ID_D,                    ///< 按键 D
  700.     RM_KEY_ID_O,                    ///< 按键 OK
  701.     RM_KEY_ID_P                     ///< 按键 Power
  702.    
  703. } RM_KEY_ID_E;


  704. /**
  705. * @enum RM_KEY_STATE_E
  706. * @brief 按键状态
  707. */
  708. typedef enum _RM_KEY_STATE_E
  709. {
  710.     RM_KEY_STATE_IDLE = 0x00,        ///< 常态 空闲
  711.     RM_KEY_STATE_WAIT_COMB,          ///< 过度状态 开始等待组合或者多击,弹开时也会用到这个状态,用来判断两次按键按下的间隔
  712.     RM_KEY_STATE_WAIT_LONG,          ///< 等待进入长按状态 或者不支持长按
  713.     RM_KEY_STATE_WAIT_IDLE           ///< 等待空闲状态,按键不松开,长期挺溜此状态
  714.    
  715. } RM_KEY_STATE_E;


  716. /**
  717. * @brief 按键GPIO定义的结构体 需要设置按键有效的电平是高还是低
  718. */
  719. typedef struct _RM_KEY_GPIO_DEF_T
  720. {
  721.     GPIO_TypeDef*   ptGpio;         // GPIO 端口
  722.     u16             u2Pin;          // GPIO 管脚
  723.     BOOL            bActiveLevel;   // 按键有效激活电平
  724.    
  725. } RM_KEY_GPIO_DEF_T;

  726. /**
  727. * @brief RM 逻辑按键参数配置
  728. */
  729. typedef struct _RM_KEY_LOGIC_CONFIG_T
  730. {
  731.     u8  uRmKeyBusData;          // 按键总线数据 10ms更新一次 带滤波
  732.     u8  uKeyBusDataCnt;         // 当前有效按键的个数
  733.    
  734.     // 滤波是指按键按下,去掉抖动之后,平稳的时间达到阈值才生效
  735.     u8  uFilterCtr;             // 按键底层总线滤波,按键接近时,可滤波成同时按下,既多键
  736.    
  737.     u8  uCombCtr;               // 组合、连击等待时间阈值 0 表示不支持,最大2.5s
  738.     u8  uClickCtr;              // 连击最大次数,必须支持组合/连击时才生效 最小值2 最大值7
  739.    
  740.     u8  uLongCtr;               // 长按计数器 等待阈值 0 表示不支持,最大2.5s
  741.     u8  uRepeatCtr  ;           // 长按连续发送阈值, 0 表示不支持,最大2.5s,必须支持长按时才生效
  742.    
  743.     u8  uIdleCtr;               // 按键弹开后,如何进入IDLE模式,0:必须没有按键才能进入,其它:延时对应时间,强制进IDLE
  744.    
  745. } RM_KEY_CONFIG_T;


  746. /**
  747. * @brief 逻辑按键计数器
  748. */
  749. typedef struct _RM_KEY_RUN_DATA_T
  750. {
  751.     RM_KEY_STATE_E nGobleState; // 按键处理状态机状态
  752.    
  753.     u8  uRmKeyData;             // 有效的按键数据
  754.     u8  uRmKeyDataCnt;          // 有效按键个数

  755.     u8  uFIlterCount;           // 逻辑滤波计数器 单位毫秒 等于物理按键的滤波时间
  756.    
  757.     u8  uCombCnt;               // 组合按键或者多击计数器
  758.     u8  uClickCnt;              // 按键单击次数
  759.    
  760.     u8  uLongCnt;               // 长按计数器
  761.     u8  uRepeatCnt;             // 长按连续发送计数器
  762.    
  763.     u8  uIdleCnt;               // 长按连续发送计数器

  764.     // 消息缓存区设置
  765.     // b15:长按/短按;b14:连发;b13:是否发生过组合;b10~b8:连击次数;
  766.     // b7:按下/弹开;b6:连击/单击; b5~b0:按键
  767.     u16 u2MsgBuf[RM_KEY_MSG_FIFO_SIZE];     // 按键消息缓存区
  768.     u8 uWriteAddr;                          // 缓冲区写指针
  769.     u8 uReadAddrA;                          // 缓冲区读指针1
  770.     u8 uReadAddrB;                          // 缓冲区读指针2,不同的函数同时读取缓存区
  771.    
  772. } RM_KEY_RUN_DATA_T;




  773. // 按键按下或者弹开 后面两个选项可以用来修饰按键的具体情况
  774. #define RM_KEY_MASK_SHORT_D         ((u16)0x0080)    // 按键按下
  775. #define RM_KEY_MASK_SHORT_U         ((u16)0x0000)    // 按键弹开

  776. // 按键类型
  777. #define RM_KEY_MASK_DOBLE           ((u16)0x0040)    // 连击

  778. #define RM_KEY_MASK_ADD             ((u16)0x2000)    // 发生了组合

  779. // 两个同时只能用一个 支持连发时 不会生产长按弹起 而是长按连发弹起!!!
  780. #define RM_KEY_MASK_LONG            ((u16)0x8000)    // 长按
  781. #define RM_KEY_MASK_LONG_P          ((u16)0xC000)    // 连发 一定长按

  782. #define RM_KEY_BIT_DEF_A            ((u16)0x0001)
  783. #define RM_KEY_BIT_DEF_B            ((u16)0x0002)
  784. #define RM_KEY_BIT_DEF_C            ((u16)0x0004)
  785. #define RM_KEY_BIT_DEF_D            ((u16)0x0008)
  786. #define RM_KEY_BIT_DEF_O            ((u16)0x0010)
  787. #define RM_KEY_BIT_DEF_P            ((u16)0x0020)
  788. #define RM_KEY_BIT_DEF_ALL          ((u16)0x003F)


  789. #define RM_KEY_MASK_DU              (RM_KEY_MASK_SHORT_D |RM_KEY_BIT_DEF_ALL)       // 不区分 单击/连击 不区分 长按/连发
  790. #define RM_KEY_MASK_DU_C            (RM_KEY_MASK_DU      |RM_KEY_MASK_DOBLE)        // 区分 单击/连击 不区分长按/连发

  791. #define RM_KEY_MASK_DU_L            (RM_KEY_MASK_DU      |RM_KEY_MASK_LONG)         // 不区分 单击/连击 区分 长按
  792. #define RM_KEY_MASK_DU_LP           (RM_KEY_MASK_DU      |RM_KEY_MASK_LONG_P)       // 不区分 单击/连击 区分 长按/连发

  793. // 支持连发的时候,连发结束后,有连发弹起,没有长按弹起
  794. #define RM_KEY_MASK_DU_CL           (RM_KEY_MASK_DU_C    |RM_KEY_MASK_LONG)         // 区分 单击/连击 区分 长按
  795. #define RM_KEY_MASK_DU_CLP          (RM_KEY_MASK_DU_C    |RM_KEY_MASK_LONG_P)       // 区分 单击/连击 区分 长按/连发





  796. // 按键 A
  797. #define RM_MSG_KEY_A_SD             (RM_KEY_BIT_DEF_A | RM_KEY_MASK_SHORT_D)        // 单键 短按按下
  798. #define RM_MSG_KEY_A_SU             (RM_KEY_BIT_DEF_A | RM_KEY_MASK_SHORT_U)        // 单键 短按弹起
  799. #define RM_MSG_KEY_A_C_SD           (RM_MSG_KEY_A_SD  | RM_KEY_MASK_DOBLE)          // 组合或者双击等 短按按下 最后一次按键是短按
  800. #define RM_MSG_KEY_A_C_SU           (RM_MSG_KEY_A_SU  | RM_KEY_MASK_DOBLE)          // 组合或者双击等 短按弹起 最后一次按键是短按

  801. // 按键 B
  802. #define RM_MSG_KEY_B_SD             (RM_KEY_BIT_DEF_B | RM_KEY_MASK_SHORT_D)         // 单键 短按按下
  803. #define RM_MSG_KEY_B_SU             (RM_KEY_BIT_DEF_B | RM_KEY_MASK_SHORT_U)         // 单键 短按弹起
  804. #define RM_MSG_KEY_B_C_SD           (RM_MSG_KEY_B_SD  | RM_KEY_MASK_DOBLE)           // 组合或者双击等 短按按下 最后一次按键是短按
  805. #define RM_MSG_KEY_B_C_SU           (RM_MSG_KEY_B_SU  | RM_KEY_MASK_DOBLE)           // 组合或者双击等 短按弹起 最后一次按键是短按

  806. // 按键 C
  807. #define RM_MSG_KEY_C_SD             (RM_KEY_BIT_DEF_C | RM_KEY_MASK_SHORT_D)         // 单键 短按按下
  808. #define RM_MSG_KEY_C_SU             (RM_KEY_BIT_DEF_C | RM_KEY_MASK_SHORT_U)         // 单键 短按弹起
  809. #define RM_MSG_KEY_C_C_SD           (RM_MSG_KEY_C_SD  | RM_KEY_MASK_DOBLE)           // 组合或者双击等 短按按下 最后一次按键是短按
  810. #define RM_MSG_KEY_C_C_SU           (RM_MSG_KEY_C_SU  | RM_KEY_MASK_DOBLE)           // 组合或者双击等 短按弹起 最后一次按键是短按

  811. // 按键 D
  812. #define RM_MSG_KEY_D_SD             (RM_KEY_BIT_DEF_D | RM_KEY_MASK_SHORT_D)       // 单键 短按按下
  813. #define RM_MSG_KEY_D_SU             (RM_KEY_BIT_DEF_D | RM_KEY_MASK_SHORT_U)       // 单键 短按弹起
  814. #define RM_MSG_KEY_D_C_SD           (RM_MSG_KEY_D_SD  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按按下 最后一次按键是短按
  815. #define RM_MSG_KEY_D_C_SU           (RM_MSG_KEY_D_SU  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按弹起 最后一次按键是短按

  816. // 按键 O
  817. #define RM_MSG_KEY_O_SD             (RM_KEY_BIT_DEF_O | RM_KEY_MASK_SHORT_D)       // 单键 短按按下
  818. #define RM_MSG_KEY_O_SU             (RM_KEY_BIT_DEF_O | RM_KEY_MASK_SHORT_U)       // 单键 短按弹起
  819. #define RM_MSG_KEY_O_C_SD           (RM_MSG_KEY_O_SD  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按按下 最后一次按键是短按
  820. #define RM_MSG_KEY_O_C_SU           (RM_MSG_KEY_O_SU  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按弹起 最后一次按键是短按

  821. // 按键 P
  822. #define RM_MSG_KEY_P_SD             (RM_KEY_BIT_DEF_P | RM_KEY_MASK_SHORT_D)       // 单键 短按按下
  823. #define RM_MSG_KEY_P_SU             (RM_KEY_BIT_DEF_P | RM_KEY_MASK_SHORT_U)       // 单键 短按弹起
  824. #define RM_MSG_KEY_P_C_SD           (RM_MSG_KEY_P_SD  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按按下 最后一次按键是短按
  825. #define RM_MSG_KEY_P_C_SU           (RM_MSG_KEY_P_SU  | RM_KEY_MASK_DOBLE)         // 组合或者双击等 短按弹起 最后一次按键是短按

  826. // 按键 AB
  827. #define RM_MSG_KEY_AB_SD            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_B_SD)
  828. #define RM_MSG_KEY_AB_SU            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_B_SU)
  829. #define RM_MSG_KEY_AB_C_SD          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_B_C_SD)
  830. #define RM_MSG_KEY_AB_C_SU          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_B_C_SU)

  831. // 按键 AC
  832. #define RM_MSG_KEY_AC_SD            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_C_SD)
  833. #define RM_MSG_KEY_AC_SU            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_C_SU)
  834. #define RM_MSG_KEY_AC_C_SD          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_C_C_SD)
  835. #define RM_MSG_KEY_AC_C_SU          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_C_C_SU)

  836. // 按键 AD
  837. #define RM_MSG_KEY_AD_SD            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_D_SD)
  838. #define RM_MSG_KEY_AD_SU            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_D_SU)
  839. #define RM_MSG_KEY_AD_C_SD          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_D_C_SD)
  840. #define RM_MSG_KEY_AD_C_SU          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_D_C_SU)

  841. // 按键 AO
  842. #define RM_MSG_KEY_AO_SD            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_O_SD)
  843. #define RM_MSG_KEY_AO_SU            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_O_SU)
  844. #define RM_MSG_KEY_AO_C_SD          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_O_C_SD)
  845. #define RM_MSG_KEY_AO_C_SU          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_O_C_SU)

  846. // 按键 AP
  847. #define RM_MSG_KEY_AP_SD            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_P_SD)
  848. #define RM_MSG_KEY_AP_SU            (RM_KEY_BIT_DEF_A | RM_MSG_KEY_P_SU)
  849. #define RM_MSG_KEY_AP_C_SD          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_P_C_SD)
  850. #define RM_MSG_KEY_AP_C_SU          (RM_KEY_BIT_DEF_A | RM_MSG_KEY_P_C_SU)

  851. // 按键 BC
  852. #define RM_MSG_KEY_BC_SD            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_C_SD)
  853. #define RM_MSG_KEY_BC_SU            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_C_SU)
  854. #define RM_MSG_KEY_BC_C_SD          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_C_C_SD)
  855. #define RM_MSG_KEY_BC_C_SU          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_C_C_SU)

  856. // 按键 BD
  857. #define RM_MSG_KEY_BD_SD            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_D_SD)
  858. #define RM_MSG_KEY_BD_SU            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_D_SU)
  859. #define RM_MSG_KEY_BD_C_SD          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_D_C_SD)
  860. #define RM_MSG_KEY_BD_C_SU          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_D_C_SU)

  861. // 按键 BO
  862. #define RM_MSG_KEY_BO_SD            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_O_SD)
  863. #define RM_MSG_KEY_BO_SU            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_O_SU)
  864. #define RM_MSG_KEY_BO_C_SD          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_O_C_SD)
  865. #define RM_MSG_KEY_BO_C_SU          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_O_C_SU)

  866. // 按键 BP
  867. #define RM_MSG_KEY_BP_SD            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_P_SD)
  868. #define RM_MSG_KEY_BP_SU            (RM_KEY_BIT_DEF_B | RM_MSG_KEY_P_SU)
  869. #define RM_MSG_KEY_BP_C_SD          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_P_C_SD)
  870. #define RM_MSG_KEY_BP_C_SU          (RM_KEY_BIT_DEF_B | RM_MSG_KEY_P_C_SU)


  871. // 按键 CD
  872. #define RM_MSG_KEY_CD_SD            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_D_SD)
  873. #define RM_MSG_KEY_CD_SU            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_D_SU)
  874. #define RM_MSG_KEY_CD_C_SD          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_D_C_SD)
  875. #define RM_MSG_KEY_CD_C_SU          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_D_C_SU)

  876. // 按键 CO
  877. #define RM_MSG_KEY_CO_SD            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_O_SD)
  878. #define RM_MSG_KEY_CO_SU            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_O_SU)
  879. #define RM_MSG_KEY_CO_C_SD          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_O_C_SD)
  880. #define RM_MSG_KEY_CO_C_SU          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_O_C_SU)

  881. // 按键 CP
  882. #define RM_MSG_KEY_CP_SD            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_P_SD)
  883. #define RM_MSG_KEY_CP_SU            (RM_KEY_BIT_DEF_C | RM_MSG_KEY_P_SU)
  884. #define RM_MSG_KEY_CP_C_SD          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_P_C_SD)
  885. #define RM_MSG_KEY_CP_C_SU          (RM_KEY_BIT_DEF_C | RM_MSG_KEY_P_C_SU)


  886. // 按键 DO
  887. #define RM_MSG_KEY_DO_SD            (RM_KEY_BIT_DEF_D | RM_MSG_KEY_O_SD)
  888. #define RM_MSG_KEY_DO_SU            (RM_KEY_BIT_DEF_D | RM_MSG_KEY_O_SU)
  889. #define RM_MSG_KEY_DO_C_SD          (RM_KEY_BIT_DEF_D | RM_MSG_KEY_O_C_SD)
  890. #define RM_MSG_KEY_DO_C_SU          (RM_KEY_BIT_DEF_D | RM_MSG_KEY_O_C_SU)

  891. // 按键 DP
  892. #define RM_MSG_KEY_DP_SD            (RM_KEY_BIT_DEF_D | RM_MSG_KEY_P_SD)
  893. #define RM_MSG_KEY_DP_SU            (RM_KEY_BIT_DEF_D | RM_MSG_KEY_P_SU)
  894. #define RM_MSG_KEY_DP_C_SD          (RM_KEY_BIT_DEF_D | RM_MSG_KEY_P_C_SD)
  895. #define RM_MSG_KEY_DP_C_SU          (RM_KEY_BIT_DEF_D | RM_MSG_KEY_P_C_SU)

  896. // 按键 OP
  897. #define RM_MSG_KEY_OP_SD            (RM_KEY_BIT_DEF_O | RM_MSG_KEY_P_SD)
  898. #define RM_MSG_KEY_OP_SU            (RM_KEY_BIT_DEF_O | RM_MSG_KEY_P_SU)
  899. #define RM_MSG_KEY_OP_C_SD          (RM_KEY_BIT_DEF_O | RM_MSG_KEY_P_C_SD)
  900. #define RM_MSG_KEY_OP_C_SU          (RM_KEY_BIT_DEF_O | RM_MSG_KEY_P_C_SU)



  901. extern u8   RM_KEY_GetKeyState(void);
  902. extern void RM_KEY_Init(void);
  903. extern void RM_KEY_Scan10ms(void);
  904. extern void RM_KEY_PutKeyMsg(u16 u2KeyMsgCode);
  905. extern u16  RM_KEY_GetKeyMsgA(void);
  906. extern void RM_KEY_SetKeyParam(u8 uFilterCtr, u8 uCombCtr, u8 uClickCtr,  u8 uLongCtr, u8 uRepeatCtr, u8 uIdleCtr);



  907. #endif  /* _RM_KEY_H_ */
复制代码





























回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2019-12-31 20:03:17 | 显示全部楼层
代码分享下更好,哈哈
回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-1-1 09:56:36 | 显示全部楼层
1:这里面最重要的就是将每一个独立的按键组合起来,一起处理,这样做的好处是,A和B键组合时,不会产生A先按下,B后按下,而是滤波之后,会认为AB同时按下。
2:很多朋友做组合按键的时候,各种定时器,单独判断每一个按键,这样非常麻烦,也容易出现某一个按键单独按下或者弹开的问题,用我说的思虑,整体滤波,就不会,而且还能实现组合按键的双击,3连击。。。。等等,出来起来非常简单。
回复

使用道具 举报

1

主题

103

回帖

106

积分

初级会员

积分
106
发表于 2020-1-7 14:17:47 | 显示全部楼层
等了6天了,还没有更新
回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-3-11 09:11:16 | 显示全部楼层
西点钟灵毓秀 发表于 2020-1-7 14:17
等了6天了,还没有更新

还是按照这个思路自己设计吧,我写的代码,有时候我自己都看不懂了,哈哈
回复

使用道具 举报

23

主题

211

回帖

280

积分

高级会员

积分
280
发表于 2020-3-11 11:21:43 | 显示全部楼层
lz的按键设计应该不是独立IO,而是2*3的矩阵吧?
回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-3-12 14:56:29 | 显示全部楼层
blackfire531 发表于 2020-3-11 11:21
lz的按键设计应该不是独立IO,而是2*3的矩阵吧?

不是的,是独立的几个按键,不是矩阵。我的思路就是为了解决组合按键的问题,以及组合按键的双击,例如按键A和B,组合,然后再次组合,相当于组合按键的双击。
回复

使用道具 举报

29

主题

231

回帖

318

积分

高级会员

积分
318
发表于 2020-3-13 08:45:53 | 显示全部楼层
明显吊人胃口贴~
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
发表于 2020-3-19 10:45:51 | 显示全部楼层
czm_hyt@163.com 发表于 2020-3-12 14:56
不是的,是独立的几个按键,不是矩阵。我的思路就是为了解决组合按键的问题,以及组合按键的双击,例如按 ...

楼主您好,我最近也是在解决这个双键长按10s,标志位一直无法进入的问题,但是一直无果,单按键长按10s一直是可行的,但是两个一起长按不行
回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-3-19 14:44:33 | 显示全部楼层
guoxiang 发表于 2020-3-13 08:45
明显吊人胃口贴~

不是的,大家做按键检测遇到什么问题,我们可以在这里详细的分析讨论,哈哈
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106692
QQ
发表于 2020-6-17 18:34:17 | 显示全部楼层
后台看到你编辑了下,是不是开源出来了。
回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-6-18 09:20:43 | 显示全部楼层
eric2013 发表于 2020-6-17 18:34
后台看到你编辑了下,是不是开源出来了。

是的,我是基于咱们硬汉的代码,优化了一下,分享给大家
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106692
QQ
发表于 2020-6-18 10:02:03 | 显示全部楼层
czm_hyt@163.com 发表于 2020-6-18 09:20
是的,我是基于咱们硬汉的代码,优化了一下,分享给大家

回复

使用道具 举报

3

主题

16

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2020-6-19 15:07:12 | 显示全部楼层

我自认为按键处理比较简单,高效,但就是这里面的判断技巧比较难理解,有点尴尬。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106692
QQ
发表于 2020-6-19 17:08:44 | 显示全部楼层
czm_hyt@163.com 发表于 2020-6-19 15:07
我自认为按键处理比较简单,高效,但就是这里面的判断技巧比较难理解,有点尴尬。



已经很给力了,好贴。
回复

使用道具 举报

609

主题

3049

回帖

4896

积分

至尊会员

积分
4896
发表于 2021-12-27 17:14:11 | 显示全部楼层
这个貌似要好好的研究一下才行哟,目前看着貌似是似懂非懂的感觉
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106692
QQ
发表于 2021-12-28 00:12:38 | 显示全部楼层
hpdell 发表于 2021-12-27 17:14
这个貌似要好好的研究一下才行哟,目前看着貌似是似懂非懂的感觉

楼主搞的略复杂。
回复

使用道具 举报

334

主题

2032

回帖

3039

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3039
发表于 2021-12-28 08:55:11 | 显示全部楼层
非常认真细致的分享,感谢!
回复

使用道具 举报

334

主题

2032

回帖

3039

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3039
发表于 2021-12-28 08:57:18 | 显示全部楼层
eric2013 发表于 2021-12-28 00:12
楼主搞的略复杂。

现在我都用电阻分压,ADC来检测按键,实现起来比较简单。
现在ADC通道都是足够多的,电阻精度也都够。
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
发表于 2021-12-28 21:49:22 | 显示全部楼层
caicaptain2 发表于 2021-12-28 08:57
现在我都用电阻分压,ADC来检测按键,实现起来比较简单。
现在ADC通道都是足够多的,电阻精度也都够。

这个思路新颖
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-30 06:28 , Processed in 0.395378 second(s), 34 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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