matlab状态机stateflow生成C语言代码解析

1. 简介

simulink的stateflow采用的是单事件触发的同步状态机模式。本文介绍了一种可行的状态机的实现方法,可根据stateflow由C code generator直接生成。

1.1 状态

状态(State)拥有Entry,During,Exit三个方法,分别在进入循环退出状态时发生。

1.2 转移

转移(Transition)的形式为:

event[guard]{action}

事件(event)触发状态转移。
守卫条件(guard condition)一般是一个返回bool类型的函数,如果不满足条件,事件会被“安静地丢弃”(discard silently)。
转移动作(action)是在转移过程中执行的函数。

1.3 伪状态

节点伪状态(Junction PseudoState)因为可以用相同方式处理,因此将条件、合并、分支伪状态统称。
历史伪状态 (History PseudoState)再一次进入子状态时,将上一次退出时的状态作为默认状态。
初始伪状态 顾名思义,状态机起点。

2. 事件

用宏定义的方式定义事件。-1表示没有事件发生。

#define untitled_CALL_EVENT            (-1)
#define untitled_event_goGreen         (0)
#define untitled_event_goOff           (1)
#define untitled_event_goOn            (2)
#define untitled_event_goQuickly       (3)
#define untitled_event_goRed           (4)
#define untitled_event_goSlowly        (5)
#define untitled_event_goSteady        (6)
#define untitled_event_goYellow        (7)

3. 状态

3.1 一级状态

一级状态也使用用宏定义,从1开始。

#define untitled_IN_Off                ((uint8_T)1U)
#define untitled_IN_On                 ((uint8_T)2U)

3.2 嵌套子状态

嵌套子状态多一个无激活的0状态。
Color状态的子状态:

#define untitled_IN_NO_ACTIVE_CHILD    ((uint8_T)0U)
#define untitled_IN_Green              ((uint8_T)1U)
#define untitled_IN_Red                ((uint8_T)2U)
#define untitled_IN_Yellow             ((uint8_T)3U)

Rate状态的子状态:

#define untitled_IN_NO_ACTIVE_CHILD    ((uint8_T)0U)
#define untitled_IN_Flashing_Quickly   ((uint8_T)1U)
#define untitled_IN_Flashing_Slowly    ((uint8_T)2U)
#define untitled_IN_Steady             ((uint8_T)3U)

3.3 状态结构体

状态结构体:

typedef struct {
  real_T data;                      /* '<Root>/Chart' */
  int32_T sfEvent;                     /* '<Root>/Chart' */
  uint8_T is_active_c3_untitled;       /* '<Root>/Chart' */
  uint8_T is_c3_untitled;              /* '<Root>/Chart' */
  uint8_T is_COLOR;                    /* '<Root>/Chart' */
  uint8_T was_COLOR;                   /* '<Root>/Chart' */
  uint8_T is_active_COLOR;             /* '<Root>/Chart' */
  uint8_T is_RATE;                     /* '<Root>/Chart' */
  uint8_T was_RATE;                    /* '<Root>/Chart' */
  uint8_T is_active_RATE;              /* '<Root>/Chart' */
} DW_untitled_T;

结构体包括状态机中的使用的变量:

  real_T data;                      /* '<Root>/Chart' */

事件变量。由于是单事件同步模式,所以只需要一个事件。

int32_T sfEvent;                     /* '<Root>/Chart' */

一级状态。is_c3储存当前状态,is_active_c3储存当前是否激活(为了entry事件)

  uint8_T is_active_c3_untitled;       /* '<Root>/Chart' */
  uint8_T is_c3_untitled;              /* '<Root>/Chart' */

嵌套事件。is储存当前状态,is_active储存当前是否激活,was储存上一次退出时的状态,如果没有历史伪状态则不需要。

  uint8_T is_COLOR;                    /* '<Root>/Chart' */
  uint8_T was_COLOR;                   /* '<Root>/Chart' */
  uint8_T is_active_COLOR;             /* '<Root>/Chart' */

4. 流程

以下代码均为伪代码。

main函数调用如下。OverrunFlag标志进入临界区,保证线程安全。StateMachine_Step()为状态机更新调用函数。

  OverrunFlag = true;
  /* Save FPU context here (if necessary) */
  /* Re-enable timer or interrupt here */
  /* Set model inputs here */

  /* Step the model */
  StateMachine_Step();

  /* Get model outputs here */

  /* Indicate task complete */
  OverrunFlag = false;

4.1 StateMachine_Step()

设置当前事件为无事件。事件可以由外界更改,也可由内部更改。

CurEvent = untitled_CALL_EVENT;

通过is_active判断是否执行entry任务。状态由初始伪状态变为第一个状态,同时初始化输出值。一级状态不可以有历史伪状态。

if (is_active_c3 == 0U) {
    is_active_c3 = 1U;
    is_c3 = InitState;
    InitState_Entry();
  } 
  else {
  	StateMachine_Select(); 
  }

4.2 StateMachine_Select()

如果已经激活一级状态机。那么根据is_c3判断当前状态。每个状态都有一个处理函数。

switch (is_c3) {
     case State1:
      State1_Proc();
      break;
     case State2:
      State2_Proc();
      break;
      ...
    }

4.3 State_Proc()

格式为:

//当前事件为转移事件,且满足守卫条件
if ((CurEvent == TranEvent) && Guard())
 {
 	//转移action
    Tran_Action();
    //上一个状态子状态Exit
    LastSubState_Exit();
 	//上一个状态Exit
 	LastState_Exit();
 	//状态变为下一个状态
 	CurState = NextState;
 	NextState_Entry();
 	//下一个状态子状态Entry
 	NextSubState_Entry();
 }

如果存在条件伪状态(一般情况条件伪状态前是事件,后面是守卫条件):

else if((CurEvent == TranEvent2))
{
	//有条件伪状态
	if(Guard2())
	{
	...
	}
	else if(Guard3())
	{
	...
	}
	else
	{
	...
	}
}

如果没有转移,那么就执行during。

 else
 {
 	LastState_During();
 	if (is_active_lastsubstate != 0U) 
 	{
      LastSubState_Select();
    }
 }

4.4 LastSubState_Exit()

switch (is_LastSubState) {
     case LastSubState_Substate1:
      Substate1_exit();
      is_LastSubState = NO_ACTIVE_CHILD;
      break;
     case LastSubState_Substate2:
      ...
    }
    is_active_LastSubState = 0U;

4.5 NextSubState_Entry()

有历史伪状态,上一次退出状态保存在was_中。

is_active_NextSubState = 1U;
switch (was_NextSubState) {
       case NextSubState_SubState1:
        is_NextSubState = NextSubState_SubState1;
        was_NextSubState = NextSubState_SubState1;
        SubState1_entry();
        break;
       case NextSubState_SubState2:
       ...
       }

无历史伪状态,进入默认初始状态。

is_active_NextSubState = 1U;
is_NextSubState = NextSubState_SubState1st;
SubState1_entry();

直接转移到子状态中某一状态的,要先处理父状态,然后处理子状态。

is_active_NextSubState = 1U;
is_NextSubState = NextSubState_SubStateInd;
SubState1_entry();

4.6 LastSubState_Select()

switch (is_LastSubState) {
     case LastSubState_Substate1:
      //与State_Proc()类似,判断转移
      SubState1_Proc();
      break;
     case LastSubState_Substate2:
      ...
    }

按照以上递推直到没有子状态,然后循环执行。

5. 总结

本状态的exit与下一个状态的entry都是在转移的过程中完成的,执行顺序为action->exit->entry。不发生状态转移才会执行本状态的during。
另外,stateflow中的OR状态有严格的先后执行顺序。

  • 18
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏打豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值