一文带你了解状态机思维

状态机思维

 状态机思维可以更好的描述系统的行为,方便整个系统逻辑的理解和后期程序的管理。

简介

回主目录
 状态机(State Machine)在嵌入式软件编程中是很常见的一种编程思想,它是一种描述和处理系统行为的模型,将系统划分为一组离散的状态,定义了状态之间的转换条件和操作。
 状态机由状态(State)状态转换条件(Transition)动作(Action)初始状态(Initial State)初始状态(Initial State)组成。

类型
 状态机可以分为两种类型:有限状态机(FSM)和无限状态机(USM)。

  • 有限状态机(FSM)是最常见的状态机实现方式。它由确定的状态、预定义的转移条件和对应的动作组成。程序根据当前状态和输入条件,进行状态转移和执行相应的动作。
  • 无限状态机(USM)是一种更灵活的状态机实现方式,状态和转移条件可以动态生成和修改。USM通常使用状态模式进行实现,状态之间通过递归调用实现转移,可以处理更复杂的状态转移逻辑。

实现方式:

  1. 条件逻辑编码法:这种方法通过编写代码来直接实现状态机的转换和动作。一般使用switch语句或、if-else语句或者函数指针等方式来处理不同的事件和状态转换。
  2. 表驱动法:这种方法利用数据结构来存储状态及其对应的转换条件和动作。通常使用状态转换表(State Transition Table)或状态转换图(State Transition Diagram)来描述状态机的行为。在C语言中,可以使用表格(如二维数组)来表示状态及其转换。通过查表即可根据当前状态和输入事件找到下一个状态,执行相应的动作。
  3. 状态模式:使用面向对象的方式,将状态抽象为类,每个状态类实现自己的行为和状态迁移逻辑。

基本步骤

  1. 定义状态:根据具体系统需求,确定状态的数据和含义。每个状态都有一个标识符来表示。

  2. 定义状态转换条件:确定触发状态转换的条件,即从一个状态转移到另一个状态所需的条件。如输入事件、定时器等。

  3. 定义动作:确定每个状态下需要执行的动作操作,如更新数据、发送消息等。

  4. 实现状态机逻辑:将状态、转换条件和动作组织起来,使用代码实现状态机逻辑。可以定义状态机的数据结构和函数,数据结构通常包含当前状态、状态转换表等信息。函数可以用来处理状态转换、执行状态转换动作等。

  5. 测试和调试:通过测试验证状态机的正确性和稳定性,修复存在的问题。

框架

回主目录

一、条件逻辑编码

模型一:

/*定义状态A,B,C,每个状态标识一个特定的行为或状态*/
typedef enum{
    STATE_A,
    STATE_B,
    STATE_C,
    // ...
} State;
/*定义状态转换条件,开始和停止*/
typedef enum{
    EVENT_START,
    EVENT_STOP
} Event;
/*实现状态机逻辑*/
void processEvent(Event event,State *currentState) 
{
	/*根据当前的状态执行对应的动作*/
    switch (*currentState) { 
        case STATE_A:
            if (event == EVENT_START)
            {
                // 状态转移到状态B,执行状态转移时会产生的动作
                *currentState = STATE_B;
                ……	
            }
            break;
        case STATE_B:
            if (event == EVENT_STOP)
            {
                //状态转移到状态C,执行状态转移时会产生的动作
                *currentState = STATE_C;
				……	
            }
            break;
        case STATE_C:
            // 停止
            break;
        default:
            // 错误处理
            printf("错误的状态\n");    /*根据语法规范,错误时最好有个日志输出,方便Debug*/
            break;
    }
}

int main()
{
    State currentState = STATE_A; 
    processEvent(EVENT_START, &currentState); //此时跳转到了状态B
    processEvent(EVENT_STOP,  &currentState); //此时跳转到了状态C
    return 0;
}

模型二:

/*定义状态A,B,C,每个状态标识一个特定的行为或状态*/
typedef enum {
    STATE_A,
    STATE_B,
    STATE_C,
    // ...
} State;
/*实现状态机逻辑*/
int main()
{
	while(1)
	{
	  switch (current_state)
	  {
	    case STATE_A:
	       // 处理状态A的逻辑
	       // ...
	       if(/* 满足某个条件 */)
	       {
	          /*触发状态转换条件,状态跳转*/
	          current_state = STATE_B;
	       } 
	       else if(/* 满足某个条件 */)
	       {
	          current_state = STATE_C;
	       }
	       break;
	    case STATE_B:
	        // 处理状态B的逻辑
	        // ...
	        current_state = STATE_C;
	        break;
	    case STATE_C:
	       // 处理状态C的逻辑
	       // ...
	       current_state = STATE_A;
	       break;
	       // ...
	  }
	}
}

二、表驱动法

回主目录
 表驱动法通过使用一张状态转换表来实现状态机。这张表保存了状态转换的信息,程序会根据当前状态和输入来查找对应的状态转换,并执行相应的操作。

#include <stdio.h>
/*定义状态A,B,C,每个状态标识一个特定的行为或状态*/
typedef enum {
    State_A,
    State_B,
    State_C
} State;
// 定义输入事件
typedef enum {
    Event_1,
    Event_2
} Event;

// 定义状态转换表
typedef struct {
    /*当前状态-当前事件-下个状态-动作*/
    State current_state;
    Event current_event;
    State next_state;
    void (*action)();
} Transition;

// 定义状态转换表数组
Transition transitions[] = {
    /*当前状态-当前事件-下个状态-动作*/
    {State_A, Event_1, State_B, action1},
    {State_A, Event_2, State_C, action2},
    // ... 其他状态转换
};

/*根据当前状态和输入事件在定义的表里面查找相应状态转换*/
Transition* findTransition(State current_state, Event current_event) {
    for (int i = 0; i < sizeof(transitions) / sizeof(transitions[0]); i++) {
        if (transitions[i].current_state == current_state &&
            transitions[i].current_event == current_event) {
            return &transitions[i];
        }
    }
    return NULL;
}

// 执行相应的操作
void action1() {
    printf("Performing action 1.\n");
}

void action2() {
    printf("Performing action 2.\n");
}

int main() {
    /*状态和事件初始化*/
    State current_state = State_A;
    Event current_event = Event_1;
    /*查找状态转换,并执行相应的操作*/
    Transition* transition = findTransition(current_state, current_event);
    if (transition != NULL) {
        /*如果表中存在对应的数据,则更新状当前状态*/
        current_state = transition->next_state;
        /*执行转换动作*/
        transition->action();      
    }
    return 0;
}

三、状态模式

回主目录
 使用面向对象的方式,将状态抽象为类,但在C语言中,并不能直接使用面向对象的语法来实现状态机。但是可以通过结构体和函数指针来模拟面向对象的思想,如下所示:

#include <stdio.h>

// 定义状态机结构体
typedef struct {
    void (*state)();
    void (*transition)(Event);
} StateMachine;

// 定义状态函数
void stateA(Event event);
void stateB(Event event);
void stateC(Event event);

// 定义状态机对象
StateMachine state_machine = {stateA, NULL};

// 定义状态转换函数
void transition(Event event) 
{
    state_machine.state(event);
}

// 定义状态函数的实现
void stateA(Event event) 
{
    if (event == Event_1) 
    {
        printf("Performing action 1.\n");
        state_machine.state = stateB;
    } 
    else if (event == Event_2) 
    {
        printf("Performing action 2.\n");
        state_machine.state = stateC;
    }
}

void stateB(Event event) 
{
    // 状态B的实现...
}
void stateC(Event event) 
{
    // 状态C的实现...
}
int main() 
{
    Event current_event = Event_1;
    // 执行状态转换
    transition(current_event);
    return 0;
}

总结:以上就是状态机的一些内容,它可以说是一种总结归纳的思想,能让你更好的梳理整个系统的逻辑。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值