送给像我这样的初学者,什么叫状态机:按键消抖实例。

2020-01-27 11:28发布

看了二三十本教程书,从来没有一本讲到过状态机的概念和编程思路,特从别的论坛转贴一篇很好的实例,献给广大初学者。

用状态机做键盘消抖,很好用,不必延时等待键盘稳定,当检测到有键按下或弹起时能发出相应的键盘消息,英文不好,只好用拼音做变量名和函数名,将就看吧 ;-)

设置状态机有4种状态,A0,A1,A2,A3
初始时处于A0状态,当扫描发现有键按下时,转入到A1状态。
当处于A1状态时,当扫描发现有键按下并且键值等于A1状态下的键值时,转入到A2状态,否则转入A0状态。
当处于A2状态时,当扫描发现有键按下并且键值等于A2状态下的键值时,转入到A3状态,同时发出键按下消息或将按下键的键值入队,否则转入A0状态。
当处于A3状态时,当扫描发现无键按下时,转入到A0状态。同时发出键弹起消息或弹起键的键值入队。
函数JianSaoMiao()用于键扫描的到即时键值
函数JianChuLi()用于按键处理,可放在时钟中断中调用
例:在10ms中断中扫描并处理按键只需调用:JianChuLi(JianSaoMiao());
可使调用后完成发出键按下或键弹起的消息,或者将键值送入键值队列供后续处理

#define Kong 0x00 //定义无键按下时,键扫描返回的值
#define A0 0
#define A1 1
#define A2 2
#define A3 3

struct
{
unsigned char JianZhi;          //当前键值   
unsigned char DangQianZhuangTai;//当前状态
} ZTJ;

void ZTJ_ChuShiHua(void)         //状态机初始化
    {
        ZTJ.DangQianZhuangTai=A0; //初始状态A0
       ZTJ.JianZhi=Kong;          //键值为Kong
    }
uchar JianSaoMiao(void) //键值扫描
{
   uchar JianZhi;
   //在此根据实际电路插入键值扫描程序段,键值存放到JianZhi
   ......
   return(JianZhi);
}
void JianChuLi(uchar JZ)
{
   switch(ZTJ.DangQianZhuangTai)
     {
        case A0:
          {
              if(JZ!=Kong)
               {
                    ZTJ.DangQianZhuangTai=A1; //有键按下,状态转移
                    ZTJ.JianZhi=JZ;       //保存当前键值
                }
         } break;
        case A1:
           {
              if(JZ==ZTJ.JianZhi)
                 ZTJ.DangQianZhuangTai=A2; //有键按下,且键值稳定状态转移
             else
                    ZTJ_ChuShiHua(); //键值不稳,回到初始状态A0
           } break;
        case A2:
          {
              if(JZ==ZTJ.JianZhi)
                {
                    ZTJ.DangQianZhuangTai=A3; //有键按下,且键值稳定状态转移
                    //在此发出键按下消息,或将键按下键值入键值队列供后续处理
                    ......
                }
            else
                    ZTJ_ChuShiHua(); //键值不稳,回到初始状态A0
         } break;
        case A3:
         {
              if(JZ==Kong)
                  {
                         ZTJ_ChuShiHua();   //键已弹起,回到初始状态A0
                            //在此发出键弹起消息,或将键弹起键值入键值队列供后续处理
                           ......
                    }
        } break;
   default :
        {
           ZTJ_ChuShiHua();   //初始状态A0
       }
}
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
97条回答
zhouziwen99_99
1楼-- · 2020-02-02 09:47
mark
qtds11
2楼-- · 2020-02-02 15:46
mark
cuikai12345
3楼-- · 2020-02-02 16:42
 精彩回答 2  元偷偷看……
GDYJ
4楼-- · 2020-02-02 18:01
我目前基本用自己搞的方法,代码不多,大概也就这样:没有按下---判断状态位的状态,状态位是1表示按键松开了,状态位是0表示这次扫描没有键按下;有键按下--判断之前状态位,是1,表示键还未松开(这时加上计数值可以支持长按功能)是0,表示按键刚刚按下
416446891
5楼-- · 2020-02-02 18:42
MARK
my_love
6楼-- · 2020-02-02 20:10
只用VHDL编写过状态机  学习了

一周热门 更多>