zhuyi2576 发表于 2010-5-23 01:37:45

用状态机写的一个按键程序,死活调不出,大伙帮我看下,问题在哪

就三个按键,设置,加,减每个都要实现长按短按功能。单独调一个的时候是可以的,三个一起就乱了,

中断程序里10ms扫一次



/按键
sbit        KEY_SET       = P1^3;
sbit        KEY_UP       = P1^2;
sbit        KEY_DOWN = P1^0;

//状态机四种状态 按下,松手,确认,松手
#define key_state_0                0        //按下               
#define key_state_1                1        //确认
#define key_state_2                2        //计时1 判断长短按
#define key_state_3                3        //松手检测计时

#define set_shot_press        1   //短按
#define set_long_press        2   //长按
#define up_shot_press                   3
#define up_long_press                   4
#define down_shot_press        5
#define        down_long_press        6

uchar keyscan(void)
{
        static uchar key_state = 0, key_time = 0;
        uchar key_set_press,key_up_press,key_down_press;
        uchar        key_return = 0;

        key_set_press = KEY_SET;        // 读按键I/O电平
        key_up_press=KEY_UP;
        key_down_press=KEY_DOWN;

        switch (key_state)
        {
                case key_state_0:           // 按键初始态                       
                     if ((!key_set_press) || !(key_up_press)||!(key_down_press))//如果三个键有任何一个按下
                       key_state = key_state_1;       // 状态转换到键确认态
                     break;                       
                case key_state_1:                // 按键确认态,确认哪一个按下
                       if (!key_set_press)       
                       {       
                              set_down=true;                //确认是set 键,标志位
                              key_state = key_state_2;        // 按键仍按下,状态转换到计时1
                               key_time = 0;                       // 清另按键时间计数器               
                                   }
                       else if (!key_up_press)
                                {
                                up_down=true;
                                key_state = key_state_2;       
                                key_time = 0;                               
                                           }
                                else if(!key_down_press)
                                        {
                                                down_down=true;
                                                key_state = key_state_2;       
                                        key_time = 0;                                               
                                        }
                                elsekey_state = key_state_0;        // 按键已抬起,转换到按键初始态
                                break;       
                case key_state_2://检测是否松开
                        if (key_set_press&&set_down)//set按下过,现在已抬起
                 {
                          key_state = key_state_0;           // 换到按键初始态
                key_return = set_shot_press;        //判断为短按 1
                        }
                        else if (++key_time >= 200&&set_down)        //按下时间>2s
                        {
                                key_state = key_state_0;       
                                key_time = 0;                                // 清按键计数器
                                key_return = set_long_press;// 判断为长按 2
                        }
//-------------------------------------------
                        if (key_up_press&&up_down)
                 {
                          key_state = key_state_0;       
                key_return = up_shot_press;               
                        }
                        else if (++key_time >= 200)       
                        {
                                key_state = key_state_0;       
                                key_time = 0;                       
                                key_return = up_long_press;
                        }
//----------------------------------------------------
                        if (key_set_press&&down_down)
                 {
                          key_state = key_state_0;
                key_return = down_shot_press;                       
                        }
                        else if (++key_time >= 200)               
                        {
                                key_state = key_state_0;       
                                key_time = 0;                       
                                key_return = down_long_press;
                        }
                        break;
        }       
    return key_return;
}

zhuyi2576 发表于 2010-5-23 01:42:33

单独一个按键的程序
uchar keyscan(void)
{
        static uchar key_state = 0, key_time = 0;
        uchar key_set_press,key_up_press,key_down_press;
        uchar        key_return = 0;

        key_set_press = KEY_SET;                                // 读按键I/O电平
        key_up_press=KEY_UP;
        key_down_press=KEY_DOWN;

        switch (key_state)
        {
                case key_state_0:                          // 按键初始态                       
                       if (!key_set_press)如果三个键有任何一个按下
                                       key_state = key_state_1;       // 状态转换到键确认态
                                break;                       
                case key_state_1:                                // 按键确认态,确认哪一个按下
                       if (!key_set_press)       
                       {       
                           key_state = key_state_2;        // 按键仍按下,状态转换到计时1
                            key_time = 0;                       // 清另按键时间计数器               
                                  }
                        elsekey_state = key_state_0;        // 按键已抬起,转换到按键初始态
                                break;       
                case key_state_2://检测是否松开
                     if (key_set_press)//现在已抬起
                 {
                          key_state = key_state_0;           // 换到按键初始态
                key_return = set_shot_press;        //判断为短按 1
                        }
                        else if (++key_time >= 200)        //按下时间>2s
                        {
                                key_state = key_state_0;       
                                key_time = 0;                                // 清按键计数器
                                key_return = set_long_press;// 判断为长按 2
                        }
                        break;
        }       
    return key_return;
}


这是单个按键的程序,很正常,三个一起做我就不会了,请大家指点下吧

towar 发表于 2010-5-31 09:06:52

回复【1楼】zhuyi2576
-----------------------------------------------------------------------

楼主,不知道你的问题解决了吗?我在使用状态机的时候和你也出现同样的问题。一个按键的时候好用,当做三个按键的时候,就出现问题,无法返回值。我在keil下写的,debug的时候正常。。写进去就不对。你是怎么解决的呢?

Gorgon_Meducer 发表于 2010-5-31 13:49:25

以下蓝色文字由版主:Gorgon Meducer 于:2010-05-31,13:49:25 加入。<font color=black>请发贴人注意:本贴放在这分区不合适,即将移走
原来分区:AVR32技术论坛
即将移去的分区:AVR (原ourAVR.com) 技术论坛
移动执行时间:自本贴发表0小时后
任何的疑问或咨询,请可随时联系站长。谢谢你的支持!</font>

ningsane 发表于 2010-6-1 15:08:32

少见,傻孩子发帖居然也被移走了。

volzhcan 发表于 2010-6-1 15:30:30

回复【4楼】ningsane
少见,傻孩子发帖居然也被移走了。
-----------------------------------------------------------------------

是傻孩子移帖,不是被移

tangly2017 发表于 2018-1-6 15:09:09

下载了,谢谢楼主的分享!!!!!!!!!

鲜衣怒马 发表于 2018-1-6 16:17:10

tangly2017 发表于 2018-1-6 15:09
下载了,谢谢楼主的分享!!!!!!!!!

是我瞎了吗,哪有下载链接,这水灌的。。。

bingshuihuo888 发表于 2019-4-24 08:00:10

tangly2017 发表于 2018-1-6 15:09
下载了,谢谢楼主的分享!!!!!!!!!

三个按键的状态机对按键判断怎么弄这个我也不会,可以提一下思路吗?

zmh169 发表于 2019-4-24 14:14:25

bingshuihuo888 发表于 2019-4-24 08:00
三个按键的状态机对按键判断怎么弄这个我也不会,可以提一下思路吗? ...

楼主的程序有三个变量(set_down,up_down,down_down)没交代,看起来应该是全局bool变量,也可以做为静态变量加入子程序中。问题也就出在这几个变量置位之后没清零,应该在设置短按或长按返回值后清零。另外就是长按计时不能在按键松开之前清零,状态机也要在按键松开之后才能重置。

bingshuihuo888 发表于 2019-4-24 15:14:44

zmh169 发表于 2019-4-24 14:14
楼主的程序有三个变量(set_down,up_down,down_down)没交代,看起来应该是全局bool变量,也可以做为静 ...

有三个按键的程序可以指导一下吗?
对于三个按键的我不指导状态机应该怎么写,怎么去判读他们状态

bingshuihuo888 发表于 2019-4-24 15:16:44

一个按键的 看起来写没有问题多个按键就不指导怎么弄了

zmh169 发表于 2019-4-24 15:26:56

本帖最后由 zmh169 于 2019-4-24 15:33 编辑

bingshuihuo888 发表于 2019-4-24 15:14
有三个按键的程序可以指导一下吗?
对于三个按键的我不指导状态机应该怎么写,怎么去判读他们状态 ...

我把楼主程序修改了一下,理论上应该没问题,没调试验证过,供参考。按键按下端口拉低,没考虑多键同时按下的情况。

//按键
sbit      KEY_SET         = P1^3;
sbit      KEY_UP          = P1^2;
sbit      KEY_DOWN                 = P1^0;

//状态机3种状态:按下,确认,松手
#define key_state_0                0      //按下               
#define key_state_1                1      //确认
#define key_state_2                2      //计时 判断长短按


#define set_short_press          1   //短按
#define set_long_press         2   //长按
#define up_short_press          3
#define up_long_press         4
#define down_short_press      5
#define down_long_press       6

uchar keyscan(void)
{
        static uchar key_state = 0, key_time = 0;
        static bool set_down = false, up_down = false, down_down = false;
        uchar key_set_press,key_up_press,key_down_press;
        uchar   key_return = 0;

        key_set_press = KEY_SET;      // 读按键I/O电平
        key_up_press = KEY_UP;
        key_down_press = KEY_DOWN;

        switch (key_state)
        {
        case key_state_0:         // 按键初始态
                set_down = false;
                up_down = false;
                down_down = false;
                key_time = 0;                         // 清零按键时间计数器   
                if ((!key_set_press) || (!key_up_press)|| (!key_down_press))//如果三个键有任何一个按下
                {
                        key_state = key_state_1;         // 状态转换到键确认态
                        if (!key_set_press)      
                        {      
                                set_down=true;                //确认是set 键,标志位
                        }
                        else if (!key_up_press)
                        {
                                up_down=true;                                 
                        }
                        else if(!key_down_press)
                        {
                                down_down=true;                                                      
                        }
                }
                break;                        
        case key_state_1:                // 按键确认态
                if ( (!key_set_press && set_down) ||
                     (!key_up_press && up_down) ||
                     (!key_down_press && down_down) )
                {      
                        key_state = key_state_2;                                                      
                }
                else
                {                       
                        key_state = key_state_0;      // 按键已抬起,转换到按键初始态
                }
                break;      
        case key_state_2:        //检测是否长按
                if( (!key_set_press&&set_down) ||
                  (!key_up_press&&up_down) ||
                  (!key_down_press&&down_down) )
                {
                        if (key_time < 255)      //避免计时器溢出
                        {      
                                key_time ++;               
                        }
                        if(key_time >= 200) //按下时间>=2s,判断为长按
                        {
                                if (!key_set_press&&set_down)       
                                {
                                        key_return = set_long_press;      
                                }
                                //-------------------------------------------
                                else if (!key_up_press&&up_down)
                                {   
                                        key_return = up_long_press;
                                }
                                //----------------------------------------------------
                                else if (!key_down_press&&down_down)
                                {
                                        key_return = down_long_press;
                                }
                        }
                }
                else
                {
                        if(key_time < 200)//按下过,现在已抬起, 判断为短按
                        {
                                if (key_set_press&&set_down)       
                                {
                                        key_return = set_short_press;      
                                }
                                //-------------------------------------------
                                else if (key_up_press&&up_down)
                                {   
                                        key_return = up_short_press;
                                }
                                //----------------------------------------------------
                                else if (key_down_press&&down_down)
                                {
                                        key_return = down_short_press;
                                }
                        }
                        else   //长按结束,判定为无按键按下
                        {
                                key_return = 0;
                        }
                        key_state = key_state_0;   // 换到按键初始态
                }
                break;
        }      
        return key_return;
}

bingshuihuo888 发表于 2019-4-24 15:33:14

感谢你啊

bingshuihuo888 发表于 2019-4-24 15:38:20

我在细细研究一下,感谢指导
页: [1]
查看完整版本: 用状态机写的一个按键程序,死活调不出,大伙帮我看下,问题在哪