if_else
if_elseif_else
图形化的迭代循环结构
使用流程图可以表示图形化的反复循环. 创建一个for 循环结构,如下图所示的流程图。当执行缺省转移时,循环变量(图中的变量为?i‘) 作为一个条件动作被初始化。
在条件声明中?i‘的值和固定值进行比较。作为条件动作的一部分,反复循环?i‘的值。创建一个while 循环, 流程图如下所示。
在每个时间步长,都会执行条件动作,直到条件不再为真为止。
注意: 当创建无状态系统(也就是流程图)时,在终止节点处,必须有一个无条件路径。
这是为了防止用户创建无限循环模型.。
临时数据vs. 局部数据
仅在状态图中可见的数据对象可以分成两类。
一类为局部(?local‘)数据对象,另一类为临时(?temporary‘)数据对象。
局部数据对象就相当于函数中的全局变量(也就是一个?局部‘的全局变量): ", 状态图中的局部数据就相当于函数的全局变量: 只有在状态图中,数据才可见
当状态图第一次被激活时,局部数据为初值。随后在状态图被激活时,局部数据为前一次数值
重新赋初值时,它的值必须要重置 ", 状态图中的临时数据对象就相当于函数中的一个局部变量: 它的值仅在状态图中可见. 永远从初值开始
在状态图的以后激活的情况下,自动重置 ", 只有在无状态的状态图中临时数据才是有效的.
??????????????????????????????????????????????????????????????怎么使用临时数据
状态图层次的概念
当状态具有第二个层次时,状态就构成了层次。那么高层次的状态就被称之为父状态,而低层次的状态就被称之为子状态。状态图中允许拥有的状态层次的数目是没有任何限制的。
Stateflow允许在不同层次状态之间存在转移,如果转移穿越了父状态的边界直接到达了低层次的子状态,则转移被称之为超转移。
使用层次需要了解掌握以下概念:
? 子状态的各种对象仅仅父状态活动时,才有可能执行或者有效
? 直接从父状态发出的转移,可以不用考虑具体哪一个子状态处于活动状态。
层次化转移的路径
哪一个状态首先被激活或者退出活动状态? 在具有层次的状态之间转移时,一般转移路径的源头是从最内部的子状态出发,而终止于目标状态的最内部的子状态。
使用层次的目的
在状态图中使用层次有如下几个目的:
? 使用层次,可以将相关的对象组合在一起,构成族群
? 可以将一些通用的转移路径或者动作组合成为一个转移动作或路径,简化模型
? 适当地使用层次,可以有效地缩减生成代码的大小,也能够提高程序执行的效率和可读性
生成组合父状态
即便是将所有的子对象都用一个父状态包含起来,子对象在编辑状态时彼此之间还是独立的,例如进行移动、拷贝和重新设置大小等操作。如果需要将具有层次的状态当作一个整
体来看待时,需要将父状态组合起来。
方法:
1. 右键单击父状态,执行快捷菜单的命令 2. 选择Make Contents子菜单下的Group命令
如果需要取消父状态的组合状态,按照上面的步骤再次选择Group命令即可。另外,还可以双击父状态来完成上面的操作。
组合了的层次化状态,其状态框图内部用灰色填充,当重新设置状态框图的大小时,除了状态的标签不发生改变,其余的对象尺寸都会相应的发生变化。
低层次的默认转移
第二个层次状态的默认转移决定了当父状态被激活时,具体哪一个子状态被激活。如果状态转移之间存在终点为子状态的转移,这种默认转移是不起作用,也没有必要存在的。
? 记住:默认转移仅仅在父状态被激活时作用一次,在第二个状态图中,如果Power_On状态被第二次激活时,该状态的默认转移就不再起作用了,那么系统不知道究竟哪一个子状态会被激活。
? 结果:当On事件驱动从Power_Off状态转移到Power_On状态第二次发生时,系统会发出一个状态二义性错误的告警
历史节点
历史节点记录了在父状态退出活动状态时,具体哪一个子状态处于活动状态。当父状态再次被激活时,如果子状态没有定义显性直接转移,则历史节点将使其记录的子状态处于活动状态。
在下面的例子中,如果从Off状态转移到On状态,具体哪一个子状态(Empty或者DiskInserted)会被激活,完全取决于在On状态上次退出时哪一个子状态是活动的。
内部转移
内部转移是指从父状态边缘内部出发,终止于子状态外边缘的转移,转移始终处于父状态的内部。
在下面的例子中,无论哪一个子状态处于活动状态,当Play事件发生时,系统都将转移
到Play状态。
层次转移的测试优先权
在层次化的状态图中,存在一组规则判断转移的有效性,特别是父状态或者子状态同时具有多个有效的转移时,这些规则如下:
? 转移测试首先从最高层次的活动状态开始,然后逐级向内检测 ? 外部转移优先于内部转移被测试 ? 在同样的层次上,超转移首先被检测
上述三个转移测试规则是每一个转移测试的基础。 所以根据这些基本原则:
1. 转移的测试从活动的父状态开始: ? 向外的转移首先被测试. (level 1) ? 接着是内部转移(level 2)
2. 然后从活动的子状态开始检测转移: ? 穿越父状态边缘的转移首先被检测(level 3)
? 然后是父状态内部子状态之间的转移被检测. (level 4)
在同等层次的转移之间,具有最严格限制的转移首先被检测。 根据语法规则,状态动作优先于转移! 状态进入动作 优先于 默认转移首先执行
? 状态的during 或on-event 动作在内部转移之前被执行
子状态图
子状态图是从父状态图中创建的,它在功能上有别于父状态,最主要的区别就是子状态隐藏了内部细节。子状态利用灰色图块隐藏内部细节,简化了状态图的复杂程度,从这一点上看,子状态图更类似与Simulink的子系统。
创建子状态图
将父状态转变成为子状态图:
1. 右键单击父状态,使用快捷菜单. 2. 使用Make Contents 子菜单 3. 选择Subcharted命令
若取消上述操作,则重复上述过程即可。
同样的功能还可以使用Box来完成,同子状态图不同,Box是直角矩形,而子状态图是圆角矩形。
观察子状态图的细节
察看子状态图的细节只要双击子状态图即可,这时Stateflow图形编辑器将切换视图到子状态图内部。可以利用编辑器工具条的前三个
按钮在子状态图内外切换。
子状态图之间的超转移
绘制子状态图之间的超转移: ? 从源状态出发,左键拖放转移
? 将转移拖过目标状态的边界,这时在子状态图 中心将出现一个虫孔(Wormhole) ? 继续拖放转移到虫孔中心,编辑窗体将自动切换到子状态图的内部,显示子图的细节。 ? 继续拖放转移,到最终的子状态的边界,这样完成了超转移的设置相反的操作,从子状态图内部出发,绘制到外部的虫孔,就可以完成操作。
状态转移的流程图
状态之间的转移可以使用流程图来完成复杂的逻辑控制,一旦发生了触发,状态转移中的流程图就会被执行,直到其中的一个分支到达了某个状态。如果存在终点是连接节点的转移分支,这个转移被认为无效。这个转移也就不会引起状态的转移。
状态中的流程图
当进入某个状态时,可能需要根据某些复杂的逻辑关系执行一系列的动作,例如if-elseif-else结构。为了完成这样的功能,就需要没有状态存在的流程图结构。
这种情况下,状态每次触发流程图就被执行一次,一直执行到某个转移分支到达终止连接节点。和状态图中的流程图不一样,当流程图执行完毕后,父状态保持活动状态。
定义状态的本地数据
可以将数据对象的作用范围定义成为Local或者静态,这样数据对象的有效范围就可以在某个状态内部了:
1. 在浏览器的层次树选择某个状态;
2. 选择Add 菜单下的命令添加数据对象到数据字典同样也可以修改已有数据的可见性,从全局到本地。可以在浏览器中用右键拖放数据对象到不同状态或状态图中,改变数据的作用范围。
访问数据对象
在其他状态中访问其他状态的数据对象依然可能,然而,必须使用特殊的表达式语法形式。如果需要在其他的状态中使用其他状态中的数据对象,使用下面的语法形式:
state_name.data_name如果在状态和父状态内部同时存在一个同名的数据对象,则状态中数据对象就会被父状态中的数据对象―屏蔽‖。例如Chart 和State1 分别具有数据对象名叫:data。若需要在State1中访问定义在Chart 中的数据对象data,则需要使用下面的语法,指定父状态的名称:parent_name.data_name
图形函数
图形函数是指在状态图中以图形方式存在的函数,它是从具有流程图的状态创建的,它