一、前言
状态机:一般指有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automaton,缩写:FSA),是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。
状态机中有几个术语:state(状态) 、transition(转移) 、action(动作) 、transition condition(转移条件) 。
- state(状态) :将一个系统离散化,可以得到很多种状态,当然这些状态是有限的。例如:门禁闸机可以划分为开启状态、关闭状态;电扇可以划分为关、一档、二档、三档等状态。
- transition(转移) :一个状态接收一个输入执行了某些动作到达了另外一个状态的过程就是一个transition(转移)。定义transition(转移)就是在定义状态机的转移流程。
- transition condition(转移条件) :也叫做Event(事件),在某一状态下,只有达到了transition condition(转移条件),才会按照状态机的转移流程转移到下一状态,并执行相应的动作。
- action(动作):在状态机的运转过程中会有很多种动作。如:进入动作(entry action)[在进入状态时进行]、退出动作(exit action)[在退出状态时进行]、转移动作[在进行特定转移时进行]。
如下图,就定义了一个只有opened 和closed两种状态的状态机。当系统处于opened状态,在收到输入“关闭事件”,达到了状态机转移条件,系统就转移到了closed状态,并执行相应的动作,此例有一个进入动作(entry action),进入closed状态,会执行close door动作。

二、简单状态机
相信读者们刚入门学习单片机的时候,应该比较常使用标志位来触发任务运行,例如,通过按键来控制LED灯的亮灭,这就是简单的状态机。
1.简单示例:
// 主函数
int main()
{
int flag = 0;
while (1)
{
if( flag == 0 )
{
task_A();
}
else if( flag == 1 )
{
task_B();
}
else if( flag == 2 )
{
task_C();
}
......
}
}
2.代码优化:
往往判断语句太多不利于阅读,那就需要对上面的代码进行优化:
// 主函数
int main()
{
int flag = 0;
while (1)
{
switch (flag)
{
case 0x00:
task_A();
break;
case 0x01:
task_B();
break;
case 0x02:
task_C();
break;
......
default:
break;
}
}
}
3.封装状态机:
在项目中使用状态机往往需要封装一下,避免全局变量标志到处飞就不好修改和维护项目,最好的方法就是高内聚低耦合。
void test(void)
{
static state;
if( state == 0 )
{
if( !task_A() )
{
state = 1;
}
}
else if( state == 1 )
{
if( !task_B() )
{
state = 2;
}
}
else if( state == 2 )
{
if( !task_C() )
{
state = 0;
}
}
}
int main()
{
while (1)
{
test();
}
}
三、完整示例
简单写个小demo,加深一下对状态机的理解,这些状态都是面向有限的状态而言。
#include "stdio.h"
#include "stdint.h"
typedef struct
{
uint8_t flag;
}task_struct;
// 触发任务
void task_open(task_struct *task)
{
if (!task->flag)
{
task->flag = !task->flag;
}
}
// 关闭任务
void task_close(task_struct *task)
{
if (task->flag)
{
task->flag = !task->flag;
}
}
// 任务初始化
void task_init(void)
{
/* 初始化 */
// printf("test init\n");
}
// 任务处理
void task_handle(void)
{
printf("test handle\n");
}
// 轮训任务
void task_A(task_struct *task, uint8_t type)
{
if (!task->flag)
{
task_init();
}
else
{
if (!type)
{
/* 单次执行 */
task_handle();
/* 关闭任务 */
task_close(task);
}
else
{
/* 循环执行 */
task_handle();
}
}
}
int main()
{
task_struct taskA;
task_open(&taskA);
while (1)
{
task_A(&taskA, 0);
}
}
#END