0

我一直在尝试访问AXIS_REF_SM3ieAxisSM3_Basic.MC_MoveAbsolute返回wDriveId轴的。

由于Axis被声明为VAR_IN_OUT变量,我无法使用.Axis语法在 FB 之外访问它,因为它会导致编译器抛出

C0178:  No external access to VAR_IN_OUT parameter 'Axis' of 'MC_MOVEABSOLUTE'."

错误是有道理的,因为VAR_IN_OUT变量不应该是可远程访问的。

然后我尝试使用扩展 FBFUNCTION_BLOCK FB_MoveAbsolute EXTENDS SM3_Basic.MC_MoveAbsolute并编写自己的方法以Axis在 PRG 调用中返回,FB_MoveAbsolute但我收到以下编译器错误

C0283:  Function block 'FB_MoveAbsolute': No override possible on Method MC_MoveAbsolute.FB_Init with access specifier FINAL

反而。

有谁知道更好的方法来获得from的wDriveId价值? 或者其他检查FB正在使用哪个轴的方法?AxisSM3_Basic.MC_MoveAbsolute

4

1 回答 1

0

您可以尝试在功能块周围制作一个包装器:

FUNCTION_BLOCK FINAL FinalBlock
VAR_IN_OUT
    someVar: DINT;
END_VAR
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
    someVar: DINT;
END_VAR
VAR
    _wrapped_obj: POINTER TO FinalBlock;
END_VAR

_wrapped_obj^(someVar := someVar);

//////

METHOD FB_Init: BOOL
VAR_INPUT
    bInitRetains: BOOL;
    bInCopyCode: BOOL;
END_VAR
VAR_IN_OUT
    wrappedObj: FinalBlock;
END_VAR

THIS^._wrapped_obj := ADR(wrappedObj);

//////

METHOD GetSomeVarMethod : DINT

GetSomeVarMethod := THIS^.someVar;

//////

METHOD GetWrappedObjP : POINTER TO FinalBlock

GetWrappedObjP := THIS^._wrapped_obj;
PROGRAM SR_Main
VAR
    original: FinalBlock;
    someVar: DINT := 5;
    wrap: Wrapper(original);
    getVar: DINT;
END_VAR

wrap(someVar := someVar); // use this instead of "original(someVar := someVar);"
getVar := wrap.GetSomeVarMethod(); // getVar = 5

编辑:如果您要使用引用(或指针),需要注意的一件事是无效引用异常。你会在这两种情况下得到它们:

  1. 如果在设置变量之前访问它:
getVar := wrap.GetSomeVarMethod(); // calling this'll try to access someVar
wrap(someVar := someVar);
  1. 您忘记了应该使用包装器而不是被包装的对象:
original(someVar := someVar); // should have called "wrap(someVar := someVar);" instead!
getVar := wrap.GetSomeVarMethod();

为避免这种情况,您可以尝试:

  1. 在访问它之前检查参考:
METHOD GetSomeVarMethod : DINT

IF __ISVALIDREF(THIS^.someVar) THEN
    GetSomeVarMethod := THIS^.someVar;
ELSE
    GetSomeVarMethod := -1;
END_IF

或者

TYPE OPTIONAL
STRUCT
    value: DINT;
    error: BOOL;
END_STRUCT
END_TYPE

METHOD GetSomeVarMethod : OPTIONAL

IF __ISVALIDREF(THIS^.someVar) THEN
    GetSomeVarMethod.value := THIS^.someVar;
ELSE
    GetSomeVarMethod.error := TRUE;
END_IF

但是,如果用户忘记调用wrap(someVar := someVar);并且只调用过,original(someVar := someVar);那么 someVar 将永远无效。

  1. 不要将对象传递给包装器,而是让包装器完全创建和管理对象:
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
    someVar: DINT;
END_VAR
VAR
        // with the 'no_init' attribute, we can let our FB_Init method initialize this object using user given arguments.
        // If FinalBlock doesn't have any custom initialization arguments, you can skip this attribute and the FB_init code below.
        {attribute 'no_init'}
    _wrapped_obj: FinalBlock;
END_VAR

_wrapped_obj(someVar := someVar);

//////

METHOD FB_Init: BOOL
VAR_INPUT
    bInitRetains: BOOL;
    bInCopyCode: BOOL;
    // FinalBlock initialization arguments
END_VAR

THIS^._wrapped_obj.FB_Init( (* initialization arguments *) );

无论哪种方式,我都建议您提供有关如何正确使用包装器并避免错误的良好文档。

或者,如果您想要将功能块传递给一个函数并访问该函数内的 VAR_IN_OUT 变量的值,您可以将该值与功能块一起传递(因为如果它是 VAR_IN_OUT,您应该可以访问反正原创):

VAR
    original: FinalBlock;
    someVar: DINT := 5;
END_VAR

original(someVar := someVar);
getVar := SomeFunction(obj := original, someVar := someVar);

或者:

TYPE Bundle :
STRUCT
    obj: REFERENCE TO FinalBlock;
    someVar: REFERENCE TO DINT;
END_STRUCT
END_TYPE

//////

VAR
    original: FinalBlock;
    someVar: DINT := 5;
    bun: Bundle(obj := original, someVar := someVar);
END_VAR

original(someVar := someVar);
getVar := SomeFunction(bundle := bun);
于 2021-12-16T14:49:22.857 回答