状态机的三种实现方法 嵌软开发思维 (状态机的三种编码方式)
本文目录导航:
嵌软开发思维:状态机的三种实现方法
深入探讨了C语言实现状态机的三种方法:switch-case法、表格驱动法、函数指针法。
每个方法都围绕着状态、事件与响应进行解析。
switch-case法通过嵌套switch-case结构实现状态与事件的交互,状态和事件分别使用switch进行组织,将频繁发生的事件代码集中于某个状态的case中,以提升效率。
此法有状态嵌套事件和事件嵌套状态两种实现方式,选择哪一种取决于具体的应用场景。
优化建议是在实现时将高频率或实时性要求高的状态和事件位置尽量前置。
表格驱动法利用二维数组将状态与事件的对应关系进行固化,事件作为纵轴,状态作为横轴,每个交点表示对应状态对特定事件的响应。
状态机节点为结构体,包含指向动作封装函数的函数指针和状态迁移的下标。
此方法优点是调用接口统一、定位快速,易于管理和扩展。
但是,代码可读性差,添加新状态或事件时操作复杂。
表格驱动法不支持Extended State Machine,即状态机在响应事件前先判断条件,选择执行的动作和状态。
针对Extended State Machine的限制,提出了压缩表格驱动法,即一维状态表格与事件switch-case的结合。
此方法用一维数组作为驱动表格,每个节点包含函数指针和状态迁移的下标,动作封装函数负责返回新的状态。
这种实现方式解决了Extended State Machine不能在表格驱动法中使用的问题,同时保留了表格驱动法的简洁高效和switch-case法的直白灵活。
函数指针法本质上是将动作封装函数的函数地址视为状态,与压缩表格驱动法实现了相似的功能。
文章最后总结,状态机是强大的编程工具,能够高效地处理有限状态的转换。
除了有限状态机,层次状态机提供更复杂、更强大的功能,适用于解决更复杂的问题。
状态机编程的关键在于理解状态转换图,以及如何将实际问题抽象为状态转换图。
一旦形成状态转换图,大部分问题就已经解决了一大半。
状态机编程的最后步骤是根据状态图编写代码,实现具体功能。
嵌入式物联网领域需要掌握的知识点众多,包括状态机在内的各种技术都需要深入学习。
分享了一个大约150多G的学习资料包,其中包含最新的学习内容、面试经验、以及丰富的项目案例,以帮助开发者提升技能和知识。

状态机编程实例-嵌套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等优质资料,免费共享给大家。
无需任何套路,直接领取即可。
欢迎关注我,获取更多资源。
如果本文对你有帮助,欢迎点赞、收藏和转发给朋友,鼓励我持续创作。