jufr12315 发表于 2014-3-25 12:58:24

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

看了马老师那个一个按键,多个功能的帖子。然后自己改成一个函数来实现状态转换,不知道这样做是否合理。

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



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

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


    switch (key_state)
          {
              case KEY_STATE_0:   // 按键初始态
                if (0 == key_press) //当前为低电平
                        {
                                        key_state = KEY_STATE_1;// 键被按下,状态转换到按键消抖和确认状态
                                }
                        break;
             
              case KEY_STATE_1:   // 按键消抖与确认态
                if (0 == key_press)
                        {
                           key_time_long = 0;               
                           key_state = KEY_STATE_2;// 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
                        }
                else
                        {
                           key_state = KEY_STATE_0;// 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
                        }
                        break;
             
              case KEY_STATE_2:
                if(1 == key_press)
                        {
                           key_state = KEY_STATE_3;   // 转换到下次判断是否双击
                                       key_time_double = 0;
                        }
                else if(++key_time_long >= 100)// 继续按下,计时加10ms(10ms为本函数循环执行间隔)      
                        {

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

              case KEY_STATE_4:               // 等待按键释放状态,此状态只返回无按键事件
                if (1 == key_press)
                        {
                                        key_state = KEY_STATE_0; //按键已释放,转换到按键初始态
                        }
                        break;
          }
       
    return key_return;
       
}

letyoufly 发表于 2014-3-25 13:36:42

沙发,
鼓励 + 有空验证下。

jufr12315 发表于 2014-3-25 13:37:48

letyoufly 发表于 2014-3-25 13:36
沙发,
鼓励 + 有空验证下。

{:lol:} O(∩_∩)O谢谢

jufr12315 发表于 2014-3-25 23:01:55

{:mad:}顶一下,来看看这样合理不

tragedy 发表于 2014-3-25 23:34:00

感觉挺好的。

68336016 发表于 2014-3-25 23:39:54

当然可以了,扔到定时器中断里面

jufr12315 发表于 2014-3-26 14:11:03

tragedy 发表于 2014-3-25 23:34
感觉挺好的。

这是我第一次用状态机,所以来看看有没有错误

jufr12315 发表于 2014-3-26 14:13:14

68336016 发表于 2014-3-25 23:39
当然可以了,扔到定时器中断里面

我定时器一毫秒的,然后在大循环,判断是否10毫秒就检查一次

68336016 发表于 2014-3-26 14:31:19

本帖最后由 68336016 于 2014-3-26 14:32 编辑

jufr12315 发表于 2014-3-26 14:13
我定时器一毫秒的,然后在大循环,判断是否10毫秒就检查一次

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

if(ReadKey() == KEY_1)
{
   Led_1_ON();
}
if(ReadKey() == KEY_2)
{
   Led_2_ON();
}

jufr12315 发表于 2014-3-26 16:37:10

68336016 发表于 2014-3-26 14:31
只说我个人观点,如果将按键读取放在大循环里面,你觉得方便么?
比如 最简单的几行代码,肯定希望一调用 ...

if (time_10ms_ok)            //每10ms执行一次,
      {
             time_10ms_ok =0;
             key = key_read();       //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常
             if (key == L_key)
               ........//点亮A_LED,关闭B_LED和C_LED
             else if(key == D_key)
               ........//点亮B_LED,关闭A_LED和C_LED
             else if(key == S_key)
               ........//点亮C_LED,关闭A_LED和B_LED
         }

我在大循环这样不行么?参考马老师的帖子的

machao 发表于 2014-3-27 16:30:20

根据我的经验,不推荐放在定时中断中,至于原因么大家可以讨论一下。任何方法都有优点和不足,要采用最可靠和适合实际需求的。

jufr12315 发表于 2014-3-27 22:14:32

machao 发表于 2014-3-27 16:30
根据我的经验,不推荐放在定时中断中,至于原因么大家可以讨论一下。任何方法都有优点和不足,要采用最可靠 ...

谢谢马老师的指点。

second_chan 发表于 2014-9-29 11:01:28

谢谢分享。。。学习学习
页: [1]
查看完整版本: 我把马老师的按键状态机改成一个函数,这样可否?