正确图表行为指南
这些指南确保事件驱动系统中的图表行为正确:
当一个状态处于活动状态时,其父级也应处于活动状态。
具有异或分解的状态(或图表)不得有多个活动子状态。
如果并行状态处于活动状态,则优先级较高的同级状态也必须处于活动状态。
早返回逻辑是如何工作的
Stateflow图表在单个线程上运行。因此,图表必须中断当前活动以处理事件。基于状态或转换动作的事件广播的活动可能与当前活动冲突。图表通过使用事件广播的早返回逻辑来解决这些冲突,如下所示:
动作类型 | 早返回逻辑 |
---|---|
Entry | 如果在事件广播结束时状态不再处于活动状态,则图表不会执行进入状态的剩余步骤。 |
Exit | 如果状态在事件广播结束时不再处于活动状态,则图表不会执行剩余的退出操作或从一个状态转换到另一个状态。 |
During | 如果在事件广播结束时状态不再处于活动状态,则图表不会执行执行活动状态的剩余步骤。 |
Condition | 如果内部或外部流程图的源状态(或默认流程图的父状态)在事件广播结束时不再处于活动状态,则该图表不会执行执行流程图的其余步骤。 |
Transition | 如果转换路径的父级未处于活动状态,或者该父级有一个活动的子状态,则图表不会执行其余的转换操作和状态输入操作。 |
早返回逻辑示例
在这个例子中,假设状态A最初是活动的。事件E发生,导致以下行为:
图表根检查事件E是否导致有效的活动状态a转换。
1 存在向状态B的有效转换。
2 有效转换的条件动作执行并广播事件F。
3 事件F中断了从A到B的转换。
4 图表根检查事件F是否导致有效的活动状态a转换。
5 存在向状态C的有效转换。
6 状态A执行其退出操作。
7 状态A变为非活动状态。
8 状态C变为活动状态。
9 状态C执行并完成其输入操作。
C状态现在是其图表中唯一活跃的子状态。状态流程图无法返回到从状态A到状态B的转换,并在广播事件F的条件操作后继续(步骤3)。首先,其源状态A不再处于活动状态。其次,如果图表允许转换,状态B将成为图表的第二个活动子状态。此行为违反了具有排他性(or)分解的状态(或图表)不能有多个活动子状态的准则。因此,该图表使用早期返回逻辑并停止从状态A到状态B的转换。
避免使用无向的本地事件广播,这可能会导致图表中出现不必要的递归行为。使用send操作符进行定向本地事件广播。
下面我搭建一个类似的模型,其中E是输入事件,F是本地事件,生成一下代码
/* Function for Chart: '<Root>/Chart' */
static void untitled_c3_untitled(void)
{
int32_T b_previousEvent;
if (untitled_DW.is_c3_untitled == untitled_IN_A) {
switch (untitled_DW.sfEvent) {
case untitled_event_E:
b_previousEvent = untitled_DW.sfEvent;
untitled_DW.sfEvent = untitled_event_F;
/* Chart: '<Root>/Chart' */
/* Chart: '<Root>/Chart' */
untitled_c3_untitled();
untitled_DW.sfEvent = b_previousEvent;
if (untitled_DW.is_c3_untitled == untitled_IN_A) {
untitled_DW.is_c3_untitled = untitled_IN_B;
/* Outport: '<Root>/Out1' incorporates:
* Inport: '<Root>/In1'
*/
untitled_Y.Out1 = untitled_U.In1 + 1.0;
}
break;
case untitled_event_F:
untitled_DW.is_c3_untitled = untitled_IN_C;
/* Outport: '<Root>/Out1' incorporates:
* Inport: '<Root>/In1'
*/
untitled_Y.Out1 = untitled_U.In1 + 100.0;
break;
}
}
}
/* Model step function */
void untitled_step(void)
{
/* Chart: '<Root>/Chart1' */
if (untitled_DW.is_active_c1_untitled == 0U) {
untitled_DW.is_active_c1_untitled = 1U;
/* Chart: '<Root>/Chart' */
/* Chart: '<Root>/Chart' */
untitled_DW.sfEvent = untitled_event_E;
untitled_c3_untitled();
}
/* End of Chart: '<Root>/Chart1' */
}
可以看到untitled_c3_untitled函数中使用了递归,但是在递归中有switch判断,函数直接会跳到untitled_event_F这个条件中,从而执行untitled_IN_C图表中的内容,完成后break跳出函数,从而不会陷入无限的函数递归中。