资讯详情

C语言--状态机模块实现

1. 实现状态机模块

状态机编程理念可以使复杂的逻辑代码更加简单,逻辑理念更加清晰和严谨。根据另一篇博客介绍的状态机思想,用C语言实现状态机可重复使用的模块化代码。

状态机 fsm.h 头文件代码如下:

#ifndef _FSM_H_ #define _FSM_H_   #include <stdint.h> #include <stddef.h>   typedef struct FsmTable_s {     uint8_t event;                /* 触发事件 */     uint8_t CurState;             /* 当前状态 */     void (*eventActFun)(void *);  /* 动作函数 */     uint8_t NextState;            /* 跳转状态 */ }FsmTable_T;   typedef struct FSM_s {     FsmTable_T *FsmTable;         /* 状态迁移表 */     uint8_t curState;             /* 状态机的现状 */     uint8_t stuMaxNum;            /* 状态机状态迁移数量 */ }FSM_T;   /********************************************************************************* 使用方法:1.创建FSM_T对象;           2.创建FsmTable_T表;           3.调用FSM_Init()初始化;           4.程序轮询FSM_EventHandle()运行状态机。 *********************************************************************************/ void FSM_Init(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState); void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm);   #endif

状态机 fsm.c 源文件代码如下:

#include "fsm.h"   /*================================================================== * Function  : FSM_StateTransfer * Description : 状态转换 * Input Para  :  * Output Para :  * Return Value:  ==================================================================*/ static void FSM_StateTransfer(FSM_T *pFsm, uint8_t state) {     pFsm->curState = state; }   /*================================================================== * Function  : FSM_EventHandle * Description : 状态机处理函数 * Input Para  : pFsm状态机对象, event触发事件, parm动作执行参数 * Output Para :  * Return Value:  ==================================================================*/ void FSM_EventHandle(FSM_T *pFsm, uint8_t event, void *parm) {     FsmTable_T *pAcTable = pFsm->FsmTable;     void (*eventActFun)(void *) = NULL;     uint8_t NextState;     uint8_t CurState = pFsm->curState;     uint8_t flag = 0;            for (uint8_t i = 0; i < pFsm->stuMaxNum; i  )// 遍历状态表     {         if (event == pAcTable[i].event && CurState == pAcTable[i].CurState)         {             flag = 1;             eventActFun = pAcTable[i].eventActFun;             NextState = pAcTable[i].NextState;             break;         }     }     if (flag)     {         if (eventActFun != NULL)         {             eventActFun(parm);  // 执行相应的行动         }         FSM_StateTransfer(pFsm, NextState); // 状态转换     }     else     {         // do nothing     } }   /*================================================================== * Function  : FSM_Init * Description : 状态机的初始化 * Input Para  : pFsm状态机对象,pTable状态迁移表,stuMaxNum迁移表数量 *               curState当前状态 * Output Para :  * Return Value:  ==================================================================*/ void FSM_Init(FSM_T *pFsm, FsmTable_T *pTable, uint8_t stuMaxNum, uint8_t curState) {     pFsm->FsmTable = pTable;     pFsm->curState = curState;     pFsm->stuMaxNum = stuMaxNum; }

2. 使用状态机模块

结合消息队列的编程理念,使用状态机的实例代码如下:

/** @enum FSM_STATE_E  *  @brief 状态机运行状态  *    */ typedef enum {     RUNNING = 0x00, // 运行态     FAULT,          // 故障态 }FSM_STATE_E;   /** @enum TRIG_EVENT_E  *  @brief 状态机触发事件  *    */ typedef enum {            SENSOR_FAULT,       // 传感器故障事件     SENSOR_RESUME,      // 传感器故障恢复事件 }TRIG_EVENT_E, *PTRIG_EVENT_E;     /** @struct MSG_EVENT_TRIG_T  *  @brief 事件触发消息结构  *    */ typedef struct {     uint8_t eDevPort;       /* 事件触发传感器端口 */     TRIG_EVENT_E eEventType;        /* 事件触发类型 */      }MSG_EVENT_TRIG_T, *PMSG_EVENT_TRIG_T;   /** @struct DEV_DET_T  *  @brief  探测器  *    */ typedef struct {     SQ_QUEUE stEventQue;                /* 事件触发队列 */     MSG_EVENT_TRIG_T eEventQueBuf[8];  /* 事件触发缓存 */      }DEV_DET_T, *PDEV_DET_T;     /* 创建监控探测器实例 */ static DEV_DET_T g_stDetIns;     /* 状态机变量 */ static FSM_T g_stFsm;   /* 动作函数 */ static void ActFun_FaultEvent(void *parm); static void ActFun_FaultResumeEvent(void *parm);   /* 状态迁移表 */ static FsmTable_T g_stFsmTable[] =  {     /* 触发事件         初态            动作函数             次态  */   {SENSOR_FAULT,      RUNNING,     ActFun_FaultEvent,             FAULT},  {SENSOR_RESUME,     FAULT,       ActFun_FaultResumeEvent,       RUNNING}, };   /* 计算状态迁移表的长度 */ #define FSM_TABLE_MAX_NUM (sizeof(g_stFsmTable)/sizeof(FsmTable_T))     /*================================================================== * Function  : APP_Init * Description : 创建消息队列,初始化状态机 * Input Para  :  * Output Para :  * Return Value:  ==================================================================*/ void APP_Init(void) {        /* 触发事件触发队列 */    if (!Que_InitQueue(&g_stDetIns.stEventQue,\
        sizeof(g_stDetIns.eEventQueBuf)/sizeof(g_stDetIns.eEventQueBuf[0]),\
        sizeof(g_stDetIns.eEventQueBuf[0]), 1, (uint8_t *)g_stDetIns.eEventQueBuf))
    {
        USER_DEBUG(PRINT_SER, "ELEC: electrical fire detector tigger event queue create fail!\r\n");
    }
 
    /* 初始化状态机 */
    FSM_Init(&g_stFsm, g_stFsmTable, FSM_TABLE_MAX_NUM, RUNNING);
    
}
 
/*==================================================================
* Function  : ActFun_FaultEvent
* Description : 触发故障事件动作函数
* Input Para  : LocalActiveStatus
* Output Para : 
* Return Value: 
==================================================================*/
static void ActFun_FaultEvent(void *parm)
{
	/* 执行故障相关的动作 */	
}
 
/*==================================================================
* Function  : ActFun_FaultResumeEvent
* Description : 故障恢复事件动作函数
* Input Para  : 
* Output Para : 
* Return Value: 
==================================================================*/
static void ActFun_FaultResumeEvent(void *parm)
{
	/* 执行故障恢复相关的动作 */
}
 
/*==================================================================
* Function  : FsmEventHandleTask
* Description : 在定时器中定时轮询,避免动作函数中含有长任务函数
* Input Para  : 
* Output Para : 
* Return Value: 
==================================================================*/
void FsmEventHandleTask(void)
{       
    uint8_t* p_EventBuf = NULL;
    PMSG_EVENT_TRIG_T p_TrigMsg = NULL;
    
    /* 取出触发事件队列中的事件 */
    if (Que_DeQueue(&g_stDetIns.stEventQue, &p_EventBuf))
    {   
        p_TrigMsg = (PMSG_EVENT_TRIG_T)p_EventBuf;
        
        /* 在其它模块中改变触发事件,即可完成相应动作的执行 */
        FSM_EventHandle(&g_stElecFsm, p_TrigMsg->eEventType, (void *)&p_TrigMsg->eDevPort);
    }    
}
 
/*==================================================================
* Function  : Elec_UpdateEvent
* Description : 更新触发事件
* Input Para  : 
* Output Para : 
* Return Value: 
==================================================================*/
void Elec_UpdateEvent(MSG_EVENT_TRIG_T stTrigEventMsg)
{    
    /* 触发事件入队 */
    if (!Que_EnQueue(&g_stDetIns.stEventQue, (uint8_t*)&stTrigEventMsg, sizeof(g_stDetIns.eEventQueBuf[0])))
    {
        USER_DEBUG(PRINT_SYS, "ELEC: electrical fire detector tigger event entry queue fail!\r\n");
    }
}
 
/*==================================================================
* Function  : TestEvent
* Description : 测试事件函数
* Input Para  : 
* Output Para : 
* Return Value: 
==================================================================*/
void TestEvent(void)
{
	MSG_EVENT_TRIG_T stTrigEventMsg;
	
	/* 触发故障事件 */
	stTrigEventMsg.eEventType = SENSOR_FAULT; 
	Elec_UpdateEvent(stTrigEventMsg);
}

 

标签: zwb传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台