第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 里画几个简单的状态图练练手,有什么问题咱们下章聊。