Stateflow状态机建模:开关控制LED灯状态
汇聚博主多年工程经验的新书《Simulink嵌入式开发实战》现已上市针对Simulink与MBD开发技术形成了一套完整的知识体系和方法论。详细介绍和优惠链接可以参考博客《Simulink嵌入式开发实战》新书上市感谢粉丝长期以来的支持文章目录1 引入2 Stateflow状态机的概念3 状态机建模开关控制LED灯状态5 总结1 引入虽然之前写过一篇状态机的博客《Simulink算法建模 状态机基础》但是没有做更深入的学习。博主准备以LED灯开关为例重新研究一下状态机建模中的一些常用技术点形成一个相对完整的系列。本文内容基于Matlab 2024b。2 Stateflow状态机的概念在嵌入式软件开发中常常会遇到与“状态”和“流转”相关的场景。例如汽车刚刚启动时处于【静止】状态挂挡并踩下油门后会进入到【行驶】状态。在按下开关后LED灯会进入【点亮】状态再按一下开关会进入【熄灭】状态。用传统的if-else或switch 语句去描述这些与状态相关的行为代码往往会变得非常臃肿且出现大量的条件嵌套。通过Simulink中的Stateflow状态机建模可以直观、清晰地描述系统的状态、以及状态之间的转换过程。Stateflow状态机由以下几个核心组成部分状态State系统在某一时刻所处的情况如汽车“静止”、小灯“亮”。事件或条件Event/Condition引发状态变化的外部或内部触发因素如“踩下油门”、“按下开关”。转移Transition系统从一个状态切换到另一个状态的过程。动作Action进入状态、状态保持或退出状态时执行的代码或行为。Stateflow集成在Simulink中通过Chart模块的形式插入到 Simulink 模型中通过输入端口接收 Simulink 中来的信号通过输出端口输出控制命令、标志信号、状态量等。Stateflow可以弥补Simulink其他模块难以处理复杂控制逻辑的缺点在下文的建模示例中可以直观地理解这些概念。3 状态机建模开关控制LED灯状态在Simulink中添加一个Chart模块如图所示。模块中央包含2个矩形和2个箭头看起来就像是两个状态以及互相之间的跳转。双击Chart模块进入模块内部在其中可以进行状态机相关建模。在Chart模块内的上方的组件栏包含了建模常用的子模块如状态、跳转、真值表等。点击组件栏中的Insert State并拖入主界面可以创建OFF和ON状态如图所示。其中状态名称需要用户自己定义位于状态框的左上角。注意第一个拖动出来的状态框图包含一个指向自身的箭头该箭头表示在模型运行的第一个周期状态机默认跳转到这个状态。在两个状态框图内分别用entry关键字定义进入动作进入OFF和ON状态时分别将变量LED_State赋值为0和1表示LED灯的亮和灭如图所示。这里的entry动作表示在第一次进入该状态的周期内执行下面的语句。entry也可简写成en。类似的动作还有during和exit动作分别表示处于状态内和离开状态执行的语句。接着用鼠标在状态框图的边缘拖出2条转移线表示建立2个状态之间的转移如图所示。建立的转移上并没有任何的条件或事件需要在上面添加按下按钮的条件如图所示。转移上的方括号表示其中是跳转的条件这里定义为Key_Pressed表示按钮按下。状态机的搭建已经完成其中包含2个状态OFF和ON跳转条件Key_Pressed互相之间的转移带箭头的线以及进入状态的动作。接下来需要定义LED_State和Key_Pressed变量的属性。首先点击上面建模工具的Model Explorer打开模型浏览器如图所示。在模型浏览器的左侧选中Chart模块时上方会对应出现添加变量以及事件按钮如图所示。这里需要通过添加变量按钮分别定义按下按钮的条件Key_Pressed以及LED灯状态LED_State。在中间的变量配置面板中需要分别配置变量名Name变量类型Scope和数据类型DataType属性。Key_Pressed和LED_State的类型分别为Input和Output代表是状态机的输入和输出。其类型都是boolean即按钮和LED灯都只有开和关两种状态如图所示。定义完成后返回到Chart模块外部。Chart模块自动变成一个输入端口和一个输出端口端口名分别为Key_Pressed和LED_State如图所示。接下来通过输入和输出来验证状态机的效果。首先在Chart模块的输入端口用Pulse Generator模块模拟按下按钮的过程使用Unitdelay模块和逻辑运算模块来检测按下的上升沿时刻如图所示。该输入逻辑表明当Pulse Generator本周期为1且上周期为0的时候Chart模块输入的Key_Pressed为1。该方法表明无论按下按钮多久都只检测从0到1的那一个周期作为跳转的条件。双击Pulse Generator模块配置其中的参数如图所示模拟多次按下开关。在Chart模块的输出端口用Scope模块观测Pulse Generator模块的输出、Key_Pressed输入和LED_State的输出如图所示。参照2.3.1节的内容将模型配置为固定步长、离散求解器以及运行周期为0.01s如图所示。运行模型仿真双击Scope模块可以观察到各个信号如图所示。输出结果可以结合状态机内部逻辑分析。PulseGenerator信号在1-2s、3-4s、5-6s、7-8s、9-10s时为1表示这些时间段按下了开关并且在第2、4、6、8、10时刻松手开关回弹到0。由于模型中使用了Unitdelay模块检测上升沿所以Key_Pressed只在1、3、5、7、9时刻产生一个周期置位为1其余时候都处于0。在Chart模块内部0时刻时通过默认跳转跳到OFF状态如图所示。在1、3、5、7、9s时由于Key_Pressed产生了一个周期的置位1激活了状态机内部的跳转条件如图所示。因此状态从OFF跳转到ON或者从ON跳转到OFF。输出的LED_State表现为数值从0和1之间互相跳转0表示状态OFF1表示状态ON。该状态机以状态跳转、条件、动作等概念简单直观地描述了开关和LED灯的状态之间的关系免去了if-else条件判断的复杂和繁琐。注意如果直接将Pulse Generator输出的方波信号输入到Chart模块的Key_Pressed端口在Pulse Generator置为1的一段时间内状态机会在每个周期都满足[Key_Pressed]跳转条件会在OFF和ON之间来回地跳转。显然这不符合开关控制LED灯的逻辑因此只判断上升沿触发转移。5 总结本文以开关控制LED灯为例研究了状态机的基本概念和建模方法。后续会继续以LED灯为例进行深入的学习。返回个人博客总目录