OpenPLC的Bug

287 阅读2分钟

1.定义功能块为全局时的bug

  • 本地功能块对应POU.c和ST代码
void PROGRAM0_init__(PROGRAM0 *data__, BOOL retain) {
  __INIT_VAR(data__->RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__->COUNTOUT,0,retain)
  COUNTERST_init__(&data__->COUNTLOCAL,retain);
}

// Code part
void PROGRAM0_body__(PROGRAM0 *data__) {
  // Initialise TEMP variables

  __SET_VAR(data__->COUNTLOCAL.,RESET,,__GET_VAR(data__->RESET,));
  COUNTERST_body__(&data__->COUNTLOCAL);
  __SET_VAR(data__->,COUNTOUT,,__GET_VAR(data__->COUNTLOCAL.OUT,));

  goto __end;

__end:
  return;
} // PROGRAM0_body__() 

FUNCTION_BLOCK CounterST
  VAR_INPUT
    Reset : BOOL;
  END_VAR
  VAR
    Cnt : INT;
  END_VAR
  VAR_OUTPUT
    Out : INT;
  END_VAR

  IF Reset THEN
    Cnt := 0;
  ELSE
    Cnt := Cnt + 1;
  END_IF;

  Out := Cnt;
END_FUNCTION_BLOCK

PROGRAM program0
  VAR_INPUT
    Reset : BOOL;
  END_VAR
  VAR_OUTPUT
    CountOut : INT;
  END_VAR
  VAR
    CountLocal : CounterST;
  END_VAR

  CountLocal(Reset:=Reset);
  CountOut := CountLocal.Out;
END_PROGRAM


CONFIGURATION Config0

  RESOURCE Res0 ON PLC
    TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
    PROGRAM instance0 WITH task0 : program0;
  END_RESOURCE
END_CONFIGURATION

  • 全局功能块对应POU.c和ST代码
void PROGRAM0_init__(PROGRAM0 *data__, BOOL retain) {
  __INIT_VAR(data__->RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__->COUNTEROUT,0,retain)
  __INIT_EXTERNAL_FB(COUNTERST,COUNTERGLOBAL,data__->COUNTERGLOBAL,retain)
}

// Code part
void PROGRAM0_body__(PROGRAM0 *data__) {
  // Initialise TEMP variables

  __SET_EXTERNAL_FB(data__->COUNTERGLOBAL.,RESET,,__GET_VAR(data__->RESET,));
  COUNTERST_body__(data__->COUNTERGLOBAL);
  __SET_VAR(data__->,COUNTEROUT,,__GET_VAR(data__->COUNTERGLOBAL->OUT,));

  goto __end;

__end:
  return;
} // PROGRAM0_body__() 
FUNCTION_BLOCK CounterST
  VAR_INPUT
    Reset : BOOL;
  END_VAR
  VAR
    Cnt : INT;
  END_VAR
  VAR_OUTPUT
    Out : INT;
  END_VAR

  IF Reset THEN
    Cnt := 0;
  ELSE
    Cnt := Cnt + 1;
  END_IF;

  Out := Cnt;
END_FUNCTION_BLOCK

PROGRAM program0
  VAR_INPUT
    Reset : BOOL;
  END_VAR
  VAR_OUTPUT
    CounterOut : INT;
  END_VAR
  VAR_EXTERNAL
    CounterGlobal : CounterST;
  END_VAR

  CounterGlobal(Reset:=Reset);
  CounterOut := CounterGlobal.Out;
END_PROGRAM


CONFIGURATION Config0
  VAR_GLOBAL
    CounterGlobal : CounterST;
  END_VAR

  RESOURCE Res0 ON PLC
    TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
    PROGRAM instance0 WITH task0 : program0;
  END_RESOURCE
END_CONFIGURATION

2.错误位置

image.png

// variable setting macros
#define __SET_VAR(prefix, name, suffix, new_value)\
	if (!(prefix name.flags & __IEC_FORCE_FLAG)) prefix name.value suffix = new_value
#define __SET_EXTERNAL(prefix, name, suffix, new_value)\
	{extern IEC_BYTE __IS_GLOBAL_##name##_FORCED(void);\
    if (!(prefix name.flags & __IEC_FORCE_FLAG || __IS_GLOBAL_##name##_FORCED()))\
		(*(prefix name.value)) suffix = new_value;}
#define __SET_EXTERNAL_FB(prefix, name, suffix, new_value)\
	__SET_VAR((*(prefix name)), suffix, new_value)
#define __SET_LOCATED(prefix, name, suffix, new_value)\
	if (!(prefix name.flags & __IEC_FORCE_FLAG)) *(prefix name.value) suffix = new_value

#endif //__ACCESSOR_H

__SET_VAR会判断flags是否置位,如果没置位则进行变量赋值。
__SET_EXTERNAL_FB先取外部变量的指针,然后调用__SET_VAR进行赋值

本地变量宏替换后

__SET_VAR(data__->COUNTLOCAL.,RESET,,__GET_VAR(data__->RESET,));
//宏替换后
if (!(data__->COUNTLOCAL.RESET.flags & __IEC_FORCE_FLAG)) 
    data__->COUNTLOCAL.RESET.value  = __GET_VAR(data__->RESET,)

全局变量宏替换后

__SET_EXTERNAL_FB(data__->COUNTERGLOBAL.,RESET,,__GET_VAR(data__->RESET,));
//宏替换后
__SET_VAR(*(data__->COUNTERGLOBAL.RESET),,__GET_VAR(data__->RESET,))
//继续宏替换(此时调用__SET_VAR会缺少一个输入变量,但是可以推测替换结果)
if (!(*(data__->COUNTERGLOBAL.RESET).flags & __IEC_FORCE_FLAG)) 
    *(data__->COUNTERGLOBAL.RESET).value = __GET_VAR(data__->RESET,)

修改后的代码和编译错误信息

// variable setting macros
#define __SET_VAR(prefix, name, suffix, new_value)\
	if (!(prefix name.flags & __IEC_FORCE_FLAG)) prefix name.value suffix = new_value
#define __SET_EXTERNAL(prefix, name, suffix, new_value)\
	{extern IEC_BYTE __IS_GLOBAL_##name##_FORCED(void);\
    if (!(prefix name.flags & __IEC_FORCE_FLAG || __IS_GLOBAL_##name##_FORCED()))\
		(*(prefix name.value)) suffix = new_value;}
#define __SET_EXTERNAL_FB(prefix, name, suffix, new_value)\
	if (!(*(data__->COUNTERGLOBAL.RESET).flags & __IEC_FORCE_FLAG)) *(data__->COUNTERGLOBAL.RESET).value = __GET_VAR(data__->RESET,)
#define __SET_LOCATED(prefix, name, suffix, new_value)\
	if (!(prefix name.flags & __IEC_FORCE_FLAG)) *(prefix name.value) suffix = new_value

#endif //__ACCESSOR_H

image.png

编译.c文件到.o文件

gcc -c Res0.c -I ./ -I ..\..\..\..\matiec\lib\C

最终matiec修改方案

image.png