是否可以向功能块添加静态参数?
Is it possible to add static parameters to function blocks?
是否可以编写带有一些静态参数化的功能块?具体来说,我可以制作一个具有静态容量的缓冲区,但不同的实例可以有不同的容量吗?
理想情况下,我会想象一些常量参数,如下所示:
FUNCTION_BLOCK FB_Buffer
VAR_INPUT CONSTANT
StorageSize : DINT;
END_VAR
VAR
Storage : ARRAY [1..StorageSize] OF REAL;
END_VAR
实例化将是这样的:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : FB_Buffer := (StorageSize := 10);
LargeBuffer : FB_Buffer := (StorageSize := 1000);
END_VAR
假设这不可能,那么管理不同功能块实例的不同存储大小的最佳方法是什么?
我将 post 我最不糟糕的解决方法作为答案。
唯一想到的就是做一个抽象的基础FB,让不同的子类定义具体的存储。仍然存在明显的重复和锅炉电镀,但至少比复制粘贴整个 FB 只是为了更改一个数字要好。
基础声明:
FUNCTION_BLOCK ABSTRACT FB_BufferBase
VAR
Storage : POINTER TO REAL;
StorageSize : DINT;
END_VAR
抽象方法声明:
METHOD ABSTRACT GetStorage
VAR_OUTPUT
ZeroElement : POINTER TO REAL;
ElementCount : DINT;
END_VAR
基体代码:
GetStorage (ZeroElement => Storage, ElementCount => StorageSize);
// Do stuff.
小具体声明:
FUNCTION_BLOCK FB_BufferSmall EXTENDS FB_BufferBase
VAR
ConcreteStorage : ARRAY [0..ConcreteStorageSize-1] OF REAL;
END_VAR
VAR CONSTANT
ConcreteStorageSize : DINT := 10;
END_VAR
具体的小方法实现:
ZeroElement := ADR(ConcreteStorage[0]);
ElementCount := ConcreteStorageSize;
(FB_BufferLarge
与 FB_BufferSmall
相同,只是 ConcreteStorageSize
是 1000 而不是 10。)
实例化:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : FB_BufferSmall;
LargeBuffer : FB_BufferLarge;
END_VAR
您对 'Static' 变量的引用让我有点吃惊,因为 VAR STAT 与您想要的不同,并且用于使 FB 的所有实例共享一个公共元素。
的奇观
示例
您必须管理自己的数据访问,确保您不会溢出和所有其他危险的东西,否则这应该按照您发布的答案工作。然后用几个不同的长度初始化这段代码很简单:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : fb_DataArray( 100 );
LargeBuffer : fb_DataArray( 10000 );
END_VAR
// Function block for handling a data array that is generated at boot time
FUNCTION_BLOCK fb_DataArray
VAR
pZeroElem : POINTER TO REAL; // Pointer to the head of the array
ArrayLength : UDINT; // Length of the array in elements
END_VAR
// Do something by indexing through ring
METHOD FB_init : BOOL
// Initialisation method for fb_DataArray, allocates memory space to array
VAR
bInitRetains : BOOL; // required
bInCopyCode : BOOL; // required
Length : UDINT; // Number of element in the array
END_VAR
pZeroElem := __NEW( REAL, Length );
// Generate a pointer to the first element of a dataspace that is precisely big enough for <Length> Real elements.
Method FB_exit
// Needs to be called to de-allocate the memory space allocated in fb_init.
VAR
bInCopyCode : BOOL; // Required
END_VAR
IF pZeroElem <> 0 THEN
// Checks if the pointer is valid, then deletes the allocation
__DELETE( pZeroElem );
END_IF
如果您不想使用动态内存创建数组,同时又想减少项目中的类型数量,您可以使用条件编译指示。
示例:
//Declaration part of MAIN
PROGRAM MAIN
VAR
{define variant_b}
{IF defined(variant_a)}
conveyor_buffer : ARRAY[1..10] OF INT;
sensor_buffer : ARRAY[1..5] OF BOOL;
{ELSIF defined(variant_b}
conveyor_buffer : ARRAY[1..100] OF INT;
sensor_buffer : ARRAY[1..20] OF BOOL;
{END_IF}
fbConveyor : FB_Conveyor;
END_VAR
//Implementation part of MAIN
fbConveyor(buffer:=conveyor_buffer);
//Declaration part of FB_Conveyor
FUNCTION_BLOCK FB_Conveyor
VAR_IN_OUT
buffer : ARRAY [*] OF INT;
END_VAR
VAR_OUTPUT
END_VAR
VAR
length : DINT;
END_VAR
//Implementation part of FB_Conveyor
length := UPPER_BOUND(buffer,1);
然后将缓冲区传递给实际使用它们作为参考的对象。在那些功能块中,您需要检查 UPPER 和 LOWER Bound,以免出现问题。
如果您不喜欢条件编译指示但仍希望您的项目简单明了,您可以在 GIT 存储库中将变体表示为 GIT 个分支。
通过这种方式,您始终知道哪台机器具有哪些功能,并且可以保持干净的结构和体系结构。
另一种策略是使用 Beckhoff 自动化接口自动创建代码并按照您决定的结构构建您的项目。
这是 link:
https://infosys.beckhoff.com/index.php?content=../content/1031/tc3_automationinterface/242682763.html&id=
通过使用自动化接口自动生成代码,您再次降低了在机器操作中注入人为错误的可能性,并将复杂性导出到“更高级别”,使您的系统更加可靠。
因此,您可以使用多种方法来实现可重用的解决方案。
尽管我知道那里有很多复杂的机器,但如果您的 plc 架构变得复杂,可能是时候考虑可以将哪些模块和功能“外包”到更高级别,以坚持 KISS 原则和安全生产在较低的水平。
是否可以编写带有一些静态参数化的功能块?具体来说,我可以制作一个具有静态容量的缓冲区,但不同的实例可以有不同的容量吗?
理想情况下,我会想象一些常量参数,如下所示:
FUNCTION_BLOCK FB_Buffer
VAR_INPUT CONSTANT
StorageSize : DINT;
END_VAR
VAR
Storage : ARRAY [1..StorageSize] OF REAL;
END_VAR
实例化将是这样的:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : FB_Buffer := (StorageSize := 10);
LargeBuffer : FB_Buffer := (StorageSize := 1000);
END_VAR
假设这不可能,那么管理不同功能块实例的不同存储大小的最佳方法是什么?
我将 post 我最不糟糕的解决方法作为答案。
唯一想到的就是做一个抽象的基础FB,让不同的子类定义具体的存储。仍然存在明显的重复和锅炉电镀,但至少比复制粘贴整个 FB 只是为了更改一个数字要好。
基础声明:
FUNCTION_BLOCK ABSTRACT FB_BufferBase
VAR
Storage : POINTER TO REAL;
StorageSize : DINT;
END_VAR
抽象方法声明:
METHOD ABSTRACT GetStorage
VAR_OUTPUT
ZeroElement : POINTER TO REAL;
ElementCount : DINT;
END_VAR
基体代码:
GetStorage (ZeroElement => Storage, ElementCount => StorageSize);
// Do stuff.
小具体声明:
FUNCTION_BLOCK FB_BufferSmall EXTENDS FB_BufferBase
VAR
ConcreteStorage : ARRAY [0..ConcreteStorageSize-1] OF REAL;
END_VAR
VAR CONSTANT
ConcreteStorageSize : DINT := 10;
END_VAR
具体的小方法实现:
ZeroElement := ADR(ConcreteStorage[0]);
ElementCount := ConcreteStorageSize;
(FB_BufferLarge
与 FB_BufferSmall
相同,只是 ConcreteStorageSize
是 1000 而不是 10。)
实例化:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : FB_BufferSmall;
LargeBuffer : FB_BufferLarge;
END_VAR
您对 'Static' 变量的引用让我有点吃惊,因为 VAR STAT 与您想要的不同,并且用于使 FB 的所有实例共享一个公共元素。
的奇观示例
您必须管理自己的数据访问,确保您不会溢出和所有其他危险的东西,否则这应该按照您发布的答案工作。然后用几个不同的长度初始化这段代码很简单:
FUNCTION_BLOCK FB_Usage
VAR
SmallBuffer : fb_DataArray( 100 );
LargeBuffer : fb_DataArray( 10000 );
END_VAR
// Function block for handling a data array that is generated at boot time
FUNCTION_BLOCK fb_DataArray
VAR
pZeroElem : POINTER TO REAL; // Pointer to the head of the array
ArrayLength : UDINT; // Length of the array in elements
END_VAR
// Do something by indexing through ring
METHOD FB_init : BOOL
// Initialisation method for fb_DataArray, allocates memory space to array
VAR
bInitRetains : BOOL; // required
bInCopyCode : BOOL; // required
Length : UDINT; // Number of element in the array
END_VAR
pZeroElem := __NEW( REAL, Length );
// Generate a pointer to the first element of a dataspace that is precisely big enough for <Length> Real elements.
Method FB_exit
// Needs to be called to de-allocate the memory space allocated in fb_init.
VAR
bInCopyCode : BOOL; // Required
END_VAR
IF pZeroElem <> 0 THEN
// Checks if the pointer is valid, then deletes the allocation
__DELETE( pZeroElem );
END_IF
如果您不想使用动态内存创建数组,同时又想减少项目中的类型数量,您可以使用条件编译指示。
示例:
//Declaration part of MAIN
PROGRAM MAIN
VAR
{define variant_b}
{IF defined(variant_a)}
conveyor_buffer : ARRAY[1..10] OF INT;
sensor_buffer : ARRAY[1..5] OF BOOL;
{ELSIF defined(variant_b}
conveyor_buffer : ARRAY[1..100] OF INT;
sensor_buffer : ARRAY[1..20] OF BOOL;
{END_IF}
fbConveyor : FB_Conveyor;
END_VAR
//Implementation part of MAIN
fbConveyor(buffer:=conveyor_buffer);
//Declaration part of FB_Conveyor
FUNCTION_BLOCK FB_Conveyor
VAR_IN_OUT
buffer : ARRAY [*] OF INT;
END_VAR
VAR_OUTPUT
END_VAR
VAR
length : DINT;
END_VAR
//Implementation part of FB_Conveyor
length := UPPER_BOUND(buffer,1);
然后将缓冲区传递给实际使用它们作为参考的对象。在那些功能块中,您需要检查 UPPER 和 LOWER Bound,以免出现问题。
如果您不喜欢条件编译指示但仍希望您的项目简单明了,您可以在 GIT 存储库中将变体表示为 GIT 个分支。 通过这种方式,您始终知道哪台机器具有哪些功能,并且可以保持干净的结构和体系结构。 另一种策略是使用 Beckhoff 自动化接口自动创建代码并按照您决定的结构构建您的项目。 这是 link: https://infosys.beckhoff.com/index.php?content=../content/1031/tc3_automationinterface/242682763.html&id=
通过使用自动化接口自动生成代码,您再次降低了在机器操作中注入人为错误的可能性,并将复杂性导出到“更高级别”,使您的系统更加可靠。
因此,您可以使用多种方法来实现可重用的解决方案。 尽管我知道那里有很多复杂的机器,但如果您的 plc 架构变得复杂,可能是时候考虑可以将哪些模块和功能“外包”到更高级别,以坚持 KISS 原则和安全生产在较低的水平。