本帖最后由 lzh12a3nf 于 2024-2-28 22:23 编辑
#申请原创#@21小跑堂
1、前言
最近在学习过程中运用到了状态机的思维,此文将对状态机的概念及使用进行学习记录。欢迎大家一起学习,有问题评论区一起讨论。
2、状态机
- 概念:状态机,又称为有限状态机(Finite State Machine,FSM),是一种用于设计和实现程序和系统行为的模型。
- 涉及六个元素:起始状态、结束状态、现状态、目标状态、动作、条件。
- 涉及实现流程:
a.定义状态和事件:首先,需要定义系统可能处于的所有状态,以及可能触发状态转换的事件。
b.创建状态转换逻辑:确定每个状态下,对于不同事件应该如何响应,包括状态转换和执行的动作。
c.实现状态机逻辑:编写代码来实现状态转换和动作执行。这通常涉及到编写一个主循环(main loop),在其中不断检查事件并更新状态。
d.将实现的状态机代码集成到MCU平台(APM32系列)中。其中,可涉及:按键、定时器、中断、输入输出等
e.调试和测试:状态机设计完成后,搭载上APM32的平台上,需进行硬件的调试和测试,确保状态机的转换能正常工作。
这是一个简单的状态机,含有两个状态:①开门,人进入,关门。②关门,刷卡,开门。
举个简单的例子:就按键处理来说,按键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、按下、抖动和重新释放等状态。
在日常编码中,状态机的思想经常使用,如下:
a.if....else....语句状态机
if 状态1
else if 状态2
else if 状态3
...
else 状态n
优点: 1、该语句结构能够处理更复杂的条件判断,不仅仅限于常量或枚举的比较,还可以包含范围判断、复合条件等。 2、逻辑简单易懂 缺点: 1、当状态或条件较多时,效率下降,需逐一评估条件直到找到匹配项。 2、随着条件的增加,逻辑容易变得非常复杂。
b.switch....case....语句状态机
优点: 1、对基于枚举或整数的状态机,效率更高。 2、清晰的分支结构,使得各个状态和转换逻辑更加明确。 3、添加或删除状态时,代码修改更集中,不易混乱。 缺点: 1、仅适用于有限的数据类型(如整数、枚举等),且不能直接使用范围或复合条件。
3、状态机设计
下面,我将基于上个章节的状态机拓展,进行逻辑代码框图设计及代码实现。
3.1、状态机实现逻辑图
3.2、参数说明:
存在状态:
- 开门,人进入,关门。
- 开门,刷卡,提示门已开。
- 关门,刷卡,开门。
- 关门,强制进入,警告需刷卡。
状态设置:
- 使用自定义枚举DoorState、DoorEvent将状态列举出来。
状态转换:使用handleEvent回调函数,函数内设计switch....case....语句进行状态转换。
3.3、状态机逻辑代码实现
#include <stdio.h>
#include <stdbool.h>
// 定义电闸门状态
typedef enum {
DOOR_CLOSED,
DOOR_OPEN
} DoorState;
// 电闸门事件
typedef enum {
CARD_SWIPED,
PERSON_PASSED,
NO_ACTION
} DoorEvent;
// 状态机处理函数原型
void handleEvent(DoorState* state, DoorEvent event);
// 主程序入口
int main() {
DoorState state = DOOR_CLOSED; // 初始状态设置为门关闭
DoorEvent event;
// 模仿事件触发
// 情景1: 刷卡时门关闭
event = CARD_SWIPED;
handleEvent(&state, event);
// 情景2: 关闭状态下未刷卡(触发警报)
event = NO_ACTION;
handleEvent(&state, event);
// 情景3: 开门状态下人通过
event = PERSON_PASSED;
handleEvent(&state, event);
// 情景4: 开门状态下再次刷卡
event = CARD_SWIPED;
handleEvent(&state, event);
return 0;
}
void handleEvent(DoorState* state, DoorEvent event) {
switch (*state) {
case DOOR_CLOSED:
if (event == CARD_SWIPED) {
*state = DOOR_OPEN; // 改变状态为门打开
printf("门现在打开。\n");
}
else if (event == NO_ACTION) {
printf("警告!请刷卡!\n"); // 保持状态,只是给出警告
}
break;
case DOOR_OPEN:
if (event == PERSON_PASSED) {
*state = DOOR_CLOSED; // 改变状态为门关闭
printf("人已进入,门现在关闭。\n");
}
else if (event == CARD_SWIPED) {
printf("门已经打开。\n"); // 保持门开状态
}
break;
default:
printf("未知状态.\n");
break;
}
}
注:
- 本次文章内容分享到此,下一章节将基于APM32系列开发板,实现状态机转换代码。
- 如有问题,大家评论区一起讨论,谢谢。
|