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);
}

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

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

C语言状态机模块实现相关推荐

  1. 以下描述中不属于python语言控制结构的是_高中信息技术《Python语言》模块试卷...

    高中信息技术<Python语言>模块试卷 本试卷分为五大题,37小题,共100分,考试用时60分钟. 一.单选题(本题共15小题,每小题2分,共30分) 是一门( ) (A)自然语言(B) ...

  2. c语言状态机实现坐标切换,C语言状态机最优模式(转)

    近来思绪有点停不下来,构思了一个GUI的框架(用在Cotex-M平台上,很小),期待以后有时间去实现,里面有一个对触摸屏的检测,自然想到使用状态机进行消息的生成和分发,于是想着实现一个状态机实现的模型 ...

  3. 你是真的“C”——详解C语言函数模块知识(上篇)

    详解C语言函数模块知识(上篇)

  4. 高中信息技术html语言,高中信息技术《Python语言》模块试卷

    12. a的7倍减3的结果,对b(b不等于0)取余,正确的表达式是( ) (A)(7a-3)/b (B)7*a-3%b (C)(7a-3)%b (D)(7*a-3)%b 13.下列可以将变量x和y的值 ...

  5. 高中信息技术python及答案_高中信息技术《Python语言》模块试卷.docx

    高中信息技术<Python语言>模块试卷.docx PAGE 区县____________ 姓名_____________ 区县____________ 姓名_____________ 座 ...

  6. 高中信息技术python及答案_高中信息技术《Python语言》模块试卷.doc

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 线 _ - - _ - _ - _ - - _ - _ - _ - _ - - ...

  7. 高中信息技术python及答案_高中信息技术《Python语言》模块试卷

    高中信息技术< Python 语言>模块试卷 本试卷分为五大题, 37 小题 ,共 100 分,考试用时 60 分钟. 一.单选题(本题共 15 小题,每小题 2 分,共 30 分) 是一 ...

  8. 易语言取java路径模块_易语言API模块制作进程取程序路径

    易语言API模块制作进程取程序路径,提高进程的PID获取程序的所在路径. 进程_取程序路径 1.CreateToolhelp32Snapshot 快照句柄 = CreateToolhelp32Snap ...

  9. c语言按键状态机,C语言状态机编程思想

    原标题:C语言状态机编程思想 有限状态机概念 有限状态机是一种概念思想,把复杂的控制逻辑分解成有限个稳定状态,组成闭环系统,通过事件触发,让状态机按设定的顺序处理事务.单片机C语言的状态机编程,是利用 ...

  10. uniapp小程序实现长按录音、上滑取消的与语言录入模块(CSS实现语音音阶动画效果)

    这里写目录标题 语言录入模块 实现效果 HTML部分 JS部分 CSS部分 总结 语言录入模块 实现效果 HTML部分 代码如下: <template><view :class=&q ...

最新文章

  1. 马尔科夫决策过程基本概念详解
  2. /usr/lib/sudo/sudoers.so must be only be writable by owner
  3. Liunx静态库和动态库
  4. leetcode 1154 一年中的第几天
  5. 项目启动时 xml报错:Could not find SQL statement to include with refid 'mbgl.panDuanZbsfkxg'
  6. ubuntu 添加证书
  7. Quartz定时任务不定时执行
  8. C A+B for Input-Output Practice (II) SDUT
  9. 旷视发布招股书,一起看看CV四小龙中的三小龙那些有意思的事情
  10. android点击图片进入幻灯片,Android实现幻灯片式图片浏览器
  11. Windows2016 L2TP配置(证书模式)
  12. 【防火墙流控配置 基于主机的带宽控制】
  13. 跨平台调用之一——java调用so库
  14. Android音乐播放器的比较。
  15. EDM邮件营销的七个基本原则
  16. java需要用到英语_javaSE常用的英语单词
  17. Android画三角形
  18. 聊聊短信接口攻击的防范方案
  19. ulong在C语言中的头文件,ULONG没有定义的 有关问题
  20. 在C语言中使用二分法算法思想解决猜商品价格问题

热门文章

  1. 重新回归最初始的51单片机,跟我一起学单片机吧(内含单片机驱动、烧录软件、程序开发软件的安装和使用)
  2. 微信小程序图片上传一直loading中,上传没反应
  3. 第二十五篇:稳定性之灰度发布
  4. php微信公众号退款,微信公众号支付--4--微信退款
  5. VMware 15.5.0安装教程
  6. html 多选框获取值数组,前端获取checkbox复选框的值 通过数组形式传递
  7. 用户权限管理模块的数据库设计
  8. 170923_Spring Cloud 微服务实战(翟永超著) 读书笔记(一)_什么是Spring Cloud?
  9. 小程序开发——比较好看的登录界面设计
  10. abb机器人searchl报错_ABB机器人常用指令介绍——ABB机器人