状态机编程实例 (状态机编程实例及适用范围)

本文目录导航:

状态机编程实例-嵌套switch-case法

嵌入式软件开发领域,状态机编程是一种实用的代码实现方式,尤其适用于事件驱动的系统。

本文以一个炸弹拆除的小游戏为例,阐述了状态机编程的方法。

C/C++语言中实现状态机编程的方法有很多,本文将首先介绍最简单且易于理解的switch-case方法。

1 状态机实例介绍1.1 炸弹拆除游戏这是一个自制的炸弹拆除小游戏,包含3个按键和一个屏幕,用于显示倒计时时间和输入的拆除密码。

1.2 状态图使用状态机编程,首先要绘制对应的UML状态图。

在绘制之前,需要明确状态机的状态和事件。

对于本例中的炸弹拆除小游戏,可以归纳为两个状态。

对于事件,有3个按键事件和一个Tick节拍事件。

相关的结构定义如下。

为了便于维护状态机,可以将其定义为一个数据结构体,如下。

数据结构定义好之后,可以设计UML状态图。

这里使用visio画图。

分析这个状态图。

1.3 事件表示上述状态机事件可以分为两类:按键事件(UP、DOWN和ARM)和Tick。

对于第一类事件,需要单一的事件变量来区分;对于第二类Tick,由于引入了1/10s的精细时间,所以需要一个额外的事件参数来表示此次Tick事件的精细时间。

这里介绍一个编程技巧,通过结构体的继承关系实现对事件数据结构的设计,如下。

子图(a)表示TickEvt与Event是继承关系,这是UML类图的画法。

子图(b)是这两个结构体的定义。

子图(c)是TickEvt数据结构在内存中的存储示意。

这两个结构体的定义如下。

这样定义的好处是,对于状态机事件调度函数Bomb1_dispatch的参数形式,可以统一使用(Event *)类型,将TickEvt类型传入时,可以取其地址,再转为(Event *)类型。

2 switch-case嵌套法状态图设计好之后,就可以对照着状态图进行编程实现了。

本文先使用最简单最容易理解的switch-case方法来实现状态机编程。

2.1 状态机处理使用switch-case法实现状态机,一般需要两层switch结构。

2.1.1 第一层switch处理状态2.1.2 第二层switch处理事件这里以状态机处于“设置状态”时,对事件(信号)的处理为例。

2.1.3 两层switch-case状态机完整代码2.2 主函数两层switch-case状态机逻辑编写好之后,还需要将状态机运行起来。

运行状态机的本质,就是周期性地调用状态机(上面实现的两层switch-case),当有事件触发时,设置对应的事件,状态机在运行时,即可处理对应的事件,从而实现状态的切换,或是其它的逻辑处理。

2.2.1 状态机的运行状态机运行的整体逻辑如下。

2.2.2 事件的触发在状态机的每个状态循环执行前,都检测一下是否有事件触发,本例中就是UP、DOWN和ARM的按键事件,另外Tick事件是周期性触发的。

UP、DOWN和ARM的按键事件的触发检测代码如下,检测到对应的按键事件后,则设置对应的事件给状态机,状态机即可在下次状态循环中进行处理。

3 测试本例程使用Arduino作为控制器进行测试,外接3个独立按键和一个IIC接口的OLED显示屏。

4 总结本文以一个炸弹拆除的小游戏为例,介绍了嵌入式软件开发中,状态机编程的思路。

另外,本文中,还需要体会的是,对事件的表示,通过结构体继承(嵌套)的方式,实现一个额外的事件参数这种用法。

状态机编程实例 (状态机编程实例及适用范围)

有限元状态机的三种C语言实现方式

正文状态机实现的核心要素为状态、事件与响应,简化为三句话描述。

在C语言中,主要存在三种实现方式:switch-case法、表格驱动法和函数指针法。

在条件判断法中,使用switch-case结构组织状态与事件,实现状态之间的转换。

实际应用中,事件的多样性导致许多状态对特定事件无意义,因此在相应状态的case中无需编写与该事件相关的代码。

选择状态嵌套事件或事件嵌套状态取决于具体情况,每种方法都有其优缺点。

表格驱动法将状态与事件的关系固化为二维表格,通过事件和状态定位响应动作和状态迁移。

此方法中,状态机节点存储输出动作、状态迁移信息,以及指向动作封装函数的函数指针。

通过此函数指针调用封装函数,实现事件响应。

若事件对状态无意义,则状态机节点的函数指针指向空函数。

表格驱动法的优势在于统一接口和快速定位,但代码格式可能导致可读性问题和添加状态的不便。

压缩表格驱动法是表格驱动法的一种简化,使用一维数组作为驱动表格,通过状态作为数组下标定位动作封装函数,解决了状态机迁移状态的不确定性。

此方法中,动作封装函数不再指定状态迁移,而是返回迁移状态。

通过检查当前状态与函数指针指向的状态一致来确保程序安全运行。

函数指针法将动作封装函数的函数地址视为状态,通过全局函数指针变量存储状态,实现事件响应。

与压缩表格驱动法类似,但状态机的安全运行更为复杂,需谨慎处理全局函数指针的合法性问题。

总结而言,状态机提供了强大的工具,用于解决复杂问题。

有限状态机提供了简洁的实现方式,层次状态机则在有限状态机的基础上引入了更高级的结构,增强了功能。

理解状态机的理论知识是基础,更重要的是如何将其应用于实际问题,形成状态转换图,并优化实现。

通过状态转换图编程,实现问题的自动化解决。

为了帮助大家获取IT学习资源,我整理了一系列视频、电子书、PPT等优质资料,免费共享给大家。

无需任何套路,直接领取即可。

欢迎关注我,获取更多资源。

如果本文对你有帮助,欢迎点赞、收藏和转发给朋友,鼓励我持续创作。

状态机编程实例-面向对象的状态设计模式

面向对象的状态设计模式的核心思想在于通过不同的类表示不同的状态,状态机从一个状态转换到另一个状态时,表现为在运行时改变自己的类。

此模式引入了一个炸弹状态的抽象基类BombState,用于派生具体的工作状态类,例如设置状态(SettingState)和倒计时状态(TimingState)。

在模式下,BombState类为炸弹的两个工作状态声明了一些公共的接口:onUP、onDOWN、onARM和onTICK。

具体的工作状态类通过定义自己的onUP等操作,实现各自状态类需要处理的功能。

为了实现状态的维护,模式设计了一个上下文类Bomb3,它通过一个抽象类BombState的指针来实现。

上下文(context)可以理解为环境或语境,每一段程序都有很多的外部变量,要想让程序独立运行,必须把所有外部变量的值传进去,这些值的集合就是上下文。

在本例中,BombState的运行需要一个上下文类作为其参数,这个参数就是Bomb3类。

上下文类Bomb3中还包含需要用到的扩展状态变量,并通过提供对BombState一样的接口,即每派生一个事件对应一个操作。

上下文类中的事件处理是通过state_指针实现的,它代表了对当前状态对象的全部特定请求,状态的改变对应于当前工作状态类对象的改变,通过上下文操作tran()实现状态转换。

在C++语言中实现面向对象的状态设计模式,需要定义几个关键类:状态基类与派生类、炸弹业务类(上下文类)、以及主函数。

状态基类定义了通用接口,派生类则具体实现了不同的状态行为。

炸弹业务类提供通用的事件处理接口,其内部根据具体状态调用对应状态类的事件处理函数。

主函数简洁,主要调用通用的事件处理接口,实现状态转换和业务逻辑。

总结,面向对象的状态设计模式利用C++的继承特性及类指针,为状态机编程提供了一种高效、灵活的实现方式,简化了状态转换的管理,并通过上下文类实现了状态的动态维护。

通过本篇内容,重点理解了如何通过类的设计实现状态机的动态改变,以及上下文类在状态机中的作用。

你可能想看:
« 上一篇
下一篇 »

相关推荐

FreeBasic:强大免费开源的64位basic编译器及应用优势

2025年05月10日

84阅读

脊柱侧弯矫正方法大盘点:运动康复、支具矫正等多种方式

2025年05月09日

88阅读

如何在winForm标题栏去掉标题文字且任务栏图标正常显示

2025年05月09日

88阅读

十一黄金周促销广告词大全,国庆购物狂欢等你来

2025年05月09日

79阅读

关闭快速编辑模式及插入模式,设置控制台指定文字颜色举例

2025年05月09日

65阅读

黄金搭档低糖高钙饮品包装及成分功效全解析,适合人群要知晓

2025年05月09日

92阅读