搜索
bottom↓
回复: 113

[并发长短键+shift键+环形buf]简洁且功能强大的按键程序

  [复制链接]

出0入0汤圆

发表于 2013-11-9 20:13:04 | 显示全部楼层 |阅读模式
本帖最后由 mojinpan 于 2013-11-9 20:36 编辑

提供一个简洁且功能强大的按键程序,供大家参考[并发长短键+shift键+环形buf]

主要参考:
1.[转]新型的按键扫描程序:http://www.amobbs.com/forum.php? ... =%E6%8C%89%E9%94%AE
2.[推荐]一种软件去除键抖动的方法:http://blog.csdn.net/joseph_happy/article/details/5133708

功能:
1.支持最大32个按键(视编译器所支持的数据类型而定)
2.支持不同的扫描方式(根据具体情况编写KeyIOread()和KeyInit())
3.支持按键消抖处理
2.支持按键环形缓冲区
5.支持短按键,短按键数量 = 最大按键数 - shift按键数
6.支持长按键,长按键数量 = 最大按键数,延时判定时间和扫描周期均可配置
7.支持shift键,shift键长按短按均可生效
用法:
1.每20ms~50ms调用KeyScan()扫描按键
2.调用KeyHit()判断是否有按键
3.调用KeyGet()获得按键值

关键代码:
  1. /*************************************************************************************************************
  2. 函数名称:KeyScan()
  3. 函数入口:无
  4. 函数出口:无
  5. 函数说明:
  6. 1.功能说明
  7.   a.按键消抖
  8.   b.捕捉长按键和短按键
  9. 2.算法说明
  10.   a.滤波算法
  11.     1).PreScanKey&NowScanKey: 取连续2次按键的高电平值
  12.     2).PreScanKey^NowScanKey: 取连续2次按键的差异部分
  13.     3).PreReadKey&(PreScanKey^NowScanKey): 取前一次按键值的差异部分
  14.     4).上面的合起来即:当前按键值等于连续2次有效按键值或前次有效按键值
  15.   b.按键获取算法
  16.     1).NowKey ^ PreKey                                : 边缘触发
  17.     2).NowKey & (NowKey ^ PreKey)或(~PreKey) & NowKey : 上升沿触发
  18.     3).PreKey & (NowKey ^ PreKey)或PreKey & (~NowKey) : 下降沿触发
  19. 3.调用说明
  20.   a.对下调用的KeyIOread()中,有效按键必须为高电平,且每个bit表示一个按键值
  21.   b.应用调用该函数的间隔应该在20ms~50ms,在调用间隔内的毛刺均可滤除。
  22. *************************************************************************************************************/
  23. void KeyScan(void)
  24. {
  25.   KEY_TYPE NowScanKey   = 0;                                  //当前按键值扫描值
  26.   KEY_TYPE NowReadKey   = 0;                                  //当前按键值
  27. //INT32U KeyPressDown = 0;                                  //按键按下
  28.   KEY_TYPE KeyRelease   = 0;                                  //按键释放
  29.   KEY_TYPE KeyShiftMask = KEY_SHIFT;                          //shift按键码
  30.   NowScanKey  = KeyIOread();
  31.   NowReadKey  = (PreScanKey&NowScanKey)|
  32.                  PreReadKey&(PreScanKey^NowScanKey);  

  33. //KeyPressDown  = NowReadKey & (NowReadKey ^ PreReadKey);
  34.   KeyRelease    = PreReadKey & (NowReadKey ^ PreReadKey);
  35.   KeyShift      = KeyShift ^ (KeyRelease & KeyShiftMask);
  36. #if LONG_KEY_EN > 0                                         
  37.   if(NowReadKey == PreReadKey && NowReadKey){               //长按键有效判断
  38.     KeyPressTmr--;
  39.     if(!KeyPressTmr){                                       //长按判断周期到,保存相应长按键值
  40.       KeyBufIn(NowReadKey | KeyShift);
  41.       KeyPressTmr = KEY_PRESS_TMR;                          //重置按键判断周期,准备获取下1个长按键
  42.     }
  43.   }
  44.   else{
  45.     KeyPressTmr = KEY_PRESS_DLY;                            //按键变化,重置按键判断周期
  46.   }
  47. #endif


  48.   if(KeyRelease & (~KeyShiftMask)){                         //短按键判断
  49.     KeyBufIn(KeyRelease | KeyShift);
  50.   }
  51.   
  52.   PreScanKey     = NowScanKey;
  53.   PreReadKey     = NowReadKey;
  54. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-11-9 21:50:51 | 显示全部楼层
很牛逼的赶脚有莫有

出0入0汤圆

发表于 2013-11-9 22:49:45 | 显示全部楼层
不觉明历!  

出0入0汤圆

发表于 2013-11-9 22:55:49 | 显示全部楼层
先标记下,有空来看看

出0入0汤圆

发表于 2013-11-9 23:20:16 | 显示全部楼层
现标记下  学习

出0入0汤圆

发表于 2013-11-10 15:35:26 | 显示全部楼层
标记!!!

出0入0汤圆

发表于 2013-11-10 19:41:48 | 显示全部楼层
仔细学习下

出0入0汤圆

发表于 2013-11-10 20:50:05 来自手机 | 显示全部楼层
先标记下,有空来看看

出0入0汤圆

发表于 2013-11-10 20:56:58 | 显示全部楼层
好。MARK.
有时间看看。
谢。

出0入0汤圆

发表于 2013-11-10 21:05:40 | 显示全部楼层
能不能用C51写个啊?

出0入0汤圆

发表于 2013-11-10 22:16:22 | 显示全部楼层
标记下,再慢慢读

出0入0汤圆

发表于 2013-11-11 17:04:19 | 显示全部楼层
标记!!!有时间看。

出0入0汤圆

发表于 2013-11-12 15:08:27 | 显示全部楼层
不错。相当的OK

出0入0汤圆

 楼主| 发表于 2013-11-14 22:06:35 | 显示全部楼层
果然没详细的说明是很容易沉掉的

出0入0汤圆

发表于 2013-11-14 22:17:59 | 显示全部楼层
帮顶一下!

出0入0汤圆

 楼主| 发表于 2013-11-17 12:35:49 | 显示全部楼层
自己顶一下,看是否有有缘人

出0入0汤圆

发表于 2013-11-17 12:41:04 | 显示全部楼层
先标记下,等用到的时候再来看看,看能不能移入单片机中。

出0入0汤圆

发表于 2013-11-17 14:54:42 来自手机 | 显示全部楼层
有时间可以试试

出0入0汤圆

发表于 2013-11-21 08:42:04 | 显示全部楼层
如何判断
长键按下
短键按下
长键释放
短键释放
组合键

有呼叫范例吗
另外在FIFO是否须加上临界区?

出0入0汤圆

发表于 2013-11-21 08:48:12 | 显示全部楼层
看看 以后不定能用上

出0入0汤圆

发表于 2013-11-21 08:53:03 | 显示全部楼层
标记一下,以后有用

出0入0汤圆

发表于 2013-11-21 08:54:25 来自手机 | 显示全部楼层
看看, 不觉明历!

出0入0汤圆

发表于 2013-11-21 08:55:04 | 显示全部楼层
路过,支持一把

出0入0汤圆

发表于 2013-11-21 08:56:53 | 显示全部楼层
感覺會是很有用的東西

出0入0汤圆

发表于 2013-11-21 09:16:12 | 显示全部楼层
楼主这个头文件,能不能传上来,#include "bsp.h",还有,能否给个例子

出0入0汤圆

发表于 2013-11-21 09:32:33 | 显示全部楼层
刚看了下楼主的程序,确实很简练,但,有一个问题,不知道楼主的程序如何知道,从缓存区里读的按键到到底 是 长按,短按

出0入0汤圆

发表于 2013-11-21 09:36:44 | 显示全部楼层
mojinpan 发表于 2013-11-14 22:06
果然没详细的说明是很容易沉掉的

其实你已经给出了两个链接,原理方面基本OK,不过你的代码如何使用,如何配置,再配上一个实例说明更好.

不过我更关心的是: 你是否真正应用了? 稳定吗? 因为打算尝试一下放产品上去,可又没时间来测试,故且问问楼主.

出0入0汤圆

发表于 2013-11-21 21:01:12 | 显示全部楼层
好使不好使啊

出0入0汤圆

发表于 2013-11-21 21:59:11 | 显示全部楼层
标记一下。

出0入0汤圆

发表于 2013-11-21 22:41:44 | 显示全部楼层
Mark 收藏备用,谢谢

出0入0汤圆

发表于 2013-11-21 23:18:59 | 显示全部楼层

标记!!!

出0入0汤圆

 楼主| 发表于 2013-11-22 18:09:46 | 显示全部楼层
blueice1108 发表于 2013-11-21 08:42
如何判断
长键按下
短键按下

再详细点说明吧:
1、所有按键都是判释放有效,即判下降沿触发。(函数中我也给出了按下的判据注释,你可以自己修改程序用按键按下作为有效判据,但是这样不好区分长按和短按)
2、长按键是等待X秒有效后,以Y秒为周期发送键值给环形fifo,即长按会在一段时间后fifo中会有多个按键值,即长按键和短按键的键值无法区分,长按键=N个短按键码,N的数量和时间有关。
3、组合码,发送的键值=组合码+按键值,使用时,点击一次你设定的shift键后,后面按下的按键就都带对应的组合码了,在按一次就取消组合键了,被设置为组合键的按键将失去常规按键的功能
4、另外补充一点组合键、长按键、短按键都是用位操作写的,所有都是并发功能都是并发独立的,所有按键的处理也都是并发独立的。你可以同时按好几个按键测试,都会并发响应……
5、fifo没有加临界代码保护,因为刚开始学os,还没弄懂哪些是要保护的代码,也不清楚是关中断,还是锁调度器,还是用互斥量好,所以还没加这个。


出0入0汤圆

 楼主| 发表于 2013-11-22 18:16:13 | 显示全部楼层
本帖最后由 mojinpan 于 2013-11-22 18:21 编辑
xyz2008 发表于 2013-11-21 09:32
刚看了下楼主的程序,确实很简练,但,有一个问题,不知道楼主的程序如何知道,从缓存区里读的按键到到底  ...


1、长按键=N个短按键,N的数值与时间有关
2、长按键和短按键从键值上无法确认
3、bsp.h是提供底层驱动的支持的,包括具体IO操作和数据类型的宏定义,具体IO操作我就不给了,给出bsp中数据类型的宏定义吧:
  1. /*************************************************************************************************************
  2.                                                                                                                                                                                                   Data Type                        数据类型
  3. *************************************************************************************************************/
  4. #define BOOLEAN            char                                      //布尔量                                 
  5. #define INT8U     unsigned char                                      //无符号 8bit整型量                       
  6. #define INT8S              char                                      //有符号 8bit整型量                       
  7. #define INT16U    unsigned short                                     //无符号16bit整型量                       
  8. #define INT16S                               short                                     //有符号31bit整型量                       
  9. #define INT32U    unsigned long                               //无符号32bit整型量                       
  10. #define INT32S                               long                               //有符号32bit整型量                       
  11. #define INT64U    unsigned long long                    //无符号64bit整型量(有的编译器可能不支持)
  12. #define INT64S                                     long long                    //有符号64bit整型量(有的编译器可能不支持)
  13. #define FP32      float                                              //单精度浮点数                           
  14. #define FP64      double                                             //双精度浮点数
复制代码
在提供一个简单的调用范例:
  1. void MainTask2(void *pdata)
  2. {         

  3.         while(1)
  4.          {
  5.                  KeyScan();       
  6.                 OSTimeDlyHMSM(0,0,0,50);
  7.                                  
  8.          }

  9. }

  10. void MainTask1(void *pdata) //Main Task
  11. {         
  12.         INT32U key;
  13.        
  14.        
  15.                  
  16.         while(1)
  17.          {
  18.                 if(KeyHit()==TRUE){
  19.                         key = KeyGet();
  20.                         APP_TRACE_INFO("\nkey=0x%04x\r\n",key);
  21.                         switch (key)
  22.                         {
  23.                                 case KEY_UP:SDcarTest();
  24.                                                         break;
  25.                                 case KEY_DOWN:FlashTest();
  26.                                                         break;
  27.                                 case KEY_LIFT:LcdTest();
  28.                                                         break;
  29.                                 case KEY_RIGHT:
  30.                                                         break;
  31.                                 case KEY_ENTER:
  32.                                                         break;
  33.                                 case KEY_ESC:
  34.                                                         break;
  35.                                 default:
  36.                                                         break;                                       
  37.                         }
  38.                 }               
  39.          }

  40. }
复制代码
上面是假设os中跑着两个任务,其中MainTask2,负责每50ms扫描按键,MainTask1,检测有按键触发时,执行对应的操作。

出0入0汤圆

 楼主| 发表于 2013-11-22 18:18:30 | 显示全部楼层
kinsno 发表于 2013-11-21 09:36
其实你已经给出了两个链接,原理方面基本OK,不过你的代码如何使用,如何配置,再配上一个实例说明更好.

不 ...

实例已经给出,配置的话看key.h吧,很简单的。代码写好后一直在用,但时间不长,不确定是否稳定,版本上也没到正式的V1.0版本

出0入0汤圆

 楼主| 发表于 2013-11-22 22:06:05 | 显示全部楼层
顶顶再睡觉,终于有人看代码了,而不只是make

出0入0汤圆

发表于 2013-11-22 22:48:45 | 显示全部楼层
这几年做的每个项目都是重新些按键驱动,想找个通用型切高效的。先看看

出0入8汤圆

发表于 2013-11-22 23:17:52 | 显示全部楼层
好东西,顶起!!!

出0入0汤圆

发表于 2013-11-22 23:35:43 | 显示全部楼层
四轴飞行器 发表于 2013-11-9 21:50
很牛逼的赶脚有莫有

出0入0汤圆

发表于 2013-11-23 10:39:48 | 显示全部楼层
mojinpan 发表于 2013-11-22 22:06
顶顶再睡觉,终于有人看代码了,而不只是make

在下太笨,还是没想通,怎么判断是不是长按键,按下,楼主给的例子,似乎只是一个短按的例子

出0入0汤圆

 楼主| 发表于 2013-11-23 12:21:29 | 显示全部楼层
xyz2008 发表于 2013-11-23 10:39
在下太笨,还是没想通,怎么判断是不是长按键,按下,楼主给的例子,似乎只是一个短按的例子 ...

呵呵,在详细说一下长按和短按的思路:
1,从键值上是无法区分长按和短按的,所以给出的例子中是可以同时测试到长按,短按的(当然shift键也能测试到,因为shift键的键值不一样)
2, 长短键是在KeyScan()中已经判定了,短按键就向buf发一个按键值,长按键就定期向buf中发送按键值(按键值和短按键的一样),所以我前面强调了长按键=N个短按键.
3,再说一下长按键在KeyScan()中的判定思路:
   a,KeyScan()先判定io的状态一直处于不变,且都是有效按下(IO状态有高电平的),这时开始计时按键的时间
   b,如果这个按键按下足够长的时间后,将其判定为长按键,然后继续累计时间,每达到发送间隔,则发送一个键值到buf中.
   c,按键释放后,将所有长按键相关的变量恢复成初始状态,等待下一次按键的出现.
4,在说一下长按键的一些其他问题:
   a,短按键优先级高于长按键,即如果你长按a,然后同时短按b,则不断相应b,a被挂起,直到没有其他按键的变化.
   b,支持多个按键的同时长按,因为都是并发处理的,所以多个按键和一个按键是没啥区别,唯一的不同是,触发时间只一个,所以多个按键的变化导致触发时间不断被重置,所以多个长按键同时按,以最后一个的按下开始计时,只有一个触发计时的设计也导致了长按键的优先级比短按键的低
   c,程序中没有区分长按和短按,所以但长按释放时会多触发了一个短按,由于实际长按的时候,产生多少个长按的键值码并不是太重要,所以这里我没有去处理这个'bug'
   d,由于长按键只是循环发送键值码到buf中,所以这个驱动不支持长按出第二功能的方式,所以我另外提供了shift键,来提供转意按键的输出.

出0入0汤圆

 楼主| 发表于 2013-11-24 19:40:34 | 显示全部楼层
本帖最后由 mojinpan 于 2013-11-24 19:42 编辑
xyz2008 发表于 2013-11-23 10:39
在下太笨,还是没想通,怎么判断是不是长按键,按下,楼主给的例子,似乎只是一个短按的例子 ...


好像长按键的争议比较大,我修改了一下代码,将长按键分成:长按连续键和长按shift键两种方式,修改后代码的功能:
1.每20ms~50ms调用KeyScan()扫描按键,调用KeyHit()判断是否有按键,调用KeyGet()获得按键值
2.支持最大32个按键(数量可配置)
3.支持不同的扫描方式(根据具体情况编写KeyIOread()和KeyInit())
4.支持按键消抖处理(可滤掉小于2个扫描周期的毛刺)
5.支持按键环形缓冲区(长度可配置)
6.支持短按键     :短按直接输出键值
7.支持短按shift键:点击后除了输出一次短按键外,还将后续所有其他按键的键值改为,shift键+按键值(包括长短按键)
8.支持长按连续键 :长按一定时间后连续输出按键键值
9.支持长按shift键:长按一定时间后反码输出键值(仅一次)
10.4种不同按键方式可相互叠加使用,所有按键功能都能并发输出

关键代码如下:

  1. /*************************************************************************************************************
  2. 函数名称:KeyScan()
  3. 函数入口:无
  4. 函数出口:无
  5. 函数说明:
  6. 1.功能说明
  7.   a.按键消抖
  8.   b.捕捉长按键和短按键
  9.   c.根据设置将按键分成短按键/长按连续建/短按shift键/长按shift键4种方式写入buf
  10. 2.算法说明
  11.   a.按键获取算法
  12.     1).NowKey & PreKey                                : 电平触发
  13.     2).NowKey ^ PreKey                                : 边缘触发
  14.     3).NowKey & (NowKey ^ PreKey)或(~PreKey) & NowKey : 上升沿触发
  15.     4).PreKey & (NowKey ^ PreKey)或PreKey & (~NowKey) : 下降沿触发
  16.   b.滤波算法
  17.     1).PreScanKey & NowScanKey                        : 电平触发
  18.     2).PreReadKey & (PreScanKey ^ NowScanKey)         : 采样保持
  19.     3).NowReadKey = 1) | 2)                           : 带采样保持的电平触发
  20. 3.调用说明
  21.   a.对下调用的KeyIOread()中,有效按键必须为高电平,且每个bit表示一个按键值
  22.   b.应用调用该函数的间隔应该在20ms~50ms,在调用间隔内的毛刺均可滤除。
  23. *************************************************************************************************************/
  24. void KeyScan(void)
  25. {
  26.   KEY_TYPE NowScanKey   = 0;                                //当前按键值扫描值
  27.   KEY_TYPE NowReadKey   = 0;                                //当前按键值
  28. //KEY_TYPE KeyPressDown = 0;                                //按键按下                                    
  29.   KEY_TYPE KeyRelease   = 0;                                //按键释放                                                           
  30.   NowScanKey  = KeyIOread();
  31.   NowReadKey  = (PreScanKey&NowScanKey)|                    //电平触发
  32.                  PreReadKey&(PreScanKey^NowScanKey);        //采样保持(即消抖)

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

  35. #if LONG_KEY_EN > 0                                         
  36.   if(NowReadKey == PreReadKey && NowReadKey) {              //用电平触发做长按键的有效判据
  37.     KeyPressTmr--;
  38.     if(!KeyPressTmr){                                       //长按判断周期到,保存相应长按键值
  39.       if(NowReadKey & ~(KEY_LONG_SHIFT)){                   //长按键模式一
  40.         KeyBufIn(NowReadKey | KeyShift);                    //长按键重复输出
  41.       }
  42.       else if(NowReadKey & (KEY_LONG_SHIFT) & ~KeyMask ){   //长按键模式二        
  43.         KeyBufIn(~(NowReadKey | KeyShift));                 //长按键反码输出作为第二功能键      
  44.       }
  45.       KeyPressTmr = KEY_PRESS_TMR;                          //重置连按周期,准备获取下1个长按键
  46.       KeyMask = NowReadKey;
  47.     }
  48.   }
  49.   else{
  50.     KeyPressTmr = KEY_PRESS_DLY;                            //按键变化,重置按键判断周期
  51.   }
  52. #endif

  53.   if(KeyRelease){                                           //短按键判断
  54.       if(KeyRelease &(~KeyMask)){
  55.         KeyShift ^= (KeyRelease & (KEY_SHORT_SHIFT));       //shift按键码(边缘触发)
  56.         KeyBufIn(KeyRelease | KeyShift);
  57.       }else{
  58.         KeyMask = 0;
  59.       }
  60.   }
  61.   
  62.   PreScanKey = NowScanKey;
  63.   PreReadKey = NowReadKey;
  64. }
复制代码


相应的工程文件:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-11-25 10:05:57 | 显示全部楼层
楼主的程序,越来越强大了,本人,用在了一个产品上,感觉挺好使的

出0入0汤圆

 楼主| 发表于 2013-11-25 11:36:46 | 显示全部楼层
xyz2008 发表于 2013-11-25 10:05
楼主的程序,越来越强大了,本人,用在了一个产品上,感觉挺好使的

哈哈,希望找到有缘人,不过看代码的人确实不多,现在的社会信息量太大了,大家主要的问题不是怎么获得资源,而且怎么好好的吸收资源

出0入0汤圆

发表于 2013-11-25 15:33:02 | 显示全部楼层
if(NowReadKey == PreReadKey && NowReadKey){               //长按键有效判断

既是    (1或者0) && NowReadKey      楼主确认这个没人buy?

另如果我代码里遇到短按就做动作,那么长按就是让短按功能多次重复出现,这功能在音量加减中就不错,但我的长按关机功能就不好实现了

出0入0汤圆

 楼主| 发表于 2013-11-25 20:52:13 | 显示全部楼层
heicnhei3 发表于 2013-11-25 15:33
if(NowReadKey == PreReadKey && NowReadKey){               //长按键有效判断

既是    (1或者0) && Now ...

你看我后面发的程序,我提供了长按连续键和长按shift键两种不同的输出方式,你的关机键用长按shift键的方式就ok了,我会将短按键码反码输出一次作为长按的响应

出0入0汤圆

 楼主| 发表于 2013-11-30 19:14:47 | 显示全部楼层
自己顶一下

出0入0汤圆

发表于 2013-11-30 20:07:43 | 显示全部楼层
帮顶 之后还没仔细看

出0入0汤圆

发表于 2013-12-4 11:01:45 | 显示全部楼层
MARK~~~~,有时间好好看看

出0入0汤圆

发表于 2013-12-14 00:49:52 | 显示全部楼层
好,就一个字

出0入0汤圆

发表于 2013-12-18 21:53:46 来自手机 | 显示全部楼层
顶就一个字。

出0入0汤圆

发表于 2013-12-18 22:38:36 | 显示全部楼层
流弊,支持一个啊

出0入0汤圆

发表于 2013-12-19 08:42:48 | 显示全部楼层
好牛X,一定要下来研究研究

出0入0汤圆

发表于 2013-12-19 20:46:03 来自手机 | 显示全部楼层
顶顶收了!

出0入0汤圆

发表于 2013-12-23 07:18:21 | 显示全部楼层
收藏下以后看

出0入0汤圆

发表于 2013-12-23 07:23:34 | 显示全部楼层
收藏下来,有空再仔细研究!

出100入0汤圆

发表于 2013-12-23 07:53:56 来自手机 | 显示全部楼层
不明觉厉

出0入0汤圆

发表于 2014-1-9 09:31:37 | 显示全部楼层
       MARK   

出0入0汤圆

发表于 2014-1-15 10:39:45 | 显示全部楼层
楼主, 组合键的应用在这里是相当于Shift 键吗?

我用了你的第一个版本的例子,组合键不大灵,需要二个键同时按下,同时松开.

出0入0汤圆

发表于 2014-1-18 10:34:25 | 显示全部楼层
想问
(1)
NowReadKey  = (PreScanKey&NowScanKey)|                    //电平触发
                 PreReadKey&(PreScanKey^NowScanKey);        //采样保持(即消抖)
这不是电平变化+ 下降沿变化?
电平变化不是已经包含了下降沿及上降沿吗?
这不是有些多余吗?
不明白精粹所在,可以解释一下吗?

=======================================
(2)
KeyRelease    = PreReadKey & (NowReadKey ^ PreReadKey);   //下降沿触发  
也就是释放按键,是吗?

if(KeyRelease){                                           //短按键判断
      if(KeyRelease &(~KeyMask)){
        KeyShift ^= (KeyRelease & (KEY_SHORT_SHIFT));       //shift按键码(边缘触发)
        KeyBufIn(KeyRelease | KeyShift);
      }else{
        KeyMask = 0;
      }
  }

也就是释放是才发送信号,那不是释放按键才做短按键所对应的事?????

出0入0汤圆

 楼主| 发表于 2014-1-18 15:41:49 | 显示全部楼层
DVD1478 发表于 2014-1-18 10:34
想问
(1)
NowReadKey  = (PreScanKey&NowScanKey)|                    //电平触发

1、这里不是下降沿变化,注意看这个的区别:
NowReadKey  = (PreScanKey&NowScanKey)|                    //电平触发
                 PreReadKey&(PreScanKey^NowScanKey);        //采样保持(即消抖)

PreKey & (NowKey ^ PreKey)或PreKey & (~NowKey) : 下降沿触发
====================================================
2、也就是释放是才发送信号,那不是释放按键才做短按键所对应的事?????
是的,程序里短按键是以释放为准,因为如果短按键以按下为准,就没法区分长按短按了。

出0入0汤圆

发表于 2014-1-19 10:29:02 | 显示全部楼层
谢谢!学习!!!!!!!!!!

出0入0汤圆

发表于 2014-1-19 16:48:36 | 显示全部楼层
学习一下

出0入0汤圆

 楼主| 发表于 2014-1-21 12:34:27 | 显示全部楼层
ldxepthnn 发表于 2014-1-15 10:39
楼主, 组合键的应用在这里是相当于Shift 键吗?

我用了你的第一个版本的例子,组合键不大灵,需要二个键同时 ...

你可以用第二版试试,上面有下载.不过我的设想是,你先按下shift键,然后在操作其他按键,这样输出就变了,不是同时按的..............

出0入0汤圆

发表于 2014-1-22 08:48:32 | 显示全部楼层
mojinpan 发表于 2014-1-21 12:34
你可以用第二版试试,上面有下载.不过我的设想是,你先按下shift键,然后在操作其他按键,这样输出就变了,不 ...

楼主, 可能我没有说明白,

我是将 SHIFT 键 关闭的, KEY_SHIFT=0, 然后将 PC0,PC1,PC2 接到三个按键,内部上拉,

我使用新的版本了.

现在单个键按下的时候很灵敏,长按也很好.

就是二个键同时按下时(组合键, 如判断 PC0,和 PC2 同时按下),要求很严格,要几乎同时按下去才可以,还有松开时要几乎同时松开,这点对于用户体验来说,是很差的. 按中组合键的几率很小.

将释放功能改为上升沿触发, 几率可以大很多,但是常有漏键情况.

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

由于项目急,没有时间去研究,只能改了老的键扫方法.不过我相信这个键扫程序可以更加完美,等有时间了.再和楼主一起多研究一下.

出0入0汤圆

 楼主| 发表于 2014-1-23 12:22:52 | 显示全部楼层
ldxepthnn 发表于 2014-1-22 08:48
楼主, 可能我没有说明白,

我是将 SHIFT 键 关闭的, KEY_SHIFT=0, 然后将 PC0,PC1,PC2 接到三个按键,内 ...

短按键模式的确认时间比较短,所有对双击的准确性要求是很高的,其实你这个需求可以使用长按键模式来实现,将触发时间设置设置在0.8s左右,这样当双击来使用.至于你要哪种长按键模式就看你的应用需求了.

出0入0汤圆

发表于 2014-1-23 13:32:06 | 显示全部楼层
mojinpan 发表于 2014-1-23 12:22
短按键模式的确认时间比较短,所有对双击的准确性要求是很高的,其实你这个需求可以使用长按键模式来实现, ...

楼主, 这个方面,我也偿试过了.但是用户在做键释放的时候,一样要求很严格.一个先释放,一个稍慢一点.同样的很难进入相应的模式.

出0入0汤圆

发表于 2014-1-23 14:48:59 | 显示全部楼层
等待更强大的版本

出0入0汤圆

发表于 2014-1-23 15:47:35 | 显示全部楼层
不错,空了试试

出0入0汤圆

发表于 2014-1-24 08:46:05 | 显示全部楼层
好,mark。

出0入0汤圆

 楼主| 发表于 2014-1-24 12:25:58 | 显示全部楼层
ldxepthnn 发表于 2014-1-23 13:32
楼主, 这个方面,我也偿试过了.但是用户在做键释放的时候,一样要求很严格.一个先释放,一个稍慢一点.同样的 ...

那我晚点 有空了再尝试改改滤波算法,看是否能解决这个问题

出0入0汤圆

发表于 2014-1-24 16:49:43 | 显示全部楼层
mojinpan 发表于 2014-1-24 12:25
那我晚点 有空了再尝试改改滤波算法,看是否能解决这个问题

谢谢楼主,新年快乐,过个轻松年先.

出0入0汤圆

 楼主| 发表于 2014-1-25 09:50:50 | 显示全部楼层
ldxepthnn 发表于 2014-1-24 16:49
谢谢楼主,新年快乐,过个轻松年先.

晚上抽空研究了一下,双击不好实现啊,首先双击时会有3种情况:
A,最理想的同时双击,目前已经支持
B,同时双击下去,但分别释放,这个可以稍加修改支持
C,先按下一个键再释放,然后再快速按下另外一个键再释放,这种没有办法和单击区分开,目前无解.............

要实现上面B的判断可以这样改

将:
  1.   if(KeyRelease){                                           //短按键判断
  2.       if(KeyRelease &(~KeyMask)){
  3.         KeyShift ^= (KeyRelease & (KEY_SHORT_SHIFT));       //shift按键码(边缘触发)
  4.         KeyBufIn(KeyRelease | KeyShift);
  5.       }else{
  6.         KeyMask = 0;
  7.       }
  8.   }
复制代码


改为:
  1.   if(KeyRelease){                                           //短按键判断
  2.       if(KeyRelease &(~KeyMask)&& !NowReadKey){
  3.         KeyShift ^= (KeyRelease & (KEY_SHORT_SHIFT));       //shift按键码(边缘触发)
  4.         KeyBufIn(KeyRelease | KeyShift | PreReadKey);
  5.       }else{
  6.         KeyMask = 0;
  7.       }
  8.   }
复制代码


出0入0汤圆

发表于 2014-1-29 19:24:07 | 显示全部楼层
mojinpan 发表于 2014-1-25 09:50
晚上抽空研究了一下,双击不好实现啊,首先双击时会有3种情况:
A,最理想的同时双击,目前已经支持
B,同时双 ...

是的,确实是比较麻烦。

我试想过一个方法,就是使用 KeyMask 来记录按键真正按下的情况,例如说在长按次数里面增加一个变量,

如长按次数为2时,说明此时的按键是有效的(可用于组合键或是独立按键),双键组合时,错开一点点时间是比较合理的。

然后释放的时候,能判断这二个键同时释放,或是错开一点点时间再释放的话,也可以。这样的话,手感应该比较好。

我尝试过,但是对释放的滤波算法还不是理解得很好,所以我就放弃了。

楼主可否参考一下此算法?

出0入0汤圆

发表于 2014-1-29 20:51:38 | 显示全部楼层
收藏了,以后有用

出0入0汤圆

发表于 2014-1-29 22:43:42 | 显示全部楼层
还是没有搞懂长按键。请给个实例说明下。

出0入0汤圆

 楼主| 发表于 2014-2-7 12:18:08 | 显示全部楼层
Shampoo 发表于 2014-1-29 22:43
还是没有搞懂长按键。请给个实例说明下。

实例在33楼

出0入0汤圆

 楼主| 发表于 2014-2-7 12:25:27 | 显示全部楼层
ldxepthnn 发表于 2014-1-29 19:24
是的,确实是比较麻烦。

我试想过一个方法,就是使用 KeyMask 来记录按键真正按下的情况,例如说在长按 ...

1.滤波算法你可以不管,这个只是做底层按键真值的判断,你在真值判断后来构思你的算法即可.
2.你说的方法不是非常要,需要延迟判断即意味着短按键的都带有一定的延时,这样短按键的手感会不 好的,因为你至少需200ms以上来判断一次按键,才能做到识别这种连按.
3.其实最致命的问题是,没有办法很好的区分,先后按下的双击和先后按下的单击,导致要么误判概率高,要么单击判断高.
4.基于上面的假设,建议你在应用层上做这个双击的判断,如目前有按键A,B,C,D.其中AB为双击,那么收到代码AB,或A+B,B+A(加号表示先后两次按下),你都认为是双击即可.

出0入0汤圆

发表于 2014-2-7 12:47:55 | 显示全部楼层
赞一个,非常好

出0入0汤圆

 楼主| 发表于 2014-3-1 10:52:27 | 显示全部楼层
自己冒个泡

出0入0汤圆

发表于 2014-3-1 12:20:41 | 显示全部楼层
不错,程序精辟,注解到位。

出0入0汤圆

发表于 2014-3-28 11:04:55 | 显示全部楼层
正好用上,仔细拜读。

出0入0汤圆

发表于 2014-3-28 11:11:12 | 显示全部楼层
mark......收藏了

出0入0汤圆

发表于 2014-3-28 11:30:32 | 显示全部楼层
LZ有心人!

出0入0汤圆

发表于 2014-3-30 15:48:10 | 显示全部楼层
不错的按键代码~~

出0入0汤圆

发表于 2014-5-30 15:40:07 | 显示全部楼层
路过学习学习。。

出0入0汤圆

发表于 2014-6-17 17:26:54 | 显示全部楼层
先标记下,有空来看看

出0入8汤圆

发表于 2014-9-1 12:49:46 | 显示全部楼层
先下载了再说·~

出0入0汤圆

发表于 2014-9-8 18:00:24 | 显示全部楼层
路过学习学习。。

出0入0汤圆

发表于 2014-9-8 18:10:02 | 显示全部楼层
看起来还是不错,希望能有详细的讲解,圈圈教你玩USB书上也有一个按键程序,也不错,不过我没有看得太明白,书上也没有讲原理,比如粗。只能拿来用。

出0入0汤圆

发表于 2014-10-17 16:03:04 | 显示全部楼层
先收藏,有空再拿出来看看

出0入0汤圆

发表于 2014-11-21 23:46:51 | 显示全部楼层
认真看应该没有什么大的问题

出0入0汤圆

发表于 2014-11-22 00:01:51 | 显示全部楼层
先标记下。好像在哪儿见过一样

出0入4汤圆

发表于 2014-11-22 00:43:02 | 显示全部楼层
组合键逻辑比较复杂,
要求:
            先按下组合识别键,然后不管延迟多久再按下某个功能键都能正确识别为组合,  要命的是松开的时候,要求是不管先松开哪个键,组合键行为即告停止,并且在两键先后松开的过程中不得触发单按、长按等行为

出0入0汤圆

发表于 2014-11-24 15:28:39 | 显示全部楼层
路过看看记录下。

出0入0汤圆

发表于 2014-11-24 15:39:31 | 显示全部楼层
好东西,mark一下

出0入46汤圆

发表于 2014-11-25 21:31:17 | 显示全部楼层
楼主的程序相当强大,收藏先!有空再来研究

出0入0汤圆

发表于 2014-12-4 08:43:53 | 显示全部楼层
呵呵刚要用到按键部分,这就来看看楼主的贴。mark下

出0入0汤圆

发表于 2014-12-10 15:46:47 | 显示全部楼层
思路了解了,先咀嚼一下细节看看。。。

出0入0汤圆

发表于 2015-1-3 19:13:22 | 显示全部楼层
很好用,稍微修改下就OK

出0入0汤圆

发表于 2015-1-3 20:55:01 来自手机 | 显示全部楼层
看一下了,支持
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 13:02

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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