搜索
bottom↓
回复: 14

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

[复制链接]

出0入0汤圆

发表于 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;                                               
                                        }
                                else  key_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;
}

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

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

出0入0汤圆

 楼主| 发表于 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;                         // 清另按键时间计数器               
                                  }
                        else  key_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;
}


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

出0入0汤圆

发表于 2010-5-31 09:06:52 | 显示全部楼层
回复【1楼】zhuyi2576  
-----------------------------------------------------------------------

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

出0入296汤圆

发表于 2010-5-31 13:49:25 | 显示全部楼层
以下蓝色文字由版主:Gorgon Meducer 于:2010-05-31,13:49:25 加入。
<font color=black>请发贴人注意:
本贴放在这分区不合适,即将移走
原来分区:[1030]AVR32技术论坛
即将移去的分区:[1000]AVR (原ourAVR.com) 技术论坛
移动执行时间:自本贴发表0小时后

任何的疑问或咨询,请可随时联系站长。谢谢你的支持!
</font>

出0入0汤圆

发表于 2010-6-1 15:08:32 | 显示全部楼层
少见,傻孩子发帖居然也被移走了。

出0入0汤圆

发表于 2010-6-1 15:30:30 | 显示全部楼层
回复【4楼】ningsane
少见,傻孩子发帖居然也被移走了。
-----------------------------------------------------------------------

是傻孩子移帖,不是被移

出0入0汤圆

发表于 2018-1-6 15:09:09 | 显示全部楼层
下载了,谢谢楼主的分享!!!!!!!!!

出50入58汤圆

发表于 2018-1-6 16:17:10 来自手机 | 显示全部楼层
tangly2017 发表于 2018-1-6 15:09
下载了,谢谢楼主的分享!!!!!!!!!

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

出0入0汤圆

发表于 2019-4-24 08:00:10 | 显示全部楼层
tangly2017 发表于 2018-1-6 15:09
下载了,谢谢楼主的分享!!!!!!!!!

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

出0入0汤圆

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


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

出0入0汤圆

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

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

出0入0汤圆

发表于 2019-4-24 15:16:44 | 显示全部楼层
一个按键的 看起来写没有问题  多个按键就不指导怎么弄了

出0入0汤圆

发表于 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;
}

出0入0汤圆

发表于 2019-4-24 15:33:14 | 显示全部楼层
感谢你啊

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-24 05:22

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

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