[APM32F4] 状态机简介及编程-1

[复制链接]
4734|0
 楼主| lzh12a3nf 发表于 2024-2-28 21:48 | 显示全部楼层 |阅读模式
本帖最后由 lzh12a3nf 于 2024-2-28 22:23 编辑

#申请原创#@21小跑堂
1、前言

最近在学习过程中运用到了状态机的思维,此文将对状态机的概念及使用进行学习记录。欢迎大家一起学习,有问题评论区一起讨论。

2、状态机
  • 概念:状态机,又称为有限状态机(Finite State Machine,FSM),是一种用于设计和实现程序和系统行为的模型。
  • 涉及六个元素:起始状态、结束状态、现状态、目标状态、动作、条件。
  • 涉及实现流程:
      a.定义状态和事件:首先,需要定义系统可能处于的所有状态,以及可能触发状态转换的事件。
      b.创建状态转换逻辑:确定每个状态下,对于不同事件应该如何响应,包括状态转换和执行的动作。
      c.实现状态机逻辑:编写代码来实现状态转换和动作执行。这通常涉及到编写一个主循环(main loop),在其中不断检查事件并更新状态。
      d.将实现的状态机代码集成到MCU平台(APM32系列)中。其中,可涉及:按键、定时器、中断、输入输出等
      e.调试和测试:状态机设计完成后,搭载上APM32的平台上,需进行硬件的调试和测试,确保状态机的转换能正常工作。

  • 状态机实现的基本逻辑图:
      这是一个简单的状态机,含有两个状态:①开门,人进入,关门。②关门,刷卡,开门。
状态机流程图2.drawio.png


  • MCU(APM32)的状态机
       举个简单的例子:就按键处理来说,按键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、按下、抖动和重新释放等状态
  • 状态机语句框架
       在日常编码中,状态机的思想经常使用,如下:
       a.if....else....语句状态机
  1. if 状态1
  2. else if 状态2
  3. else if 状态3
  4. ...
  5. else 状态n
      优点:
             1、该语句结构能够处理更复杂的条件判断,不仅仅限于常量或枚举的比较,还可以包含范围判断、复合条件等。
             2、逻辑简单易懂
      缺点:
              1、当状态或条件较多时,效率下降,需逐一评估条件直到找到匹配项。
              2、随着条件的增加,逻辑容易变得非常复杂。

       b.switch....case....语句状态机
  1.  switch(state)
      优点:
             1、对基于枚举或整数的状态机,效率更高。
             2、清晰的分支结构,使得各个状态和转换逻辑更加明确。
             3、添加或删除状态时,代码修改更集中,不易混乱。
      缺点:
             1、仅适用于有限的数据类型(如整数、枚举等),且不能直接使用范围或复合条件。



3、状态机设计
下面,我将基于上个章节的状态机拓展,进行逻辑代码框图设计及代码实现。
3.1、状态机实现逻辑图

状态机流程图.drawio.png

3.2、参数说明:

存在状态:
  • 开门,人进入,关门。
  • 开门,刷卡,提示门已开。
  • 关门,刷卡,开门。
  • 关门,强制进入,警告需刷卡。
状态设置:

  • 使用自定义枚举DoorState、DoorEvent将状态列举出来。
状态转换:使用handleEvent回调函数,函数内设计switch....case....语句进行状态转换。


3.3、状态机逻辑代码实现

  1. #include <stdio.h>
  2. #include <stdbool.h>

  3. // 定义电闸门状态
  4. typedef enum {
  5.     DOOR_CLOSED,
  6.     DOOR_OPEN
  7. } DoorState;

  8. // 电闸门事件
  9. typedef enum {
  10.     CARD_SWIPED,
  11.     PERSON_PASSED,
  12.     NO_ACTION
  13. } DoorEvent;

  14. // 状态机处理函数原型
  15. void handleEvent(DoorState* state, DoorEvent event);

  16. // 主程序入口
  17. int main() {
  18.     DoorState state = DOOR_CLOSED; // 初始状态设置为门关闭
  19.     DoorEvent event;

  20.     // 模仿事件触发
  21.     // 情景1: 刷卡时门关闭
  22.     event = CARD_SWIPED;
  23.     handleEvent(&state, event);

  24.     // 情景2: 关闭状态下未刷卡(触发警报)
  25.     event = NO_ACTION;
  26.     handleEvent(&state, event);

  27.     // 情景3: 开门状态下人通过
  28.     event = PERSON_PASSED;
  29.     handleEvent(&state, event);

  30.     // 情景4: 开门状态下再次刷卡
  31.     event = CARD_SWIPED;
  32.     handleEvent(&state, event);

  33.     return 0;
  34. }

  35. void handleEvent(DoorState* state, DoorEvent event) {
  36.     switch (*state) {
  37.         case DOOR_CLOSED:
  38.             if (event == CARD_SWIPED) {
  39.                 *state = DOOR_OPEN; // 改变状态为门打开
  40.                 printf("门现在打开。\n");
  41.             }
  42.             else if (event == NO_ACTION) {
  43.                 printf("警告!请刷卡!\n"); // 保持状态,只是给出警告
  44.             }
  45.             break;
  46.         case DOOR_OPEN:
  47.             if (event == PERSON_PASSED) {
  48.                 *state = DOOR_CLOSED; // 改变状态为门关闭
  49.                 printf("人已进入,门现在关闭。\n");
  50.             }
  51.             else if (event == CARD_SWIPED) {
  52.                 printf("门已经打开。\n"); // 保持门开状态
  53.             }
  54.             break;
  55.         default:
  56.             printf("未知状态.\n");
  57.             break;
  58.     }
  59. }

注:

  • 本次文章内容分享到此,下一章节将基于APM32系列开发板,实现状态机转换代码。
  • 如有问题,大家评论区一起讨论,谢谢。








您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

37

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部