OpenPLC SFC代码分析

153 阅读5分钟
  • 在顺序功能图(SFC)的代码中,data__->STEP0.X中的X表示步骤STEP0的当前状态(激活或者未激活)
  • 整体结构:
    • PROGRAM0_init__函数对SFC进行初始化,包括步数量、动作数量、时间等
    • 定义步进START, STEP0, STEP1, STEP2
    • 定义动作ACTION0
    • 在PROGRAM0_body__函数中计算经过时间,初始化步和动作
    • 计算步进BOOL_A和BOOL_B的状态,用于转移条件
    • 生成STEP0的动作关联逻辑
    • 计算动作的状态变化
    • 执行动作ACTION0,递增CNT变量
    • 根据转移状态复位相应步进
    • 根据转移状态设置相应步进
  • data__->STEP0.T.value 是STEP0的计时器T的值,表示STEP0已经经过的时间
  • __time_to_timespec(1, 0, 2, 0, 0, 0)将时间转换为时间规格结构体,这里表示2秒
  • __time_cmp是时间比较函数,比较两个时间规格的值。>= 0表示STEP0.T.value大于等于2秒

执行流程图

// Calculate elapsed_time
current_time = __CURRENT_TIME;
elapsed_time = __time_sub(current_time, data__->__lasttick_time);
data__->__lasttick_time = current_time;

// Steps initialization
for (i = 0; i < data__->__nb_steps; i++) {
    data__->__step_list[i].prev_state = __GET_VAR(data__->__step_list[i].X);
    if (__GET_VAR(data__->__step_list[i].X)) {
      data__->__step_list[i].T.value = __time_add(data__->__step_list[i].T.value, elapsed_time);
    }
}

// Actions initialization
__SET_VAR(data__->,__action_list[i].state,,0);

// Transitions fire test
if (__GET_VAR(data__->START.X)) {
    __SET_VAR(data__->,__transition_list[0],,__GET_VAR(data__->BOOL_A,))
    }
    
__SET_VAR(data__->,__transition_list[1],,0);
__SET_VAR(data__->,__transition_list[2],,0);
__SET_VAR(data__->,__transition_list[3],,0);

// Transitions reset steps
if (__GET_VAR(data__->__transition_list[0])) {
    __SET_VAR(data__->,START.X,,0);
    
// Transitions set steps
if (__GET_VAR(data__->__transition_list[0])) {
    __SET_VAR(data__->,STEP0.X,,1);
    data__->STEP0.T.value = __time_to_timespec(1, 0, 0, 0, 0, 0);
}

// Steps association
// STEP0 action associations
{
    char active = __GET_VAR(data__->STEP0.X);
    char activated = active && !data__->STEP0.prev_state;
    char desactivated = !active && data__->STEP0.prev_state;

    if (active && __time_cmp(data__->STEP0.T.value, __time_to_timespec(1, 0, 2, 0, 0, 0)) >= 0) 
                      {__SET_VAR(data__->,__action_list[__SFC_ACTION0].state,,1);}
    else if (desactivated)
                      {__SET_VAR(data__->,__action_list[__SFC_ACTION0].state,,0);};

}

// Actions state evaluation
__SET_VAR(data__->,__action_list[i].state,,__GET_VAR(data__->__action_list[i].state) | data__->__action_list[i].stored);

// Actions execution
if(__GET_VAR(data__->__action_list[__SFC_ACTION0].state)) {
__SET_VAR(data__->,CNT,,(__GET_VAR(data__->CNT,) + 1));
}

OpenPLC执行步骤

  1. 设置每个step的前一步状态和当前激活的step对应的时间T
  2. 设置action的状态为FALSE
  3. 获取当前激活的step对应的transition
  4. 如果transition为TRUE则设置当前激活的step为FALSE,设置下一step状态为TRUE并且时间T为0
  5. 根据当前step的状态(激活,上升沿,下降沿)决定action的状态
  6. 如果action状态为TRUE,则执行action对应的操作

修改后的执行步骤

  1. 设置当前激活的step对应的时间T
  2. 设置action的状态为FALSE
  3. 根据当前step的状态(激活,上升沿,下降沿)决定action的状态
  4. 如果action状态为TRUE,则执行action对应的操作
  5. 获取当前激活的step对应的transition
  6. 如果transition为TRUE则记录step状态转换前每个step的状态,然后设置当前激活的step为FALSE,设置下一step状态为TRUE并且重置时间T为0

image.png image.png

S限定符和R限定符

image.png

  // Calculate elapsed_time
  current_time = __CURRENT_TIME;
  elapsed_time = __time_sub(current_time, data__->__lasttick_time);
  data__->__lasttick_time = current_time;

  // Steps initialization
  for (i = 0; i < data__->__nb_steps; i++) {
    data__->__step_list[i].prev_state = __GET_VAR(data__->__step_list[i].X);
    if (__GET_VAR(data__->__step_list[i].X)) {
      data__->__step_list[i].T.value = __time_add(data__->__step_list[i].T.value, elapsed_time);
    }
  }
  // Actions initialization
  for (i = 0; i < data__->__nb_actions; i++) {
    __SET_VAR(data__->,__action_list[i].state,,0);
    data__->__action_list[i].set = 0;
    data__->__action_list[i].reset = 0;
    if (__time_cmp(data__->__action_list[i].set_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) > 0) {
      data__->__action_list[i].set_remaining_time = __time_sub(data__->__action_list[i].set_remaining_time, elapsed_time);
      if (__time_cmp(data__->__action_list[i].set_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) <= 0) {
        data__->__action_list[i].set_remaining_time = __time_to_timespec(1, 0, 0, 0, 0, 0);
        data__->__action_list[i].set = 1;
      }
    }
    if (__time_cmp(data__->__action_list[i].reset_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) > 0) {
      data__->__action_list[i].reset_remaining_time = __time_sub(data__->__action_list[i].reset_remaining_time, elapsed_time);
      if (__time_cmp(data__->__action_list[i].reset_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) <= 0) {
        data__->__action_list[i].reset_remaining_time = __time_to_timespec(1, 0, 0, 0, 0, 0);
        data__->__action_list[i].reset = 1;
      }
    }
  }

  // Transitions fire test
  if (__GET_VAR(data__->INIT.X)) {
    __SET_VAR(data__->,__transition_list[0],,__BOOL_LITERAL(TRUE));
  }
  else {
    __SET_VAR(data__->,__transition_list[0],,0);
  }
  if (__GET_VAR(data__->STEP0.X)) {
    __SET_VAR(data__->,__transition_list[1],,__BOOL_LITERAL(TRUE));
  }
  else {
    __SET_VAR(data__->,__transition_list[1],,0);
  }
  if (__GET_VAR(data__->STEP1.X)) {
    __SET_VAR(data__->,__transition_list[2],,__BOOL_LITERAL(TRUE));
  }
  else {
    __SET_VAR(data__->,__transition_list[2],,0);
  }
  if (__GET_VAR(data__->STEP2.X)) {
    __SET_VAR(data__->,__transition_list[3],,__BOOL_LITERAL(TRUE));
  }
  else {
    __SET_VAR(data__->,__transition_list[3],,0);
  }

  // Transitions reset steps
  if (__GET_VAR(data__->__transition_list[0])) {
    __SET_VAR(data__->,INIT.X,,0);
  }
  if (__GET_VAR(data__->__transition_list[1])) {
    __SET_VAR(data__->,STEP0.X,,0);
  }
  if (__GET_VAR(data__->__transition_list[2])) {
    __SET_VAR(data__->,STEP1.X,,0);
  }
  if (__GET_VAR(data__->__transition_list[3])) {
    __SET_VAR(data__->,STEP2.X,,0);
  }

  // Transitions set steps
  if (__GET_VAR(data__->__transition_list[0])) {
    __SET_VAR(data__->,STEP0.X,,1);
    data__->STEP0.T.value = __time_to_timespec(1, 0, 0, 0, 0, 0);
  }
  if (__GET_VAR(data__->__transition_list[1])) {
    __SET_VAR(data__->,STEP1.X,,1);
    data__->STEP1.T.value = __time_to_timespec(1, 0, 0, 0, 0, 0);
  }
  if (__GET_VAR(data__->__transition_list[2])) {
    __SET_VAR(data__->,STEP2.X,,1);
    data__->STEP2.T.value = __time_to_timespec(1, 0, 0, 0, 0, 0);
  }
  if (__GET_VAR(data__->__transition_list[3])) {
    __SET_VAR(data__->,INIT.X,,1);
    data__->INIT.T.value = __time_to_timespec(1, 0, 0, 0, 0, 0);
  }

  // Steps association
  // STEP0 action associations
  {
    char active = __GET_VAR(data__->STEP0.X);
    char activated = active && !data__->STEP0.prev_state;
    char desactivated = !active && data__->STEP0.prev_state;

    if (activated) {
      data__->__action_list[__SFC_ACTION0].set = 1;
      data__->__action_list[__SFC_ACTION0].reset_remaining_time = __time_to_timespec(1, 0, 12, 0, 0, 0);
    }

  }

  // STEP1 action associations
  {
    char active = __GET_VAR(data__->STEP1.X);
    char activated = active && !data__->STEP1.prev_state;
    char desactivated = !active && data__->STEP1.prev_state;

    if (active)       {data__->__action_list[__SFC_ACTION0].reset = 1;}

  }


  // Actions state evaluation
  for (i = 0; i < data__->__nb_actions; i++) {
    if (data__->__action_list[i].set) {
      data__->__action_list[i].set_remaining_time = __time_to_timespec(1, 0, 0, 0, 0, 0);
      data__->__action_list[i].stored = 1;
    }
    if (data__->__action_list[i].reset) {
      data__->__action_list[i].reset_remaining_time = __time_to_timespec(1, 0, 0, 0, 0, 0);
      data__->__action_list[i].stored = 0;
    }
    __SET_VAR(data__->,__action_list[i].state,,__GET_VAR(data__->__action_list[i].state) | data__->__action_list[i].stored);
  }

  // Actions execution
  if(__GET_VAR(data__->__action_list[__SFC_ACTION0].state)) {
    __SET_VAR(data__->,A,,(__GET_VAR(data__->A,) + 1));
  }



  goto __end;

__end:
  return;
} // PROGRAM0_body__() 
主要程序

image.png

image.png

重点解释
  • 当set_remaining_time减为0时,会设置动作的激活标志set=1。
  • 当reset_remaining_time减为0时,会设置动作的禁用标志reset=1。
  • stored就是动作被激活或者禁用的标志
  • state是状态变量,通过将原来的值与stored做位或运算来更新状态
错误实例

image.png

  • SL限定符启动的action和R限定符终止的action名称不同,将导致R限定符失效