#if 0
【状态机】
1、什么是状态机
2、有限状态机
3、状态机的2中类型
4、状态机的主要用途
5、状态机解决了什么问题
6、C语言实现状态机实例
1、什么是状态机
状态机最初应用在数字电路设计领域,适合描述有先后顺序或者有逻辑规律的事情;
状态机的本质:对有逻辑顺序,或时序规律事件的一种描述方法;
状态机通过响应一系列事件而运行;当到达终态,状态机停止运行。
即:事务的状态在某事件的触发下,从其中的一个状态切换到另一个状态,直到到达终态。
2、有限状态机
有限个状态值,这个机器同时能够从外部接收事件和信息输入,机器在接收到外部输入的事件后,综合考虑当前自己的状态和用户输入的信息,然后机器做出动作:跳转到另一个状态。
状态机的关键点:当前状态、外部输入、下一状态。
比如:水、水蒸气、冰三态之间转换。
3、状态机的2种类型
moore型状态机:输出只与当前状态有关(与输入信号无关);
mealy型状态机:输出不只和当前态有关,海域输入信号有关。
(注:输出即跳转到下一状态)
4、状态机的主要用途
数字电路设计中
软件设计:(框架类型的设计:如消息机制,操作系统的GUI机制)
5、状态机解决了什么问题
传统应用程序的控制流程都是基于顺序的,即遵循事先设置好逻辑,从头到尾执行,很少有事件(异常事件或者终端)能够改变标准执行流程;
状态机能够解决:应用程序是由外部发生的事件来驱动;即:事件在应用程序之外生成,无法由应用程序或程序员来控制,具体需要执行代码取决于接受到的事件,或者它相对于其他事件的抵达时间。
6、C语言实现状态机实例
1)软件实现一个序列检测器电路,功能是检测出串行输入数据中的4位二进制是0101时,输出为1,某则输出为0;注意:考虑序列重叠的可能性,比如:010101,相当于出现2个0101
2)开锁状态机:用户连续输入正确的密码则会开锁,否则退回到初始状态,要求用户重新输入密码。
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define EVENT_COUNT 15
// 状态机的状态枚举如下:
typedef enum {
state_1 = 1,
state_2,
state_3
} State;
// 事件ID枚举如下:
typedef enum{
event_1 = 1,
event_2,
event_3,
event_4,
event_5
} EventID;
// 定义一个某状态下,处理某事件的函数指针
typedef void (*EVENT_HANDLE)(EventID *evt);
// 状态迁移结构体如下:
typedef struct {
State curState; //当前状态
EventID eventId; //事件ID
State nextState; //下个状态
EVENT_HANDLE action;//具体表现
} StateTransform;
// 将“状态迁移结构体”封装在StateMachine中:
typedef struct{
State state;
int transNum;
StateTransform *transform;
} StateMachine;
// 当前状态 + 有事件触发 ==> 跳到下个状态,同时执行回到函数;
// 此处是获取 状态迁移结构信息,若未找到,则返回NULL
StateTransform* FindStateRunInfo(StateMachine* pSM, const EventID evt)
{
int i;
for (i = 0; i < pSM->transNum; i++) {
if ((pSM->transform[i].curState == pSM->state) &&
(pSM->transform[i].eventId == evt)) {
return &pSM->transform[i];
}
}
return NULL;
}
// 状态机实现如下:
void RunStateMachine(StateMachine *pSM, EventID evt)
{
StateTransform *stateInfo;
stateInfo = FindStateRunInfo(pSM, evt);
if (stateInfo == NULL) {
printf("CurState= %d, Do not process enent: %d\r\n", pSM->state, evt);
return;
}
pSM->state = stateInfo->nextState;
EVENT_HANDLE action = stateInfo->action;
if (action == NULL) {
printf("change state to %d. No action\r\n", pSM->state);
return;
}
action(&evt); // 当前状态 + 有事件触发 ==> 跳到下个状态,同时执行回到函数
}
void f121(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
void f231(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
void f221(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
void f311(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
void f321(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
void f331(EventID *evt)
{
printf("__func__:%s, event is: %d\n", __func__, *evt);
}
// 最后模拟一些随机事件,我们只需要弄清楚事件ID,状态切换,具体表现就可以了,
// 在代码中就是填写stateTran[]这个表,一旦有增减事件,状态等等, 其代码如下:
int main(void)
{
StateMachine stateMachine;
(void)memset(&stateMachine, 0, sizeof(stateMachine));
stateMachine.state = state_1;
stateMachine.transNum = 7;
StateTransform stateTran[] = {
{ state_1, event_3, state_2, f121 },
{ state_1, event_4, state_2, NULL },
{ state_2, event_1, state_3, f231 },
{ state_2, event_4, state_2, f221 },
{ state_3, event_2, state_1, f311 },
{ state_3, event_3, state_2, f321 },
{ state_3, event_5, state_3, f331 }
};
stateMachine.transform = stateTran;
printf("state machine first state: %d, transNum: %d\n",
stateMachine.state, stateMachine.transNum);
EventID inputEvent[EVENT_COUNT] = {
event_1, event_2, event_3, event_4, event_5,
event_1, event_2, event_3, event_4, event_5,
event_1, event_2, event_3, event_4, event_5
};
int i;
for (i = 0; i < EVENT_COUNT; i++) {
RunStateMachine(&stateMachine, inputEvent[i]);
}
return 0;
}
/*
执行结果:
[zll@zll 6_weiXin_Exp]$ ./a.out
state machine first state: 1, transNum: 7
CurState= 1, Do not process enent: 1
CurState= 1, Do not process enent: 2
__func__:f121, event is: 3
__func__:f221, event is: 4
CurState= 2, Do not process enent: 5
__func__:f231, event is: 1
__func__:f311, event is: 2
__func__:f121, event is: 3
__func__:f221, event is: 4
CurState= 2, Do not process enent: 5
__func__:f231, event is: 1
__func__:f311, event is: 2
__func__:f121, event is: 3
__func__:f221, event is: 4
CurState= 2, Do not process enent: 5
[zll@zll 6_weiXin_Exp]$
*/