第3章 Stateflow入门:理解有限状态机(FSM)概念,学习Stateflow图表的基本元素和状态迁移
3.1 有限状态机到底是什么?
说实话,我刚接触嵌入式开发那会儿,对「状态机」这三个字挺发怵的。总觉得是什么高深的理论。后来做车灯控制项目做多了,才发现——说白了,状态机就是描述「一个东西在不同情况下该怎么表现」的数学模型。
你想想看,车灯不就正好是这样吗?
- 车灯要么是「关」的,要么是「开」的
- 在「开」的状态下,又分近光、远光、雾灯
- 每个状态之间,通过特定的操作(比如拨动开关)才能切换
这不就是状态机吗?
有限状态机(FSM)的核心就三个要素:状态、事件、迁移。状态就是系统当前所处的模式,事件是触发变化的条件,迁移就是从一个状态到另一个状态的路径。
核心要点:FSM 在任何时刻只能处于一个状态。这是它最根本的特征,也是它好用的原因——逻辑清晰,不会乱。
3.2 Stateflow 图表的基本元素
在 Simulink 里打开 Stateflow 编辑器,你会看到一个空白画布。嗯,这就是我们要画状态机的地方。
我个人习惯先把几个基本元素搞清楚,再动手画。不然容易画着画着就乱了。
3.2.1 状态(State)
状态是 Stateflow 里最核心的元素。它用圆角矩形表示,里面写上状态的名字。
// 一个最简单的状态定义
State1
{
entry: 进入该状态时执行的代码
during: 在该状态期间持续执行的代码
exit: 离开该状态时执行的代码
}
我在项目中遇到过一个问题:新手容易把 entry 和 during 搞混。记住一点——entry 只执行一次,during 是周期执行的。比如车灯刚打开时,entry 里做初始化;during 里做亮度调节。
3.2.2 迁移(Transition)
迁移就是状态之间的箭头。箭头上要写清楚触发条件。
格式是这样的:
事件[条件]{条件动作}/迁移动作
举个例子:
SWITCH_ON[车速 > 30]{灯亮计数器++}/点亮近光灯
这里 SWITCH_ON 是事件,车速 > 30 是条件,灯亮计数器++ 是条件动作,点亮近光灯 是迁移动作。
我的小技巧:刚开始学的时候,别把迁移条件写得太复杂。一个迁移上只放一个条件,逻辑清晰最重要。等熟练了再玩复合条件。
3.2.3 默认迁移(Default Transition)
这个容易被忽略。默认迁移是一个没有源状态的箭头,它指定了系统启动时进入哪个状态。
我曾经吃过这个亏——画完状态图,仿真一看,状态机根本没动。找了半天才发现,忘了画默认迁移。嗯,这种低级错误犯一次就够了。
3.3 状态迁移的实战案例:车灯控制
光说不练假把式。我们直接拿车灯控制来走一遍。
假设我们要实现一个简单的车灯控制器,有四个状态:
- OFF:车灯关闭
- PARKING:示廓灯
- LOW_BEAM:近光灯
- HIGH_BEAM:远光灯
迁移规则是这样的:
| 当前状态 | 触发事件 | 下一状态 |
|---|---|---|
| OFF | 旋钮转到位置1 | PARKING |
| PARKING | 旋钮转到位置2 | LOW_BEAM |
| LOW_BEAM | 远光开关按下 | HIGH_BEAM |
| HIGH_BEAM | 远光开关松开 | LOW_BEAM |
| 任意状态 | 旋钮回到OFF | OFF |
在 Stateflow 里画出来,就是四个圆角矩形,加上几条带箭头的线。每个箭头上写上事件名。
// Stateflow 中的状态定义示例
OFF
{
entry: 关闭所有灯光
during: 无操作
}
LOW_BEAM
{
entry: 点亮近光灯
during: 检测环境光,自动调节亮度
exit: 关闭近光灯
}
注意:在实际项目中,状态迁移一定要考虑「非法迁移」的处理。比如从 OFF 直接到 HIGH_BEAM 是不允许的。Stateflow 默认会忽略非法迁移,但最好在设计中明确禁止。
3.4 状态动作的类型
Stateflow 里每个状态可以定义三种动作:
- entry:进入时执行一次。适合做初始化、置位操作。
- during:在状态内每个时间步执行。适合做持续监控、数值更新。
- exit:离开时执行一次。适合做清理、复位操作。
为什么要有这三种?我举个例子你就明白了。
车灯从 LOW_BEAM 切换到 HIGH_BEAM 时:
- exit 里关闭近光灯(避免两个灯同时亮造成过载)
- entry 里点亮远光灯
- during 里检测远光灯是否过热,必要时自动降功率
你看,每个动作各司其职,逻辑就清晰了。
3.5 避坑指南
做车灯控制这几年,我在 Stateflow 上踩过不少坑。挑几个典型的说说:
我曾经犯过的错:
- 状态命名太随意,用了 state1、state2 这种名字。三个月后回来看代码,完全想不起每个状态是干嘛的。后来我强制自己用全大写加下划线,比如 LOW_BEAM_ACTIVE。
- 迁移条件写得太复杂,一个箭头上堆了五六个条件。调试时根本不知道是哪个条件触发了迁移。现在我的原则是:一个迁移最多两个条件。
- 忘了考虑状态超时。车灯控制里,如果远光灯持续亮太久,需要自动切回近光灯。这个逻辑必须在 during 里加计时器判断。
3.6 小结
Stateflow 入门其实不难。你只要记住:
- 状态是圆角矩形,迁移是箭头
- 每个状态有 entry、during、exit 三种动作
- 默认迁移不能忘
- 命名规范、条件简洁
下一章我们会用 Stateflow 真正搭建一个完整的车灯控制模型。到时候你会发现,有了状态机这个工具,复杂的控制逻辑也能变得井井有条。
嗯,今天就到这儿。你先在 Simulink 里画几个简单的状态图练练手,有什么问题咱们下章聊。