嵌入式软件中状态机的几种操作
1、状态机的术语
-
现态:是指当前所处的状态。
-
条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
-
动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
-
次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
2、当前任务需求
如图,是一个定时计数器,计数器存在两种状态,一种为设置状态,一种为计时状态。
- 设置状态
“+” “-” 按键对初始倒计时进行设置
当计数值设置完成,点击确认键启动计时 ,即切换到计时状态
- 计时状态
按下“+” “-” 会进行密码的输入“+”表示1 ,“-”表示输入0 ,密码共有4位
确认键:只有输入的密码等于默认密码,按确认键才能停止计时,否则计时直接到零,并执行相关操作
2、嵌套switch实现嵌套
/***************************************
1.列出所有的状态
***************************************/
typedef enum{
SETTING,
TIMING
} STATE_TYPE;
/***************************************
2.列出所有的事件
***************************************/
typedef enum{
UP_EVT,
DOWN_EVT,
ARM_EVT,
TICK_EVT
} EVENT_TYPE;
/***************************************
3.定义和状态机相关结构:时间显示框会出现的状态
***************************************/
struct bomb
{
uint8_t state;
uint8_t timeout;
uint8_t code;
uint8_t defuse_code;
} bomb1;
/***************************************
4.初始化状态机
***************************************/
void bomb1_init(void)
{
bomb1.state = SETTING;
bomb1.defuse_code = 6; //0110
}
/***************************************
5. 状态机事件派发
***************************************/
void bomb1_fsm_dispatch(EVENT_TYPE evt ,void* param)
{
switch(bomb1.state)
{
case SETTING:
{
switch(evt)
{
case UP_EVT: // "+" 按键按下事件
if(bomb1.timeout< 60)
++bomb1.timeout;
bsp_display(bomb1.timeout);
break;
case DOWN_EVT: // "-" 按键按下事件
if(bomb1.timeout > 0)
--bomb1.timeout;
bsp_display(bomb1.timeout);
break;
case ARM_EVT: // "确认" 按键按下事件
bomb1.state = TIMING;
bomb1.code = 0;
break;
}
}
break;
case TIMING:
{
switch(evt)
{
case UP_EVT: // "+" 按键按下事件
bomb1.code = (bomb1.code <<1) | 0x01;
break;
case DOWN_EVT: // "-" 按键按下事件
bomb1.code = (bomb1.code <<1);
break;
case ARM_EVT: // "确认" 按键按下事件
if(bomb1.code == bomb1.defuse_code)
{
bomb1.state = SETTING;
}
else
{
bsp_display("bomb!")
}
break;
case TICK_EVT:
if(bomb1.timeout)
{
--bomb1.timeout;
bsp_display(bomb1.timeout);
}
if(bomb1.timeout == 0)
{
bsp_display("bomb!")
}
break;
}
}
break;
}
}
-----------------------------------
优点:
简单,代码阅读连贯,容易理解
缺点:
当状态或事件增多时,代码状态函数需要经常改动,状态事件处理函数会代码量会不断增加
状态机没有进行封装,移植性差。
没有实现状态的进入和退出的操作。进入和退出在状态机中尤为重要:
进入事件:只会在刚进入时触发一次,主要作用是对状态进行必要的初始化
退出事件:只会在状态切换时触发一次 ,主要的作用是清除状态产生的中间参数,为下次进入提供干净环境
3、二维转态表
状态机可以分为状态和事件 ,状态的跃迁都是受事件驱动的,因此可以通过一个二维表格来表示状态的跃迁。