分享

西门子PLC数据类型——指针3

 知行合一5000W 2023-04-12 发布于湖北

有关 VARIANT 的基本信息

说明

VARIANT 数据类型的参数是一个指针或引用,可指向各种不同数据类型的变量。VARIANT 指针无法指向实例,因此不能指向多重实例或多重实例的 ARRAY。VARIANT 指针可以是基本数据类型(例如,INT 或 REAL)的对象。还可以是 STRING、DTL、STRUCT 类型的 ARRAY、UDT、UDT 类型的 ARRAY。VARIANT 指针可以识别结构,并指向各个结构元素。VARIANT 数据类型的操作数不占用背景数据块或工作存储器中的空间。但是,将占用 CPU 上的存储空间。

VARIANT 类型的变量不是一个对象,而是对另一个对象的引用。在函数的块接口中的 VAR_IN、VAR_IN_OUT 和 VAR_TEMP 部分中,VARIANT 类型的单个元素只能声明为形参。因此,不能在数据块或函数块的块接口静态部分中声明,例如,因为各元素的大小未知。所引用对象的大小可以更改。

使用 VARIANT 数据类型时,可为各种数据类型创建通用的标准函数块 (FB) 或函数 (FC)。为此,可使用所有编程语言中的各种指令。在程序创建过程中,可指定该块可处理数据类型。在此,可使用 VARIANT 数据类型对各种变量进行互连。之后,再根据这些变量在块中的数据类型进行响应。调用某个块时,可以将该块的参数连接到任何数据类型的变量。调用某个块时,除了传递变量的指针外,还会传递变量的类型信息。块代码随后可以根据运行期间传递的变量类型来执行。

例如,如果函数的块参数为 VARIANT 数据类型,那么整数数据类型的变量可以在程序中的一个点处传递,而 PLC 数据类型的变量可以在程序中的另一个点处传递。借助 VARIANT 指令,函数随后可以正确响应这种情况,而不会出错。

说明

如果一个数据块最初的数据类型为用户自定义的数据类型 (UDT),那么只能指向完整的数据块。

说明

访问 I/O

只有 S7-1500 模块的 CPU 才能直接读写 I/O 输出或输出中的信号。(<操作数>:P)

下表列出了 VARIANT 指针的属性:

长度(字节)

表示法

格式

输入值示例

0

符号

操作数

'TagResult'

数据块名称.操作数名称.元素

'Data_TIA_Portal'.StructVariable.FirstComponent

绝对

操作数

%MW10

数据块编号.操作数 类型长度

P#DB10.DBX10.0 INT 12 1)

NULL 指针

NULL

1) 如果使用前缀 P#,则只能指向“标准”访问模式的存储区。

数据类型的编码

如果通过 P# 使用绝对寻址,则允许使用以下数据类型:

  • BOOL
  • BYTE
  • CHAR
  • WORD
  • INT
  • DWORD
  • DINT
  • REAL
  • TIME
  • S5TIME
  • DATE
  • TOD
  • DT

示例

以下示例说明了 VARIANT 使用 STL 指令“MOVE:移动值”的工作原理:

STL

说明

CALL MOVE

// 调用指令。

value_type := VARIANT

// 参数 IN 和 OUT 的数据类型

IN := 'Data_TIA_Portal'.StructVariable.FirstComponent

// 从“Data_TIA_Portal”数据块移动操作数“FirstComponent”中的数据。

OUT := 'MotorDB'.StructResult.TagResult

// 从“MotorDB”数据块传送到“TagResult”操作数中。

指针在比较过程中的应用

S7-1200/1500 CPU 中的指针用例(与 S7-300/400 相比)

下表简要列出了 S7-300/400 系列 CPU(ANY 指针)与 S7-1200/1500 系列 CPU 中指针的各种应用及解决方案。

在大多数应用中,S7-1200/1500 系列 CPU 无需使用指针。取而代之的是更为简单的语言资源。

在程序运行时期间只需确定数据类型时,才建议使用 VARIANT 数据类型进行间接寻址。

ANY 指针的用途

在 TIA Portal 中应用时的建议 (S7-1200/S7-1500)

使用指令“BLKMOV:块移动”,在程序中移动任意源和目标数据类型的数据。

在 PLC 数据类型中变量定义。使用指令“Serialize”和“Deserialize”,移动变量。

初始化 ARRAY 结构

使用指令“FILL_BLK:填充块”,初始化或填充 ARRAY 结构。

移动 ARRAY 元素

使用指令“MOVE_BLK:块移动”,将一个 ARRAY 结构中的多个元素内容移到另一个 ARRAY 结构中。

使用结构化数据,优化存储器和性能

使用块接口中的 InOut 部分优化存储器和性能。

更新信息,敬请访问“S7-1200/1500 编程指南”中的《S7-1200/1500 编程指南》

访问 WORD 的各个位/字节

使用“片段访问”

更多信息,请参见“片段访问示例”

确定结构或数据块的长度

使用 ARRAY 并读取其长度:使用指令“CountofElements:获取 ARRAY 元素个数”。该指令只能与数据类型 VARIANT 结合使用。

间接寻址

使用 VARIANT 指针,可对仅在运行过程中已知的数据类型进行间接寻址。使用数据类型 DB_ANY,可对数据块进行间接访问。

VARIANT 指令

VARIANT 指令

TIA Portal 中提供了以下用于处理 VARIANT 的指令:

基本指令

类别

指令

说明

比较器运算

EQ_Type

比较数据类型与变量数据类型是否“相等”

NE_Type

比较数据类型与变量数据类型是否“不相等”

EQ_ElemType

比较 ARRAY 元素数据类型与变量数据类型是否“相等”

NE_ElemType

比较 ARRAY 元素数据类型与变量数据类型是否“不相等”

IS_NULL

EQUALS ZERO 指针查询

NOT_NULL

UNEQUALS ZERO 指针查询

IS_ARRAY

检查 ARRAY

TypeOf

检查 VARIANT 变量的数据类型

TypeOfElements

检查 VARIANT 变量的元素数据类型

移动操作

MOVE_BLK_VARIANT

块移动

VariantGet

读取 VARIANT 变量值

VariantPut

写入 VARIANT 变量值

CountOfElements

获取 ARRAY 元素个数

转换操作

VARIANT_TO_DB_ANY

将 VARIANT 转换为 DB_ANY

DB_ANY_TO_VARIANT

将 DB_ANY 转换为 VARIANT

说明

MOVE、MOVE_BLK 和 MOVE_BLK_VARIANT 之间的区别

  • 可使用“MOVE”指令来复制完整的结构。
  • 可使用“MOVE_BLK”指令来移动具有已知数据类型的 ARRAY 的部分。
  • 仅在您想要移动其数据类型仅在程序运行时期间已知的 ARRAY 的部分时,才需要使用 MOVE_BLK_VARIANT 指令。

可以在信息系统的“基本指令 > 对应编程语言”(Basic instructions > Respective programming language) 下找到有关各种指令的其它信息。

也可以在“扩展指令”(Extended instructions) 下找到同样用于处理 VARIANT 数据类型的其它指令。

VARIANT 指令的应用方式

简介

在下一章中,您将了解可用于 VARIANT 指令的应用选项。

对 VARIANT 指向的变量的数据类型求值

在下表中,您将看到可使用哪些指令来对 VARIANT 指向的变量的数据类型求值:

函数

指令

说明

确定数据类型

TypeOf():检查 VARIANT 变量的数据类型

(该指令仅适用于 SCL,且只能与 IF 或 CASE 指令一起使用。)

可使用该指令将 VARIANT 变量指向的数据类型与任何其它变量的数据类型进行比较。也可以与 PLC 数据类型作比较。

TypeOfElements():扫描 VARIANT 变量 ARRAY 元素的数据类型

(该指令仅适用于 SCL,且只能与 IF 或 CASE 指令一起使用。)

可使用该指令将 VARIANT 变量指向的数据类型与任何其它变量的数据类型进行比较。也可以与 PLC 数据类型作比较。如果 VARIANT 变量的数据类型为 ARRAY,则将比较 ARRAY 元素的数据类型。

EQ_Type:比较数据类型与变量数据类型是否“相等”

NE_Type:比较数据类型与变量数据类型是否“不相等”

可使用该指令将 VARIANT 变量指向的数据类型与任何其它变量的数据类型进行比较。也可以与 PLC 数据类型作比较。

EQ_ElemType:比较 ARRAY 元素数据类型与变量数据类型是否“相等”

NE_ElemType:比较 ARRAY 元素数据类型与变量数据类型是否“不相等”

可使用该指令将 VARIANT 变量指向的数据类型与任何其它变量的数据类型进行比较。也可以与 PLC 数据类型作比较。如果 VARIANT 变量的数据类型为 ARRAY,则将比较 ARRAY 元素的数据类型。

对 ARRAY 元素求值

IS_ARRAY:检查 ARRAY

可使用该指令检查 VARIANT 变量指向的数据类型是否为 ARRAY。

CountOfElements:获取 ARRAY 元素个数

可使用该指令读出该变量中 VARIANT 变量指向了多少个 ARRAY 元素。

可以在信息系统的“基本指令 > 对应编程语言”(Basic instructions > Respective programming language) 下找到有关各种指令的其它信息。

读取 VARIANT 指向的数据

为了能够使用数据,您必须在一个中间步骤中将该数据移到变量中,因为无法直接处理该数据。

指令

说明

示例

结果

VARIANT 指向

目标数据类型

VariantGet:读取 VARIANT 变量值

可使用该指令将单个变量的值移到另一个变量中。这两个变量的数据类型必须匹配。

UDT_1

UDT_1

已执行该指令。

REAL

REAL

DINT

DWORD

该指令未执行。

将数据分配给 VARIANT 变量

无法使用该指令来初始化 VARIANT 变量。因此,在将数据返回到变量时必须已经初始化 VARIANT 变量。请勿使用未初始化的临时 VARIANT 变量。

指令

说明

示例

结果

源数据类型

VARIANT 指向:

VariantPut:写入 VARIANT 变量值

可使用该指令将单个变量的值移到另一个变量中。这两个变量的数据类型必须匹配。

UDT_1

UDT_1

已执行该指令。

REAL

REAL

DINT

DWORD

将不执行该指令,因为数据类型不同。

处理动态 ARRAY 结构

对 ARRAY 元素求值

TypeOfElements():扫描 VARIANT 变量 ARRAY 元素的数据类型

(该指令仅适用于 SCL,且只能与 IF 或 CASE 指令一起使用。)

可使用该指令将 VARIANT 变量指向的数据类型与任何其它变量的数据类型进行比较。也可以与 PLC 数据类型作比较。如果 VARIANT 变量的数据类型为 ARRAY,则将比较 ARRAY 元素的数据类型。

IS_ARRAY:检查 ARRAY

可使用该指令检查 VARIANT 变量指向的数据类型是否为 ARRAY。

CountOfElements:获取 ARRAY 元素个数

可使用该指令读出该变量中 VARIANT 变量指向了多少个 ARRAY 元素。

MOVE_BLK_VARIANT:块移动

可使用该指令移动动态和类型安全(集成类型测试)ARRAY。可以为源和目标 ARRAY 自由选择限值。ARRAY 元素的数据类型必须匹配。

说明

MOVE、MOVE_BLK 和 MOVE_BLK_VARIANT 之间的区别

  • 可使用“MOVE”指令来复制完整的结构。
  • 可使用“MOVE_BLK”指令来移动具有已知数据类型的 ARRAY 的部分。
  • 仅在您想要移动其数据类型仅在程序运行时期间已知的 ARRAY 的部分时,才需要使用 MOVE_BLK_VARIANT 指令。

可以在“移动数据”(Moving data) 编程示例中找到有关使用 MOVE_BLK_VARIANT 指令的其它信息。

初始化 VARIANT

说明

通过在块调用时为 VARIANT 块参数指定一个特定变量,对 VARIANT 数据类型进行初始化。这将形成对所传递变量地址的引用。为此,需在块接口中创建一个 VARIANT 数据类型的块参数。在以下示例中,在 SourceArray 部分中包含两个块参数 DestinationArray 和 InOut。

文章图片1

该示例显示了“移动数据示例”中的部分编程示例。详细的程序代码,请参见“另请参见”。

说明

系统不支持将变量直接传递到 VARIANT 变量中。如,myVARIANT: = #Variable

使用 VARIANT 传递和读取各种数据类型

该示例显示了“移动数据示例”中的部分编程示例。详细的程序代码,请参见“另请参见”。

说明

VARIANT 作为形参

如果将 VARIANT 声明为一个形参,则未写保护的数据将作为实参进行传递。

传递各种数据类型

在以下示例中,将显示多次调用通用的标准函数时如何使用不同变量对 VARIANT 块参数进行初始化:

“FC_PartialArrayCopy”函数将调用两次。通过左侧的调用,将 VARIANT 参数 SourceArray 与“my_struct”数据类型的 ARRAY 互连。通过右侧的调用,将 VARIANT 参数 SourceArray 与 REAL 数据类型的 ARRAY 互连。

文章图片2

读出并检查数据类型

系统目前支持各种不同的比较指令,可读取变量或元素的数据类型,并将其与其它变量或元素的数据类型进行比较。

在下图中,将显示如何使用多个比较指令检查 ARRAY 的元素是否具有相同的数据类型:

文章图片3

仅当 ARRAY 元素的数据类型相同时,才执行 MOVE_BLK_VARIANT 指令。

移动数据的示例

编程示例

在此编程示例中,将移动在生产班次期间为示例收集的数据值以作进一步处理。 收集的数据放在 ARRAY 中。 通过“MOVE_BLK_VARIANT: 移动块”(Move block) 指令,可以动态或以类型安全方式移动整个 ARRAY 或个别 ARRAY 元素。 可以为源和目标 ARRAY 自由选择 ARRAY 限值,这些限值不必匹配。 但是,要移动的数据值的数据类型必须匹配。 该指令在所有编程语言中都可用。

通过 VARIANT 数据类型,也可以使用已创建的程序代码并通过在块调用中指定不同的源和目标区域来移动另一个生产班次的数据。

步骤

  1. 使用 SCL 编程语言创建函数并将其命名为“FC_PartialArrayCopy”。
  2. 按如下方式声明块接口:
文章图片4

3.按如下方式创建 SCL 程序代码:可以找到以下程序代码作为模板。

文章图片5

4.创建 PLC 数据类型“UDT_MyStruct”:

文章图片6

5.创建全局数据块“DB_WithArrays”:


  • 文章图片7

    6.在组织块(例如 OB1)中调用“FC_PartialArrayCopy”函数,并使用 DB_WithArrays 数据块初始化参数。 输入指定的常量:

    文章图片8

    7.也可以使用第三个和第四个 ARRAY(数据类型为 REAL)来代替使用前两个 ARRAY (数据类型为 UDT_MyStruct)。

    文章图片9

    结果

    在程序周期中调用“FC_PartialArrayCopy”块后,会将从第四个元素开始的两个数据值立即从“DB_WithArrays”全局数据块的第一个 ARRAY 复制到该数据块的第二个 ARRAY 中。 复制的数据值将插入到第二个 ARRAY 中(从第四个元素开始)。

    用于复制的 SCL 程序代码:

    SCL

    IF IS_ARRAY(#SourceArray) AND TypeOfElements(#SourceArray) = TypeOfElements(#DestinationArray) THEN

    #Error := MOVE_BLK_VARIANT(COUNT := #Count, SRC := #SourceArray, SRC_INDEX := #SourceIndex,

    DEST => #DestinationArray, DEST_INDEX := #DestinationIndex);

    END_IF;

    #FC_PartialArrayCopy := #Error;

    编程队列 (FIFO) 的示例

    编程示例

    在以下示例中,您编写了一个环形缓冲区,该缓冲区包含一个 ARRAY,并且根据 FIFO 原理进行读写。该程序代码有一个读取 VARIANT 指针和一个写入 VARIANT 指针。通过 VARIANT 指令,可以编写稳定的程序代码并确保可靠地进行复制或删除。

    通过 VARIANT 数据类型,程序部分在运行时期间可能会受影响。VARIANT 指针是类型安全指针,即在运行时期间执行类型测试。对于使用块属性“optimized”创建的块,先前使用 ANY 指针编写的子函数现在可以使用 VARIANT 指针进行解析。可使用 VARIANT 数据类型将结构传送到系统函数块。

    步骤

    1. 创建 SCL 函数块并将其命名为“FIFOQueue”。
    2. 按如下方式声明块接口:
    3. 声明
    4. 参数
    5. 数据类型
    6. 注释
    7. Input
    8. request
    9. BOOL
    10. 当“request”参数中检测到信号上升沿时,将执行该指令。
    11. mode
    12. BOOL
    13. 0 = 返回环形缓冲区的第一个条目。
    14. 1 = 条目被写入环形缓冲区的最后一个位置。
    15. initialValue
    16. VARIANT
    17. 环形缓冲区的 ARRAY 被初始化的值。
    18. Output
    19. error
    20. INT
    21. 错误信息
    22. InOut
    23. item
    24. VARIANT
    25. 从环形缓冲区中返回或写入到环形缓冲区的条目。
    26. buffer
    27. VARIANT
    28. 用于环形缓冲区的 ARRAY。
    29. Static
    30. edgeupm
    31. BOOL
    32. 保存上一次查询的 RLO 的边沿存储位。
    33. firstItemIndex
    34. INT
    35. 环形缓冲区中最旧条目的索引
    36. nextEmptyItemIndex
    37. INT
    38. 环形缓冲区中下一个空闲条目的索引
    39. Temp
    40. edgeup
    41. BOOL
    42. 边沿检测的结果
    43. internalError
    44. INT
    45. 错误信息
    46. newFirstItemIndex
    47. INT
    48. 可变下标
    49. newNextEmptyItemIndex
    50. INT
    51. 可变下标
    52. bufferSize
    53. UDINT
    54. 环形缓冲区中 ARRAY 元素的数量
    55. 在“FIFOQueue”函数块中创建以下程序代码:

    (* 该程序代码部分仅在信号上升沿后执行一次。如果逻辑运算结果的信号状态没有改变,则将“FIFOQueue”FB 的程序执行将终止。 *)

    #edgeup := #request & NOT #edgeupm;

    #edgeupm := #request;

    IF NOT (#edgeup) THEN

    RETURN;

    END_IF;

    // ------验证所有参数输入是否均有效。----

    (* 该程序代码部分检查环形缓冲区是否为 ARRAY。如果是的话,将读取 ARRAY 元素的数量。如果不是 ARRAY,程序执行将在该点终止,并输出错误代码“-10”。*)

    IF NOT (IS_ARRAY(#buffer)) THEN

    #error := -10;

    RETURN;

    ELSE

    #bufferSize := CountofElements(#buffer);

    END_IF;

    (* 该程序代码部分将检查 ARRAY 元素的数据类型是否匹配条目的数据类型(变量 #项目)。如果数据类型不匹配,则程序执行将在该点终止,并输出错误代码“-11”。*)

    IF NOT (TypeOf(#item) = TypeOfElements(#buffer)) THEN

    #error := -11;

    RETURN;

    END_IF;

    (* 该程序代码部分将检查环形缓冲区的初始值是否匹配条目(变量 #项目)。如果数据类型不匹配,则程序执行将在该点终止,并输出错误代码“-12”。*)

    IF NOT (TypeOf(#item) = TypeOf(#initialValue)) THEN

    #error := -12;

    RETURN;

    END_IF;

    (* 该程序代码部分将检查变量索引是否在 ARRAY 限值之内。如果不是,程序执行将在该点终止,并且输出错误代码“-20”或“-21”,具体取决于索引。*)

    IF (#nextEmptyItemIndex >= #bufferSize) THEN

    #error := -20;

    RETURN;

    END_IF;

    IF (#firstItemIndex >= #bufferSize) THEN

    #error := -21;

    RETURN;

    END_IF;

    //-----------程序代码执行,具体取决于模式参数-------------

    // 指令的执行取决于模式参数的信号状态。

    IF #mode = 0 THEN

    // 如果模式参数的信号状态为“0”,将返回传递的环形缓冲区的第一个条目。

    (* 该程序代码部分检查环形缓冲区是否为空。如果是,程序执行将在该点终止,并输出错误代码“-40”。*)

    IF (#firstItemIndex = -1) THEN

    #error := -40;

    RETURN;

    END_IF;

    // 该程序代码部分将返回环形缓冲区的第一个条目。

    #internalError := MOVE_BLK_VARIANT(SRC := #buffer,

    COUNT := 1,

    SRC_INDEX := #firstItemIndex,

    DEST_INDEX := 0,

    DEST => #item);

    IF (#internalError = 0) THEN

    (* 该程序代码部分检查环形缓冲区是否包含 ARRAY 元素。如果是,则传递第一个条目,且索引递增 1。*)

    #internalError := MOVE_BLK_VARIANT(SRC := #initialValue,

    COUNT := 1,

    SRC_INDEX := 0,

    DEST_INDEX := #firstItemIndex,

    DEST => #buffer);

    // 该程序代码部分将计算第一个条目的新索引。

    #newFirstItemIndex := #firstItemIndex +1;

    #newFirstItemIndex := #newFirstItemIndex MOD UDINT_TO_INT(#bufferSize);

    // 该程序部分将检查环形缓冲区是否为空。

    IF (#nextEmptyItemIndex = #newFirstItemIndex) THEN

    // 如果环形缓冲区为空,索引将被设置为 0。

    #firstItemIndex := -1;

    #nextEmptyItemIndex := 0;

    ELSE

    // 第一个条目的索引已更改。

    #firstItemIndex := #newFirstItemIndex;

    END_IF;

    END_IF;

    ELSE

    // 如果模式参数的信号状态为“1”,条目将写入到传递的环形缓冲区中。

    (* 该程序代码部分检查环形缓冲区是否已满。如果是,程序执行将在该点终止,并输出错误代码“-50”。*)

    IF (#nextEmptyItemIndex = #firstItemIndex) THEN

    #error := -50;

    RETURN;

    END_IF;

    // 该程序代码部分会将条目写入环形缓冲区中。

    #internalError := MOVE_BLK_VARIANT(SRC := #item,

    COUNT := 1,

    SRC_INDEX := 0,

    DEST_INDEX := #nextEmptyItemIndex,

    DEST => #buffer);

    IF (#internalError = 0) THEN

    // 该程序代码部分会使索引加 1,并计算新的空条目索引。

    #newNextEmptyItemIndex := #nextEmptyItemIndex +1;

    #newNextEmptyItemIndex := #newNextEmptyItemIndex MOD #bufferSize;

    #nextEmptyItemIndex := #newNextEmptyItemIndex;

    (* 该程序代码部分会检查“#firstItemIndex”变量有哪些索引。如果数字为 -1,环形缓冲区将初始化,条目将写入到环形缓冲区中。这也正是必须为变量分配“0”的原因所在。*)

    IF (#firstItemIndex = -1) THEN

    #firstItemIndex := 0;

    END_IF;

    END_IF;

    END_IF;


    //-------------------------局部错误处理
    ----------------------------

    (* 该程序代码部分将检查是否出现局部错误。如果是,程序执行将在该点终止,并输出错误代码“-100”。*)

    IF (#internalError > 0) THEN

    #error := -100;

    RETURN;

    END_IF;

    // 如果在程序执行期间没有出错,将输出错误代码“0”。

    #error := 0;

    结果在程序中运行 FIFO 队列的位置调用 SCL 函数块。

      本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
      转藏 分享 献花(0

      0条评论

      发表

      请遵守用户 评论公约

      类似文章 更多