saa*_*aad 4 state-machine switch-statement
我使用C的switch语句为嵌入式系统实现了一个简单的状态机.我知道如果我使用具有查找表的函数指针会更好,但我将其保存为下一步.
我的状态机具有以下状态:
当系统启动时,它进入启动状态,配置端口,初始化显示,并与SPI总线上连接的IC进行握手,以确保一切正常.如果是,则系统进入空闲状态.如果没有,它进入启动错误状态,在LCD上显示错误,标记变量然后进入空闲状态.
在空闲状态下,程序轮询微控制器上的3个引脚,检查是否按下3个按钮之一(检查,编程,复制到存储器).根据按下的按钮,它进入适当的状态,执行一些代码,更新LCD然后返回到空闲状态.注意:如果系统中出现硬件故障,系统不关心是否按下按钮.启动错误状态标记一个名为hardware_fault的变量,如果设置该变量,则确保空闲状态不会干扰轮询任何输入按钮.
这是我第一次实现状态机,我只是不确定这是不是一个好的设计.我还没有看到任何FSM的例子,他们在空闲状态下轮询输入.相反,似乎大多数例子本质上都是顺序的(例如计数器).所以,我的问题是,我的设计合理吗?它可以工作,但正如大家都知道的那样,设计不好,然后有好的设计.
您应该从switch语句重构代码并使用转换表,如您所述.交换机周围的代码不能扩展,很乱,很快就会变得难以阅读和更新.
要回答你的问题,我会说大多数状态机实际上和你的一样:它们对事件做出反应(在你的情况下,民意调查).如果它们是纯粹的顺序,没有任何事件,它们是专门的用法,比如实现一个正则表达式......
注意,Idle状态等同于状态机库的运行时核心:它拦截事件并将它们发布到状态机.使用状态机库,它将从客户端代码中"隐藏",而像您这样的裸机实现必须明确地进行事件轮询.
现在是一个设计批评:一般应该避免全局变量,特别是在状态机中.国家Idle不应该知道hardware_fault全球变量.对于状态机,人们应该通过添加状态(当它有意义时)努力将全局变量"嵌入"状态机本身.一个很好的介绍(分层)状态机和原理的解释是这里.
使用UML表示法(参见此处的教程),您的状态机是:

hardware_fault一起轻松重构以消除依赖关系:

也就是说,我们只是永远呆在这个StartupError州,没有过渡到Idle.
ε(epsilon)表示空转换,即,一旦与源节点相关联的活动结束就采取的转换,没有任何事件.这就是"顺序"状态机的含义.
我还将源代码包含在第一个图表中(第二个图表非常相似),使用非常简单和强大的PlantUML生成.
@startuml
skinparam shadowing false
title Embedded v1
state Startup
state StartupError
state Idle
state Program
state Check
state Copy
Startup : entry/ init HW
StartupError: entry/\n display error\n hw_fault = true
Idle : do/ if not hw_fault: poll
Program : do/ program
Check : do/ check
Copy : do/ copy
[*] -> Startup
Startup -> StartupError : ? [error]
Startup --> Idle : ? [not error]
StartupError --> Idle : ?
Idle --> Program : program_btn
Idle --> Check : check_btn
Idle --> Copy : copy_btn
Program --> Idle : ?
Check --> Idle : ?
Copy --> Idle : ?
@enduml
Run Code Online (Sandbox Code Playgroud)