嵌入式软件中状态机的几种操作
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、二维转态表
状态机可以分为状态和事件 ,状态的跃迁都是受事件驱动的,因此可以通过一个二维表格来表示状态的跃迁。