首页 > 编程知识 正文

c# 状态机设计,状态机编程思想

时间:2023-05-06 19:53:37 阅读:253024 作者:3686

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!rn"); } /* 初始化状态机 */ 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!rn"); }}/*==================================================================* Function : TestEvent* Description : 测试事件函数* Input Para : * Output Para : * Return Value: ==================================================================*/void TestEvent(void){MSG_EVENT_TRIG_T stTrigEventMsg;/* 触发故障事件 */stTrigEventMsg.eEventType = SENSOR_FAULT; Elec_UpdateEvent(stTrigEventMsg);}

 另外还有实际项目开发中,如何使用状态机设计软件架构的案例:

状态机设计模式:电动车报警器项目实战_智小星的博客-CSDN博客

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。