C语言FSM 有限状态机

fsm

简介

Finite-State Machines(fsm), 有限状态机。嵌入式系统开发会遇到很多的状态机,简单的状态机,也有复杂系统的状态机。一个门的状态机,autosar 中的网络管理的状态机,CANSM的状态机.....。使用状态机可以简化复杂的系统。

一般写C语言都是,按照解决问题的步骤一步一步写。叫面向过程。

状态机的写法是面向对象的写法,构造了一个状态机数据结构,这个数据结构描述了状态和事件之间的关系 ,状态机会根据事件的输入和当前的状态,切换到下一个状态,并且做出相应的动作。

一般状态机都需要有以下的几个属性:

有限数量的状态,系统处于其中之一

有限数量的事件

对应转换状态的动作

对所有状态转化的明确规定(当状态机处于某个状态并且输入特定事件时做什么动作)

具体怎么去写,就是根据当前的状态,发生事件后,转移到下一个状态,决定执行的动作。

还是以一个简单的状态机举个例子,分享一下三种写法。具体项目的状态机需要进行改进和优化。

OK,我们以一个车门当做例子。

不管用什么办法去写,都需要先定义下面的数据类型

定义状态枚举 、定义事件枚举、创建对应事发送后的动作函数

switch_case 或者 if else 实现

//fsm

// 定义状态枚举
typedef enum {
    CLOSE,
    OPEN,
    LOCK,
    NUM_STATES
} state_eum;

// 定义事件枚举
typedef enum {
    CLOSEED,{
    OPENED,
    LOCKED,
    UNLOCKED,
    NUM_EVENTS
} event_eum;

// 声明状态函数的原型
typedef void (*statefunction)(void *param);

//定义状态机结构体
typedef struct DoorStateMachine_
{
	state_eum current_state;
	statefunction table[NUM_EVENTS];
}statemachine_st;

// 声明状态处理函数
void handler_close(void *param);
void handler_open(void *param);
void handler_lock(void *param);
void handler_unlock(void *param);

statemachine_st machine;
#include <stdio.h>
#include "fsm.h"

// 定义状态处理函数数组
statefunction state_function[NUM_EVENTS] = {
    handler_close,
    handler_open,
    handler_lock,
    handler_unlock
};

// 状态机初始化函数
void DoorManager_Init();
// 状态机主函数
void triggerEvent(event_eum event);

//对应状态下的动作
void handler_close(void *param) {
    printf("close door\n");
    printf("Transitioning to Close\n");
    machine.current_state = CLOSE;
}

void handler_open(void *param) {

    printf("open door\n");
    printf("Transitioning to Open \n");
    machine.current_state = OPEN;
}

void handler_lock(void *param) {
   

    printf("lock door\n");
    printf("Transitioning to Lock \n");
    machine.current_state = LOCK;
}

void handler_unlock(void *param){
    
    printf("unlock door\n");
    printf("Transitioning to Close \n");
    machine.current_state = CLOSE;
}

void DoorManager_Init(){
    int i = 0;

    machine.current_state = CLOSEED;
    for ( i = 0; i < NUM_EVENTS; i++)
    {
        machine.table[i] = state_function[i];
    }
}

void triggerEvent(event_eum event){
    switch (event)
    {
    case CLOSEED:
         if(machine.current_state == OPEN){
            machine.table[CLOSEED](NULL);
         }
         else{
            printf("No transition defined for this event in the current state.\n");
         }
        break;
    case OPENED:
         if(machine.current_state == CLOSE){
            machine.table[OPENED](NULL);
         }
         else{
            printf("No transition defined for this event in the current state.\n");
         }
        break;
    case LOCKED:
        if(machine.current_state == CLOSE){
            machine.table[LOCKED](NULL);
         }
         else{
            printf("No transition defined for this event in the current state.\n");
         }
         break;
    case UNLOCKED:
         if(machine.current_state == LOCK){
            machine.table[UNLOCKED](NULL);
         }
         else{
            printf("No transition defined for this event in the current state.\n");
         }
         break;
    default:
            printf("No defined event\n");
        break;
    }
}

void main(){
    event_eum event;

	DoorManager_Init();

	while (1)
	{
        printf("Enter event: ");
        scanf("%d", &event);
        triggerEvent(event);
	}
	
}

状态转换表实现

状态机也可以描述成下面的这个一张表

//fsm1

// 定义状态枚举
typedef enum {
    CLOSE,
    OPEN,
    LOCK,
    NUM_STATES
} state_eum;

// 定义事件枚举
typedef enum {
    CLOSEED,
    OPENED,
    LOCKED,
    UNLOCKED,
    NUM_EVENTS
} event_eum;

// 声明状态函数的原型
typedef void (*statefunction)(void *param);

//状态转移表
typedef struct FsmTable_
{
    event_eum event;    //事件
    state_eum current_state; //当前状态
    statefunction action; //action
    state_eum next_state; //下一个状态
}FsmTable_st;

//定义状态机结构体
typedef struct DoorStateMachine_
{
	state_eum current_state;
	FsmTable_st* table;
}statemachine_st;

// 声明状态处理函数
void handler_close(void *param);
void handler_open(void *param);
void handler_lock(void *param);
void handler_unlock(void *param);
#include <stdio.h>
#include "fsm1.h"

statemachine_st machine;
FsmTable_st FsmTable[NUM_EVENTS] = {
    {CLOSEED,OPEN,handler_close,CLOSE},
    {OPENED,CLOSE,handler_open,OPEN},
    {LOCKED,CLOSE,handler_lock,LOCK},
    {UNLOCKED,LOCK,handler_unlock,CLOSE}
};

//对应状态下的动作
void handler_close(void *param) {
    printf("close door\n");
    printf("Transitioning to Close\n");
    machine.current_state = CLOSE;
}

void handler_open(void *param) {
    printf("open door\n");
    printf("Transitioning to Open \n");
    machine.current_state = OPEN;
}

void handler_lock(void *param) {
    printf("lock door\n");
    printf("Transitioning to Lock \n");
    machine.current_state = LOCK;
}

void handler_unlock(void *param){
    printf("unlock door\n");
    printf("Transitioning to Close \n");
    machine.current_state = CLOSE;
}

void DoorManager_Init(){
    machine.current_state = CLOSEED;
    machine.table = FsmTable;
}

void triggerEvent(event_eum event){
     if(event >= NUM_EVENTS){
        printf("No defined event\n");

        goto err;
     }

    int i = 0;
    for (i = 0;i < NUM_EVENTS; i++)
    {
        if(machine.table[i].event == event && machine.table[i].current_state == machine.current_state){
            machine.table[i].action(NULL);
            break;
        }
    }

    if(NUM_EVENTS == i){
        printf("No transition defined for this event in the current state.\n");
    }
err:
}

void main(){
    event_eum event;

	DoorManager_Init();

	while (1)
	{
        printf("Enter event: ");
        scanf("%d", &event);
        triggerEvent(event);
	}
}

state_event 实现

状态机,还可以看做是一张二维的表。表的x 为state,y为event(也可以倒过来,看你怎么写)。

// fsm2

// 定义状态枚举
typedef enum {
    CLOSE,
    OPEN,
    LOCK,
    NUM_STATES
} state_eum;

// 定义事件枚举
typedef enum {
    CLOSEED,
    OPENED,
    LOCKED,
    UNLOCKED,
    NUM_EVENTS
} event_eum;

// 声明状态函数的原型
typedef void (*statefunction)(void *param);

// 定义状态机数据结构
typedef struct {
    state_eum current_state; // 当前状态
    statefunction table[NUM_STATES][NUM_EVENTS]; // 状态转移表
} statemachine_st;


// 声明状态处理函数
void handler_close(void *param);
void handler_open(void *param);
void handler_lock(void *param);
void handler_unlock(void *param);
#include <stdio.h>
#include "fsm2.h"

// 设定state_event表
statefunction state_event[NUM_STATES][NUM_EVENTS] = {
    {NULL, handler_open, handler_lock, NULL},
    {handler_close, NULL, NULL, NULL},
    {NULL, NULL, NULL, handler_unlock}
};
//创建状态机
statemachine_st machine;

//对应状态下的动作
void handler_close(void *param) {
    printf("close door\n");
    printf("Transitioning to Close\n");
    machine.current_state = CLOSE;
}

void handler_open(void *param) {
    printf("open door\n");
    printf("Transitioning to Open \n");
    machine.current_state = OPEN;
}

void handler_lock(void *param) {
    printf("lock door\n");
    printf("Transitioning to Lock \n");
    machine.current_state = LOCK;
}

void handler_unlock(void *param){
    printf("unlock door\n");
    printf("Transitioning to Close \n");
    machine.current_state = CLOSE;
}


void init_statemachine(statemachine_st *machine) {
    // 设定初始状态
    machine->current_state = CLOSE;

    // 设定状态转移表
    for (int i = 0; i < NUM_STATES; ++i) {
        for (int j = 0; j < NUM_EVENTS; ++j) {
            machine->table[i][j] = state_event[i][j];
        }
    }
}

// 触发事件
void triggerEvent(statemachine_st *machine, event_eum event) {
    if(event >= NUM_EVENTS){
        printf("No defined event\n");

        goto err;
     }

    // 获取当前状态对应的函数
    statefunction func = machine->table[machine->current_state][event];

    // 调用函数
    if (func != NULL) {
        func(NULL);
    } else {
        printf("No transition defined for this event in the current state.\n");
    }
err:
}

// 测试状态机
int main() {
    event_eum event;

    // 初始化状态机
    init_statemachine(&machine);

    while (1) {
        printf("Enter event: ");
        scanf("%d", &event);
        triggerEvent(&machine, event);
    }

    return 0;
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
#include int main() { int state_key = 1; //钥匙状态 为1时钥匙区有钥匙,为时钥匙区 无钥匙 int state_hold = 0; // 钥匙持有状态 为1时持有钥匙,为时 未持有钥匙 int state_door = 0; //门状态 0:关闭 1:打开 int state_lock = 1; //上锁状态 1:上锁 0:解锁 int order; // 用于存放用户输入指令 printf("this is a game.\n"); printf ("if you want to OPEN THE DOOR ,input 1\n"); printf ("if you want to CLOSE THE DOOR ,input 2\n"); printf ("if you want to LOCK THE DOOR ,input 3\n"); printf ("if you want to UNLOCK THE DOOR,input 4\n"); // printf ("if you want to LOCK THE DOOR ,input 5\n"); printf("please input the order\n"); while(1) { scanf("%d",&order); // if(order!=(1||2||3||4)) // { // printf("worng input ,please input again.\n"); // continue; // } switch(order) { case 1 : if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_door=1; break; case 2: if(state_door==0) { printf("the door has been closed before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_door=0; break; case 3: if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==1) { printf("the door has been lock\n"); break; } state_lock=1; break ; case 4: if(state_door==1) { printf("the door has been opened before\n"); break; } if(state_lock==0) { printf("the door has not been lock\n"); break; } state_lock=0; break ; } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值