基于C语言的状态机框架和实现

Posted 吴跃前

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于C语言的状态机框架和实现相关的知识,希望对你有一定的参考价值。

       本文的目的是基于C语言实现简单高效的状态机。例子是倒计时bomb。Bomb有两种状态,一种是设置状态,一种是倒计时。一旦开始计时,要想回到设置状态必须要调整code的值等于bomb预设的密码值,否则无法进行状态转换。倒计时到0就BOMB了啦。基于这个例子来实现状态机。状态机实现框架包括以下几个部分:

1.      状态

enum BombStates  

   SETTING_STATE,//设置

   TIMING_STATE//倒计时

;

2. 触发状态转换的信号事件,用键盘模拟

enum BombSignals

   UP_SIG, //按u

   DOWN_SIG,//按d

   ARM_SIG,//按a,状态转换键

   TICK_SIG//0.1秒发出一个倒计时事件

;

3.      信号事件的数据结构

typedef struct EventTag

   uint16_t sig;   // BombSignals的赋值

   /* 可以添加其他属性到这里 */

Event; 

此外,还要定义信号事件附带的参数:

typedef struct TickEvtTag

   Event super;   //继承Event

   uint8_t fine_time;  //毫秒值,为0时代表倒计1秒

TickEvt;

4.      状态全局变量

typedef struct Bomb1Tag   

   uint8_t state;  // BombStates状态赋值

   uint8_t timeout;  //当前倒计时间,为0游戏结束

   uint8_t code; //用于调整数值,等于defuse密码才能转换状态

   uint8_t defuse; //解除bomb的密码,需要预设

Bomb1;

5.      状态初始化

#define INIT_TIMEOUT   10

#define TRAN(target_)  (me->state = (uint8_t)(target_))

 

void Bomb1_ctor(Bomb1 *me, uint8_t defuse)

   me->defuse = defuse;

void Bomb1_init(Bomb1 *me)

   me->timeout = INIT_TIMEOUT;

   TRAN(SETTING_STATE);

6.      状态转换

void Bomb1_dispatch(Bomb1 *me, Event const*e)

   switch (me->state)

       case SETTING_STATE:

           switch (e->sig)

                case UP_SIG:

                    if (me->timeout < 60)

                       ++me->timeout;

                       BSP_display(me->timeout);

                   

                    break;

               

                case DOWN_SIG:

                    if (me->timeout > 1)

                        --me->timeout;

                       BSP_display(me->timeout);

                   

                    break;

               

                case ARM_SIG:

                    me->code = 0;

                    TRAN(TIMING_STATE);           /* transition to "timing"*/

                    break;

               

           

           break;

       

       case TIMING_STATE:

           switch (e->sig)

                case UP_SIG:

                    me->code <<= 1;

                    me->code |= 1;

                   BSP_display(me->code);

                    break;

               

                case DOWN_SIG:

                    me->code <<= 1;

                   BSP_display(me->code);

                    break;

               

                case ARM_SIG:

                    if (me->code ==me->defuse)

                       TRAN(SETTING_STATE);     /*transition to "setting" */

                   

                    break;

               

                case TICK_SIG:

                    if (((TickEvt const*)e)->fine_time == 0)

                        --me->timeout;

                       BSP_display(me->timeout);

                        if (me->timeout ==0)

                            BSP_boom();                 /* destroy the bomb */

                        

                   

                    break;

               

           

           break;

       

   

7.      测试代码,用VC6.0

#include <stdio.h>

#include <stdlib.h>

#include <conio.h>

#include <dos.h>

#include<windows.h>

 

static Bomb1 l_bomb;  /* time bomb FSM*/

void main()  

   Bomb1_ctor(&l_bomb, 0x0D);      /* the secret defuse code, 1101 binary */ 

   printf("Time Bomb (Nested switch)\\n"

          "Press 'u'   for UP   event\\n"

          "Press 'd'   for DOWNevent\\n"

           "Press 'a'   for ARM event\\n"

          "Press <Esc> to quit.\\n");

 

   Bomb1_init(&l_bomb);                     /* take the initialtransition */

 

   for (;;)                                                /* event loop */

       static TickEvt tick_evt = TICK_SIG, 0; 

       Sleep(100);                                         /* 100ms delay */ 

       if (++tick_evt.fine_time == 10)

           tick_evt.fine_time = 0;

       

       printf("T(%1d)%c", tick_evt.fine_time,

                            (tick_evt.fine_time == 0)? '\\n' : ' '); 

       Bomb1_dispatch(&l_bomb, (Event *)&tick_evt); /* dispatch tickevent */ 

       if (kbhit())

           static Event const up_evt   = UP_SIG   ;

           static Event const down_evt = DOWN_SIG ;

           static Event const arm_evt  = ARM_SIG  ;

           Event const *e = (Event *)0; 

           switch (getch())

                case 'u':                                      /* UP event*/

                    printf("\\nUP  : ");

                    e = &up_evt;                   /* generate the UP event */

                    break;

               

                case 'd':                                    /* DOWNevent */

                    printf("\\nDOWN: ");

                    e = &down_evt;               /* generate the DOWN event */

                    break;

               

                case 'a':                                     /* ARMevent */

                    printf("\\nARM : ");

                    e = &arm_evt;                 /* generate the ARM event */

                    break;

               

                case '\\33':                                   /*<Esc> key */

                    printf("\\nESC : Bye!Bye!");

                    exit(0);

                    break;

               

           

           if (e != (Event *)0)             /* keyboard event available? */

                Bomb1_dispatch(&l_bomb,e);           /* dispatch the event */

           

       

   

更多的嵌入式linux和android、物联网、汽车自动驾驶等领域原创技术分享请关注微信公众号:

以上是关于基于C语言的状态机框架和实现的主要内容,如果未能解决你的问题,请参考以下文章

Yarn状态机框架分析

电梯控制系统基于VHDL语言和状态机实现的电梯控制系统的设计,使用了状态机

构建Lua和JS环境虚拟机1

什么是状态机?用C语言实现进程5状态模型

状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02

状态机编程思维学习笔记(C语言)