首页 > 其他分享 >C 语言实现简单有限状态机

C 语言实现简单有限状态机

时间:2023-01-08 14:00:39浏览次数:58  
标签:状态 语言 int 有限 void FSM 状态机 event

简介

常说的状态机是有限状态机 FSM,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。
三个特征:

  • 状态总数(state)是有限的。
  • 任一时刻,只处在一种状态之中。
  • 某种条件下,会从一种状态转变(transition)到另一种状态。

设计状态机的关键点:当前状态、外部输入、下一个状态。

状态机分类

Moore 型状态机

Moore 型状态机特点是:输出只与当前状态有关(与输入信号无关)。相对简单,考虑状态机的下一个状态时只需要考虑它的当前状态就行了。

Mealy 型状态机

Mealy 型状态机的特点是:输出不只和当前状态有关,还与输入信号有关。状态机接收到一个输入信号需要跳转到下一个状态时,状态机综合考虑 2 个条件(当前状态、输入值)后才决定跳转到哪个状态。

实现一个简单的状态机

代码参考AstarLight/FSM-framework

以小明的一天设计出一个状态机,下图为状态转移图:

首先,有限状态机的状态是有限的,我们可以定义一天中的状态:

enum
{
 GET_UP,
 GO_TO_SCHOOL,
 HAVE_LUNCH,
 DO_HOMEWORK,
 SLEEP,
};

状态机在没有事件的驱动下就是一潭死水,所以我们还需要定义出一些会发生的事件,去驱动状态机的运转:

enum
{
 EVENT1 = 1,
 EVENT2,
 EVENT3,
};

再定义一些在某个状态下需要处理的动作,也就是函数:


void GetUp()
{
 // do something
 printf("xiao ming gets up!\n");

}

void Go2School()
{
 // do something
 printf("xiao ming goes to school!\n");
}

void HaveLunch()
{
 // do something
 printf("xiao ming has lunch!\n");
}

void DoHomework()
{
 // do something
 printf("xiao ming does homework!\n");
}

void Go2Bed()
{
 // do something
 printf("xiao ming goes to bed!\n");
}

定义一个状态表结构,用来表示一个状态机的状态:

typedef struct FsmTable_s
{
 int event;              //事件
 int CurState;           //当前状态
 void (*eventActFun)();  //函数指针
 int NextState;          //下一个状态
}FsmTable_t;

接下来,我们就可以这个结构定义一个状态表,状态机根据这个表进行状态的流转:

FsmTable_t XiaoMingTable[] =
{
 //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
 { EVENT1,  SLEEP,           GetUp,        GET_UP },
 { EVENT2,  GET_UP,          Go2School,    GO_TO_SCHOOL },
 { EVENT3,  GO_TO_SCHOOL,    HaveLunch,    HAVE_LUNCH },
 { EVENT1,  HAVE_LUNCH,      DoHomework,   DO_HOMEWORK },
 { EVENT2,  DO_HOMEWORK,     Go2Bed,       SLEEP },
};

定义一个状态机结构,表示一个状态机:

typedef struct FSM_s
{
 FsmTable_t* FsmTable;   //指向的状态表
 int curState;           //FSM当前所处的状态

}FSM_t;

有了这些基本的结构,就可以写主函数了:

int main()
{
 FSM_t fsm;                        // 实例化一个状态机
 InitFsm(&fsm);                    // 初始化状态机
 int event = EVENT1;               // 初始化事件,为了启动状态机流转,
                                      // 因为状态机只有在有时间发生时才会改变状态

 //小明的一天,周而复始的一天又一天,进行着相同的活动
 while (1)
 {
  printf("event %d is coming...\n", event);
  FSM_EventHandle(&fsm, event); // 有了初始事件,我们就需要处理这个事件,
                                      // 再写一个处理事件的函数
  printf("fsm current state %d\n", fsm.curState);
  test(&event); 
  Sleep(1);                     //休眠1秒,方便观察
 }

 return 0;
}

// 测试用的,模拟事件的发生
void test(int *event)
{
 if (*event == 3)
 {
  *event = 1;
 }
 else
 {
  (*event)++;
 }
 
}

编写初始化状态机的函数:

int g_state_max_num = 0; // 状态机的状态最大数量,根据状态表的大小来计算
// 初始化FSM
void InitFsm(FSM_t* pFsm)
{
 g_state_max_num = sizeof(XiaoMingTable) / sizeof(FsmTable_t);
 pFsm->curState = SLEEP; // 初始状态为睡觉
    pFsm->FsmTable = XiaoMingTable;
}

编写事件处理函数:

/* 事件处理 */
void FSM_EventHandle(FSM_t* pFsm, int event)
{
 FsmTable_t* pActTable = pFsm->FsmTable;
 void (*eventActFun)() = NULL;  //函数指针初始化为空
 int NextState;
 int CurState = pFsm->curState;

 /* 获取当前动作函数 */
 for (int i = 0; i<g_max_num; i++)
 {
  //当且仅当当前状态下来个指定的事件,我才执行它
  if (event == pActTable[i].event && CurState == pActTable[i].CurState)
  {
   pActTable[i].eventActFun();                      // 执行动作函数
            FSM_StateTransfer(pFsm, pActTable[i].NextState); // 执行状态转移
   break;
  }
        else
        {
            // do nothing
        }
 }
}
/* 状态迁移 */
void FSM_StateTransfer(FSM_t* pFsm, int state)
{
 pFsm->curState = state;
}

参考资料

Linux 编程之有限状态机 FSM 的理解与实现 - Madcola - 博客园
JavaScript 与有限状态机 - 阮一峰的网络日志
有限状态机 - 维基百科,自由的百科全书

标签:状态,语言,int,有限,void,FSM,状态机,event
From: https://www.cnblogs.com/lifeislife/p/17034602.html

相关文章

  • WebAssembly 语言支持
    对WebAssembly(和WASI)的支持在所有主要编程语言中都取得了很好的进展。评估一种语言对WebAssembly/WASI的支持程度很重要,因为它可以让我们了解wasmtime和Enarx的可......
  • 初学者难点:如何在C语言中打印小数???
       首先对于我自己而言,刚刚学习C语言的时候一直弄不清楚如何打印小数,尤其是打印两位或者三位小数,当时只会打印整数,也就导致后来一直被蒙在鼓里。下面是我在弄清楚如何......
  • enum C语言
    1.定义一种新的数据类型-枚举型以下代码定义了这种新的数据类型-枚举型enumDAY{MON=1,TUE,WED,THU,FRI,SAT,SUN};(1)枚举型是一个集合,集合中的元......
  • C语言:身份证号校验位计算
    #include<stdio.h>/*身份证号码是由18位数字组成的,他们分别表示:1、前1、2位数字表示:所在省份的代码。2、前3、4位数字表示:所在城市的代码。3、前5、6位......
  • Go语言学习day2
    1.go的结构体没有构造函数,但是可以自己实现一个。由于值拷贝的开销比较大,所以返回的是结构体指针类型packagemainimport"fmt"typepersonstruct{ name,citystr......
  • 适合编程初学者的开源项目:小游戏2048(Go语言版)
    目标为编程初学者打造入门学习项目,使用各种主流编程语言来实现。2048游戏规则一共16个单元格,初始时由2或者4构成。1、手指向一个方向滑动,所有格子会向那个方向运动。2......
  • R语言中axis 中调整标签与轴线的距离
     使用padj参数调整垂直距离;使用hadj参数调整水平距离;  001、padj参数par(mfrow=c(2,1))plot(1:10,cex=2,pch=17,xaxt="n",xlab="",main="0.5")......
  • 有限自动状态机(Finite State Machine)
    有限状态自动机是拥有有限数量的状态,并且每个状态可以变换其他状态的数学模型。Afinite-statemachine(FSM)orfinite-stateautomaton(FSA,plural:automata),fin......
  • C语言:初识指针
    1.内存认识指针,首先要认识内存内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的,所以为了有效的使用内存,就把内存分成一个个小的内存单元,每个内存单元的大......
  • 自定义数据类型:结构体(C语言进阶)
    结构体类型的声明结构体的自引用结构体内存对齐结构体传参自学b站“鹏哥C语言”笔记。一、结构体类型的声明详见文章【初识结构体】第一部分。补充说明:匿名结构体类型:省略结......