嵌入式开发之有限状态机

总述

有限状态机是嵌入式开发中使用的常用方法,是针对一些连贯状态的控制响应。例如:按键按下灯亮,按键抬起灯灭

状态机结构设计

状态机是有许多的子状态构成,而子状态包括当前的状态、事件触发后的下一个状态、触发的事件以及触发后执行的动作,由此其数据结构可以如下:

typedef void (*func)(void *);
typedef struct fsm_table_t
{
​
   int cur_status;   //当前状态
   int next_status;  //触发后进入的下一状态
   int event;        //事件
   func eventfunc;   //执行动作
   
}fsm_table_t;

状态机需要维护一个整体的状态和包含子状态的列表,由此数据结构可以如下:

#define MAX_FSM_TABLE_SIZE  (10)
//系统状态结构
typedef struct fsm_t
{
   int system_status;   //当前系统状态
   int system_valid_item_len;    //有效子项个数
   fsm_table_t fsm_table[MAX_FSM_TABLE_SIZE];   //状态机子项链表
​
}fsm_t;

事件发生后,需要从状态机子项列表中查找符合条件的子状态,实现代码可如下:

int FsmEventHandler(fsm_t *fsm, int event,void *data)
{
 int i = 0; 
 for(i = 0; i < fsm->system_valid_item_len; i++)
  {
    //查找与当前系统状态一样并且触发事件也相同的子状态项   
    if(fsm->fsm_table[i].cur_status == fsm->system_status &&
         fsm->fsm_table[i].event == event)  
      {
               fsm->fsm_table[i].eventfunc(data);
               //系统状态改变
               fsm->system_status = 
               fsm->fsm_table[i].next_status;
               return 0;
      }
​
​
  }
}

添加子状态到整个状态的列表:

int AddItemToFsm(fsm_t *fsm, int cur_status, int next_status,
 int event, func eventfunc)
{ 
   //入参判断
  if(fsm->system_valid_item_len >= MAX_FSM_TABLE_SIZE
           || eventfunc == NULL)
       return - 1;
    //赋值
    fsm->fsm_table[fsm->system_valid_item_len].cur_status 
      = cur_status;
    fsm->fsm_table[fsm->system_valid_item_len].next_status
      = next_status;
    fsm->fsm_table[fsm->system_valid_item_len].event = event;
    fsm->fsm_table[fsm->system_valid_item_len].eventfunc
      = eventfunc;
    fsm->system_valid_item_len++;
    return 0 ;
 }

状态机模拟

上述基本实现了状态机的整体结构,接下来模拟一下状态机的运行效果,测试代码如下:

void func1(void *in)
{
 printf("event 1\r\n");
}
void func2(void *in)
{
 printf("event 2\r\n");
}
void func3(void *in)
{
 printf("event 3\r\n");
}
​
fsm_t test_fsm;
memset(&test_fsm, 0, sizeof(test_fsm));
test_fsm.system_status = 1;//初始化系统状态
AddItemToFsm(&test_fsm, 1, 2, 10, func1);
AddItemToFsm(&test_fsm, 2, 3, 11, func2);
AddItemToFsm(&test_fsm, 3, 1, 12, func3);
while(1)
{
   //触发事件10
   FsmEventHandler(&test_fsm, 10, NULL);
   //触发事件11
   FsmEventHandler(&test_fsm, 11, NULL);
   //触发事件12
   FsmEventHandler(&test_fsm, 12, NULL);   
}
​
//测试效果
event 1
event 2
event 3
...循环打印

总结

上述代码其实就是平常使用的switch case或者标志位的封装,只不过这样操作起来会更加简洁明了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值