[C]精炼分析状态机FSM

FSM:finite state machine  【有限状态机】,用通俗的语言来表达就是逻辑流程图。

当前状态满足触发条件时,就会切换到下一个状态,并执行对应的任务操作。传统代码做法是用if-else 或者 switch-case来处理。若要做到可扩展性良好的话,就需用状态表来设计。

用一句代码表达状态机原理:

if( state==CurrState && Event==True )
{
   state = NextState;
   Action();
}

举个简单的例子:某个电子设备的模式运行切换逻辑如下:

当前状态(CurrState)

触发条件(Event)

下个状态(NextState)

执行动作(Action)

M_IDLE 

按钮1按下

MODE1

亮红灯,蜂鸣器响1

M_IDLE 

按钮2按下

MODE2

(无动作)

MODE1

运行10秒后

MODE3

亮绿灯,电机转速100

MODE2

运行5秒后和温度大于40

M_IDLE

亮蓝灯,电机转速300

MODE3

运行30

M_END

关灯,关电机

M_END

按钮1按下和按钮2按下

M_IDLE

蜂鸣器响2

C语言写的伪代码,传统方法:

#define M_IDLE 0
#define MODE1 1
#define MODE2 2
#define MODE3 3
#define M_END 4
int state_mode = M_IDLE;
int run_cnt = 0;
int cur_temp = 0;
int btn1 = 0;
int btn2 = 0;

void main()
{
    while (1)
    {
        switch (state_mode)
        {
        case M_IDLE:
            if (btn1)
            {
                state_mode = MODE1;
                light_red();
                beep_cnt(1);
            }
            if (btn2)
            {
                state_mode = MODE2;
            }
            break;

        case MODE1:
            if (run_cnt >= 10)
            {
                state_mode = MODE3;
                light_green();
                motor_speed(100);
            }
            break;

        case MODE2:
            if (run_cnt >= 5 && cur_temp > 40)
            {
                state_mode = M_IDLE;
                light_blue();
                motor_speed(300);
            }
            break;

        case MODE3:
            if (run_cnt > 30)
            {
                state_mode = M_END;
                light_off();
                motor_off();
            }
            break;

        case M_END:
            if (btn1 && btn2)
            {
                state_mode = M_IDLE;
                beep_cnt(2);
            }
            break;
        }
    }
}

C语言写的伪代码,状态机表格方法:

#include

int run_cnt = 0;
int cur_temp = 0;
int btn1 = 0;
int btn2 = 0;

typedef enum
{
   M_IDLE,
   MODE1,
   MODE2,
   MODE3,
   M_END
}EnumState;

int state_mode = M_IDLE;

typedef struct
{
  EnumState curr_state;//当前状态
  int(*event_condition)();//触发事件条件
  EnumState next_state;//下一状态
  void(*action)();//执行动作
}FSM_Table;

//状态切换事件条件
int event_condition0()
{
  if(btn1==1)
    return 1;
  return 0;
}
//状态切换触发后并执行的操作
void action0()
{
  light_red();
  beep_cnt(1);
}

int event_condition0b()
{
  if(btn2==1)
    return 1;
  return 0;
}

void none_action()
{
 //没有动作
}

int event_condition1()
{
    return(run_cnt>=10);
}
void action1()
{
    light_green();
    motor_speed(100);
    printf("Runing action1\n");
}


int event_condition2()
{
   return(run_cnt>5 && cur_temp>40);

}
void action2()
{
    light_blue();
    motor_speed(300);
    printf("Runing action2\n");
}

int event_condition3()
{
   return(run_cnt>30);
}
void action3()
{
    light_off();
    motor_off();
}

int event_condition_end()
{
    return(btn1&&btn2);
}
void action_end()
{
    beep_cnt(2);
}


FSM_Table fsm_list[]=
{
   {M_IDLE,event_condition0,MODE1,action0},
   {M_IDLE,event_condition0b,MODE2,none_action},
   {MODE1,event_condition1,MODE3,action1},
   {MODE2,event_condition2,M_IDLE,action2},
   {MODE3,event_condition3,M_END,action3},
   {M_END,event_condition_end,M_IDLE,action_end},
};



void main()
{

   int table_size = sizeof(fsm_list)/sizeof(FSM_Table);
   printf("fsm_size=%d.\n",table_size);
    while(1)
    {
        for (size_t i = 0; i < table_size; i++)
        {
            if(state_mode==fsm_list[i].curr_state&&fsm_list[i].event_condition())
            {
                state_mode = fsm_list[i].next_state;
                fsm_list[i].action();
            }
        }
    }
}

经过这两种代码方法和思路的对比,可以看出,采用状态机数据结构表方案会十分的清晰贴合excel表上列举的功能思维,而且若后面扩展功能也十分的方便,只需要添加函数和关系表。

尤其当逻辑流程比较复杂多变时,用状态机表格的优势会比较突出。

[C]精炼分析状态机FSM_第1张图片

你可能感兴趣的:(c语言,开发语言)