1. 状态机模块实现
状态机编程思想,能够使复杂的逻辑代码变得更加的简单,且逻辑思路更加清晰严谨。下面根据另一篇博文介绍的状态机思想,用C语言实现了状态机可复用的模块化代码。
状态机 fsm.h 头文件代码如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#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 源文件代码如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68#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. 状态机模块使用
使用状态机结合消息队列的编程思想,实例代码如下
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166/** @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博客
最后
以上就是大方柜子最近收集整理的关于C语言状态机模块实现1. 状态机模块实现2. 状态机模块使用的全部内容,更多相关C语言状态机模块实现1.内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复