学习FSM状态机的C语言实现

共4套代码,内容来自网络,代码经过修改

1========================================================

#include <stdio.h>
#include <stdlib.h>
//! 定义状态名称与状态值之间的关系
#define FSM_START                       0x00
#define FSM_STATE_A                     0x01
#define FSM_STATE_B                     0x02
#define FSM_RESET                       0xFF
#define FSM_STOP                        0xFE

unsigned char inChr='0';

unsigned char fsm_exp_A()
{
    static unsigned char state = FSM_START;  // 初态
    switch (state) 
    {
    case FSM_START:    printf_s("fsm_start,press a to StateA or b to StateB or s to Stop\n");
        state = FSM_STATE_A;
        break;
    case FSM_STATE_A:               printf_s("cur state is A\n");
        if(inChr=='b')
        {
            state = FSM_STATE_B;printf_s("from A to B when [b] pressed \n");
        }
        else if(inChr=='s')
        {
            state = FSM_RESET;  printf_s("from A to Stop when [s] pressed \n");
        }
        break;
    case FSM_STATE_B:            printf_s("cur state is B\n");
        if(inChr=='a')
        {
           state = FSM_STATE_A; printf_s("from B to A when [a] pressed \n");
        }
        else if(inChr=='s')
        {
            state = FSM_RESET;  printf_s("from B to Stop when [s] pressed \n");
        }
        break;
        
    case FSM_RESET:                printf_s("in reset state\n");
    case FSM_STOP:                 printf_s("in start state\n");
    default:                    printf_s("fsm is to unknow state");
                                return 1;
    }
    return 0;
}

int main(int argc, char *argv[]) 
{
    printf_s("准备进入状态机,press a or b\n");
    while(1){
        inChr=getchar();
        if(fsm_exp_A()) break;
    }
    return 0;
}

2================================================================

// 多状态位的状态机
#include <stdio.h>
#include <stdlib.h>

//! 首先将布尔量的状态标志压缩在一个字节里面以节省内存开支
typedef union 
{
   unsigned    Value;
   unsigned     Byte;   
   struct {
        unsigned BIT0:1;
        unsigned BIT1:1;
        unsigned BIT2:1;
        unsigned BIT3:1;
        unsigned BIT4:1;
        unsigned BIT5:1;
        unsigned BIT6:1;
        unsigned BIT7:1;
    }Bits;
}byte_t;

#define FSM_ACTION_FLAG             s_tbState.Bits
#define FSM_STOP_ALL_ACTIONS()      do {s_tbState.Value = 0;}while(0)
#define FSM_START                   (0 == s_tbState.Value)
#define FSM_STATE_A                 FSM_ACTION_FLAG.BIT0
#define FSM_STATE_B                 FSM_ACTION_FLAG.BIT1
#define FSM_STATE_C                 FSM_ACTION_FLAG.BIT2
#define FSM_STATE_D                 FSM_ACTION_FLAG.BIT3
#define FSM_STATE_E                 FSM_ACTION_FLAG.BIT4
#define FSM_STATE_F                 FSM_ACTION_FLAG.BIT5
#define FSM_STATE_G                 FSM_ACTION_FLAG.BIT6
#define FSM_STATE_H                 FSM_ACTION_FLAG.BIT7

unsigned char inChr = '0';

unsigned fsm_example_a()
{
    printf_s("进入子状态a\n");
    if(inChr=='q')  return 0;
    return 1;
}

unsigned fsm_example_b()
{
    static byte_t s_tbState = {0};  //!< 定义状态变量,明确进入 起始状态 0

    if (FSM_START)
    {   
        printf_s("进入起始状态A,start装台自动结束\n");
        FSM_STATE_A = 1;      
    }

    if (FSM_STATE_A) 
    {       
           if (!fsm_example_a()) 
        {
            printf_s("离开子状态A,进入父状态B\n");
            FSM_STATE_B = 1;   
            FSM_STATE_A = 0;    
        }
    }

    if (FSM_STATE_B) 
    {       
        printf_s("进入状态B,一个典型的监视状态\n"); 
       
           if ( inChr=='c' || inChr=='d')     //! 这里检测某些条件(事件)
           {
                
                printf_s("准备,同时“开启” C、D 状态的准备工作\n");//! 这里做一些“开启”某个状态的准备工作
                FSM_STATE_C = 1;    //!< 开启某一个状态而不结束当前状态
                FSM_STATE_D = 1;    //!< 你当然可以一次触发多个状态
                printf_s("已经,同时“开启” B、C、D 状态的准备工作\n");
            } 
            else if (inChr=='B')
            {
                FSM_STATE_B = 0;    printf_s("满足某些条件以后关闭当前状态B\n");  
            }
            else if( inChr=='a')
            {
                printf_s("进入状态A,仅保留一个状态A");
                FSM_STATE_A  = 1;
                FSM_STATE_B=FSM_STATE_C=FSM_STATE_D=FSM_STATE_E=FSM_STATE_F=FSM_STATE_G=FSM_STATE_H=0;
            }
    }

    if (FSM_STATE_F) 
    {       
       if (!fsm_example_a())   //!< 一个典型的子状态机调用
       {      
            //!< 等待子状态机返回false,!子状态机运行完成,进入下一状态
            printf_s("等待子状态机返回false,!子状态机运行完成,进入父状态集内,状态F\n");
            FSM_STATE_F = 0;  //!< 结束当前状态F
            FSM_STATE_A = 1;  //!< 进入下一状态x代表某个字母
            printf_s("结束状态F,进入状态A\n");
        }
    }

   if (FSM_STATE_H) 
   {     //!< 一个典型的中止状态,某些状态机的操作,比如释放某些资源
        printf_s("进入终止状态H,释放资源");
       
        FSM_STOP_ALL_ACTIONS();     //!< 复位状态机
        return 0;                   //!< 返回false表示状态机结束
    }
   return 1;               //!< 返回true表示状态机保持运行
}

int main(int argc, char *argv[]) 
{
    printf_s("准备进入父状态机,press a,b,c,d,e,f,h\n");
    while(1){
       
       if(!fsm_example_b()) break;
       inChr = getchar();
    };
}

3============================================================

// 状态、事件查表法实现

#include <stdio.h>
#include <stdlib.h>

typedef enum {state_1=1,state_2,state_3}   State;                   // 状态可以增加
typedef enum {event_1=1,event_2,event_3,event_4,event_5}  EventID;  // 事件可以增加
typedef void (*Action)(EventID *);  
typedef Action eventAction;

typedef struct 
{
    State   curState;    // 现状态
    EventID eventId;    // 事件ID
    State   nextState;    // 次状态
    Action  action;        // 动作
} StateTransform;       // 状态转换结构

typedef struct
{
    State         state;
    int           transNum;
    StateTransform* transform;  // 状态转换集合
}StateMachine;                  // 状态机对象


StateTransform* findTrans(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* pTrans = findTrans( pSM, evt );  // 查找状态转换表
    
    if ( pTrans == NULL ) 
    {   //  无没有找到状态转换表项目,无次态
        printf_s( "初态s%d -> 事件e%d ->无次态\n", pSM->state,evt);
        return;
    }
    State preState = pSM->state;       //   
    pSM->state = pTrans->nextState;    // 转移到次态
    Action act = pTrans->action;       // 执行动作
    if (act == NULL) {
        printf_s( "初态s%d -> 事件e%d/无动作 -> 次态s%d \n",preState,evt,pSM->state);
        return;
    }
    act(&evt);
}

void f132() {      printf_s("现态s%d -> 事件e%d/动作f132->次态s%d \n",state_1,event_3,state_2); }
void f213() {    printf_s("现态s%d -> 事件e%d/动作f213->次态s%d \n",state_2,event_1,state_3); }
void f242() {    printf_s("现态s%d -> 事件e%d/动作f242->次态s%d \n",state_2,event_4,state_2); }
void f321() {    printf_s("现态s%d -> 事件e%d/动作f321->次态s%d \n",state_3,event_2,state_1); }
void f332() {    printf_s("现态s%d -> 事件e%d/动作f332->次态s%d \n",state_3,event_3,state_2); }
void f353() {    printf_s("现态s%d -> 事件e%d/动作f353->次态s%d \n",state_3,event_5,state_3); }


int run()
{
    StateMachine stateMachine;         // 状态机对象
    stateMachine.state = state_1;      // 初态 
    stateMachine.transNum = 7;         // 可状态转换数量
    StateTransform stateTran[] = {     // 状态转换表集合,共7个状态转换
        {state_1,event_3,state_2,f132},   // S1-> e3/f121 -> S2
        {state_1,event_4,state_2,NULL},
        {state_2,event_1,state_3,f213},
        {state_2,event_4,state_2,f242},
        {state_3,event_2,state_1,f321},
        {state_3,event_3,state_2,f332},
        {state_3,event_5,state_3,f353},
    };
    stateMachine.transform = stateTran;
    
    EventID inputEvent[15] = {                // 顺序输入15个事件 
        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 < 15; i++) 
    {
        runStateMachine(&stateMachine, inputEvent[i]);  //状态机对象,输入事件
    }
    return 0;
}


int main(int argc, char *argv[]) 
{
    printf_s("C语言实现状态机\n-----------------------------\n");
    run();
    return 0;
}

4============================================================

// 这个也是查表方式,带头文件 fsm.h

#ifndef _FSM_H_
#define _FSM_H_

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

typedef  enum {    walk_state=1,talk_state,fly_state,run_state,jump_state } FSM_STATE, *FSM_STATE_P;         // 状态集合
typedef  enum {    walk_event=1,talk_event,fly_event,run_event,jump_event } FSM_EVENT, *FSM_EVENT_P;        // 事件集合

typedef  void(*EAF)(void *);        // 动作函数类型声明;
typedef EAF EventActFun;            // 类型定义

// 状态表结构
typedef struct FsmTable_s
{
    uint8_t event;                       // 事件
    uint8_t CurState;                    // 现态
    //void (*eventActFun)(void *);         // 动作,函数指针类型不明确 
    EventActFun eventActFun;             // 动作,使用明确的类型
    uint8_t NextState;                   // 次态
}FsmTable_T,*FsmTable_T_P;

// 状态机对象
typedef struct FSM_s
{
    FsmTable_T *FsmTable;                // 状态表空间
    uint8_t     curState;                // 现态 
    uint8_t     stuMaxNum;                 
} FSM_T, *FSM_T_P ;

void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState);
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm);
#endif

// main.c

/* https://blog.csdn.net/weixin_44088559/article/details/105539313
   C语言实现简单有限状态机(FSM)  */
#include "fsm.h"

// 状态转换
static void FSM_StateTransfer(FSM_T *pFsm, uint8_t state)
{
    pFsm->curState = state;
}
//  状态机处理函数, pFsm状态机对象, event触发事件, parm动作执行参数
void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm)
{
    FsmTable_T *pAcTable = pFsm->FsmTable;    
    EventActFun actionFun = NULL;            // void (*ventActFun)(void *) = NULL;
    uint8_t     CurState = pFsm->curState;    // 现态
    
    uint8_t flag = 0;                       // 状态转换标记
    uint8_t NextState;
    
    for (uint8_t i = 0; i < pFsm->stuMaxNum; i++)
    {
        if (event == pAcTable[i].event && CurState == pAcTable[i].CurState)
        {
            flag = 1;    
            actionFun = pAcTable[i].eventActFun;
            NextState = pAcTable[i].NextState;    
            break;
        }
    }
    if (flag)  
    {
        if (actionFun != NULL) { actionFun(parm); }     // 执行动作          
        FSM_StateTransfer( pFsm, NextState );           // 转到次态
    }
}

//状态机注册 : pFsm状态机对象,pTable状态迁移表,stuMaxNum迁移表数量
void FSM_Regist(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState)
{
    pFsm->FsmTable  = pTable;      // 状态空间表
    pFsm->curState  = curState;    // 初状态
    pFsm->stuMaxNum = stuMaxNum;   // 状态数量
}

//函数声明
void walk(void * );
void talk(void * );
void fly( void * );
void run( void * );
void jump(void * );


//main.c

int main(int argc, char *argv[]) 
{
    FSM_T    fsm   = { 0} ;                        /*创建FSM_T对象*/
    FSM_T_P  fsm_p = &fsm;
    
    /* 创建FsmTable_T表 */
    FsmTable_T  fsm_table[5] = 
    {
        {  walk_event, walk_state, walk, talk_state },
        {  talk_event, talk_state, talk, run_state  },
        {  fly_event,  fly_state,  fly,  jump_state },
        {  run_event,  run_state,  run,  fly_state  },
        {  jump_event, jump_state, jump, walk_state }
    };
    char  i = 1;

    FSM_Regist( fsm_p, fsm_table, 5, walk_state); /*FSM_Init()初始化*/
    int EVENT  = 0;                              // 事件标记
    while(1)
        
    {
        FSM_EventHandle( fsm_p, EVENT, &i);          /*轮询运行状态机*/
        //EVENT++;
        if(EVENT++>5) EVENT = 1;
        //getchar();
    }
    return  0;
}
//函数实现
void walk(void * t){    printf("我正在走\r\n"); }
void talk(void * t){    printf("我正在讲话\r\n"); }
void fly(void * t){        printf("我正在飞机上\r\n");    }
void run(void * t ){    printf("我正在跑步\r\n"); }
void jump(void * t){    printf("我正在跳高\r\n"); }

5========================================================

#include <stdio.h>
#include <conio.h> //获取键盘建值状态

typedef enum  {    event1 = 0x31,    event2,    event3,    event4,    event5,    event6,    event7,    event8} SEvent;//所有事件的集合
typedef enum  {    state1 = 1,    state2,    state3,    state4,    state5}  CState;  //所有状态的集合
typedef struct {
    int Event;//触发的事件
    int Curstate;//当前状态
    void (*CallBack)();//触发之后的回调函数
    int Nextstate;//下一个状态
}State_table;//状态表
typedef struct {
    int Curstate;//当前状态
    State_table* Stable;//状态表
    int Stable_size;//状态表的项数
}FSM;//实际操作的状态机对象

/*状态机注册,给它一个状态表
pFsm 新建的状态机
pTable 传入的状态机对应表
state 初始默认状态*/
void FSM_Regist(FSM* pFsm, State_table *pTable, CState state,int TableSize)
{
    pFsm->Stable = pTable;//传入所给的状态表
    pFsm->Stable_size= TableSize;//所给状态表的大小
    pFsm->Curstate = state;//当前的默认状态
}

void FSM_EventHandle(FSM *pFsm, SEvent event) {//注意这里要传入的pFsm必须是一个指针,不然改不了状态
    
    void (*ActionCallBack)();
    ActionCallBack = 0;//默认置空
    for (int i = 0; i < pFsm->Stable_size; i++) {
        if (pFsm->Curstate == pFsm->Stable[i].Curstate && event == pFsm->Stable[i].Event) {
            ActionCallBack = pFsm->Stable[i].CallBack;//找出要执行的函数
            pFsm->Curstate = pFsm->Stable[i].Nextstate;//更改状态
        }
    }
    if (ActionCallBack != 0) {
        ActionCallBack();//动作执行
    }
    else return;
}

void thing1() {    printf("这里是执行函数1  \r\n");}
void thing2() {    printf("这里是执行函数2  \r\n");}
void thing3() {    printf("这里是执行函数3  \r\n");}
void thing4() {    printf("这里是执行函数4  \r\n");}
void thing5() {    printf("这里是执行函数5  \r\n");}

State_table STranTable[] = {
    { event1,  state1, thing1,  state2 },
    { event2,  state2, thing2,  state3 },
    { event3,  state3, thing3,  state4 },
    { event4,  state4, thing4,  state5 },
    { event5,  state5, thing5,  state5 },
    { event1,  state5, thing1,  state1 },
    { event3,  state3, thing1,  state5 },
};
int main(void)
{
    FSM Mfsm;
    FSM_Regist(&Mfsm, STranTable, state1,sizeof(STranTable)/sizeof(State_table));
    while (1) {
        while (_kbhit()) {
            SEvent key = (SEvent)_getch();
            FSM_EventHandle(&Mfsm, key);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值