amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 1568|回复: 12

我把马老师的按键状态机改成一个函数,这样可否?

[复制链接]
发表于 2014-3-25 12:58:24 | 显示全部楼层 |阅读模式
看了马老师那个一个按键,多个功能的帖子。然后自己改成一个函数来实现状态转换,不知道这样做是否合理。

在硬件电路上已经测试过了,可以实现。但不知道合不合理???



  1. unsigned char key_driver(void)
  2. {
  3.     static unsigned char key_state = KEY_STATE_0;//初始状态
  4.         static unsigned char key_time_long = 0; //长按计时
  5.         static unsigned char key_time_double = 0; //双击计时
  6.     unsigned char key_press;           //按下?   判断
  7.         unsigned char key_return = N_key;  //返回值初始为无键

  8.     key_press = key_input;             // 读按键I/O电平


  9.     switch (key_state)
  10.             {
  11.               case KEY_STATE_0:   // 按键初始态
  12.                 if (0 == key_press) //当前为低电平
  13.                         {
  14.                                         key_state = KEY_STATE_1;// 键被按下,状态转换到按键消抖和确认状态
  15.                                 }
  16.                         break;
  17.                
  18.               case KEY_STATE_1:   // 按键消抖与确认态
  19.                 if (0 == key_press)
  20.                         {
  21.                              key_time_long = 0;                 
  22.                              key_state = KEY_STATE_2;// 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
  23.                         }
  24.                 else
  25.                         {
  26.                              key_state = KEY_STATE_0;// 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
  27.                         }
  28.                         break;
  29.                
  30.               case KEY_STATE_2:
  31.                 if(1 == key_press)
  32.                         {
  33.                              key_state = KEY_STATE_3;   // 转换到下次判断是否双击
  34.                                          key_time_double = 0;
  35.                         }
  36.                 else if(++key_time_long >= 100)  // 继续按下,计时加10ms(10ms为本函数循环执行间隔)        
  37.                         {

  38.                              key_return = L_key;        // 按下时间>1000ms,此按键为长按操作,返回长键事件
  39.                              key_state = KEY_STATE_4;   // 转换到等待释放状态
  40.                         }
  41.                 break;
  42.               case KEY_STATE_3:  // 此状态判断单击或者双击
  43.                          
  44.                       if (0 == key_press)   // 又一次单击(间隔肯定<500ms)
  45.                     {
  46.                          key_return = D_key;           // 返回双击键事件,回初始状态
  47.                                          key_state = KEY_STATE_4;         //等待按键释放
  48.                     }                                                     
  49.             else          // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
  50.                                 {
  51.                                          if(++key_time_double >= 50)
  52.                                  {
  53.                                       key_return = S_key;      // 500ms内没有再次出现单键事件,返回上一次的单键事件
  54.                                                           key_state = KEY_STATE_0;     // 返回初始状态
  55.                                  }
  56.                         }   
  57.                         break;

  58.               case KEY_STATE_4:                 // 等待按键释放状态,此状态只返回无按键事件
  59.                 if (1 == key_press)
  60.                         {
  61.                                         key_state = KEY_STATE_0; //按键已释放,转换到按键初始态
  62.                         }
  63.                         break;
  64.             }
  65.        
  66.     return key_return;
  67.        
  68. }
复制代码

本帖子中包含更多资源

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

x
发表于 2014-3-25 13:36:42 | 显示全部楼层
沙发,
鼓励 + 有空验证下。
 楼主| 发表于 2014-3-25 13:37:48 | 显示全部楼层
letyoufly 发表于 2014-3-25 13:36
沙发,
鼓励 + 有空验证下。

O(∩_∩)O谢谢
 楼主| 发表于 2014-3-25 23:01:55 | 显示全部楼层
顶一下,来看看这样合理不
发表于 2014-3-25 23:34:00 | 显示全部楼层
感觉挺好的。
发表于 2014-3-25 23:39:54 来自手机 | 显示全部楼层
当然可以了,扔到定时器中断里面
 楼主| 发表于 2014-3-26 14:11:03 | 显示全部楼层

这是我第一次用状态机,所以来看看有没有错误
 楼主| 发表于 2014-3-26 14:13:14 | 显示全部楼层
68336016 发表于 2014-3-25 23:39
当然可以了,扔到定时器中断里面

我定时器一毫秒的,然后在大循环,判断是否10毫秒就检查一次
发表于 2014-3-26 14:31:19 | 显示全部楼层
本帖最后由 68336016 于 2014-3-26 14:32 编辑
jufr12315 发表于 2014-3-26 14:13
我定时器一毫秒的,然后在大循环,判断是否10毫秒就检查一次


只说我个人观点,如果将按键读取放在大循环里面,你觉得方便么?
比如 最简单的几行代码,肯定希望一调用ReadKey()返回就是按键值。如果你还在主循环里面不断设置中断标志来判断ReadKey()的值,那程序结构就很混乱了。

  1. if(ReadKey() == KEY_1)
  2. {
  3.      Led_1_ON();
  4. }
  5. if(ReadKey() == KEY_2)
  6. {
  7.      Led_2_ON();
  8. }
复制代码

 楼主| 发表于 2014-3-26 16:37:10 | 显示全部楼层
68336016 发表于 2014-3-26 14:31
只说我个人观点,如果将按键读取放在大循环里面,你觉得方便么?
比如 最简单的几行代码,肯定希望一调用 ...
  1. if (time_10ms_ok)            //每10ms执行一次,  
  2.         {  
  3.              time_10ms_ok =0;  
  4.              key = key_read();       //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常  
  5.              if (key == L_key)  
  6.                  ........//点亮A_LED,关闭B_LED和C_LED  
  7.              else if(key == D_key)  
  8.                  ........//点亮B_LED,关闭A_LED和C_LED  
  9.              else if(key == S_key)  
  10.                  ........//点亮C_LED,关闭A_LED和B_LED  
  11.          }  
复制代码


我在大循环这样不行么?参考马老师的帖子的
发表于 2014-3-27 16:30:20 | 显示全部楼层
根据我的经验,不推荐放在定时中断中,至于原因么大家可以讨论一下。任何方法都有优点和不足,要采用最可靠和适合实际需求的。
 楼主| 发表于 2014-3-27 22:14:32 | 显示全部楼层
machao 发表于 2014-3-27 16:30
根据我的经验,不推荐放在定时中断中,至于原因么大家可以讨论一下。任何方法都有优点和不足,要采用最可靠 ...

谢谢马老师的指点。
发表于 2014-9-29 11:01:28 | 显示全部楼层
谢谢分享。。。学习学习
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 公安备案:44190002001997(交互式论坛) 工信部备案:粤ICP备09047143号 )

GMT+8, 2019-10-23 06:46

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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