西门子博途的指针,主要用来进行数据的运算、传递等,因为对于数据运算,西门子的SCL语言最为合适,所以,这里主要用此种语言去描述应用

指针的类型:主要分为any和point

前者为10个字节,后者为6个,

point为安全型的指针

FOR #i := 0 TO #length - 1 DO
    // 通过源指针逐字节读取,并通过目标指针逐字节写入
    %DB[#destPointer] := %DB[#srcPointer];
    
    // 将两个指针都移动到下一个字节
    #srcPointer := #srcPointer + P#1.0;
    #destPointer := #destPointer + P#1.0;

1. 什么是指针 (Pointer)?

简单来说,指针就是一个变量,但这个变量存储的不是实际的数据值,而是另一个变量的内存地址。通过操作指针,你可以间接地读写该地址中存储的数据。这在需要灵活访问不同数据区域、编写通用函数或处理复杂数据结构时非常有用。

在 TIA Portal 中,主要有两种指针类型:

  • POINTER (指针)

  • ANY (可变指针)

这里我们重点讲解 POINTER 类型。

2. POINTER 指针的结构

一个 POINTER 类型的变量占用 6 个字节 的内存,其结构如下:

字节范围内容说明示例 (十六进制)
0-1DB 号 (Data Block Number):如果指针指向一个全局数据块 (DB) 中的地址,这里就是 DB 的编号。如果指向的是其他区域(如 M 区),则为 0。00 0A (表示 DB10)
2-3区域标识符 (Area ID):一个代码,用于指明指针指向哪个存储区。84 00
4-5字节地址和位地址:共 2 个字节(16 位)。其中,高 13 位 表示字节地址,低 3 位 表示位地址。20 03
关键组成部分详解:
  • 区域标识符 (Area ID):
    这是一个非常重要的代码,它定义了你要访问的存储区。常见的有:

    • 16#81:输入映像区 (I)

    • 16#82:输出映像区 (Q)

    • 16#83:位存储区 (M)

    • 16#84:数据块 (DB) / 背景数据块 (DI)

    • 16#85:局部数据 (L)

    • 16#86:调用者局部数据 (V)

    • 16#87:实例数据块 (DB,用于多重背景)

  • 地址指针 (P# Pointer):
    在 TIA Portal 中,我们通常使用 P# 格式的常量来初始化或表示一个地址。这是一种非常直观的表示方法。

    • 格式: P#<存储区><字节地址>.<位地址>

    • 示例:

      • P#M50.0:指向 M 存储区,第 50 个字节,第 0 位。

      • P#DB10.DBX20.5:指向 DB10 中的数据位,第 20 个字节,第 5 位。

      • P#I0.0:指向输入映像区,第 0 个字节,第 0 位。

3. 如何使用 POINTER?

a) 声明指针变量

在块的接口区(如 Input, InOut, Temp 或 Static)中,将变量的数据类型声明为 POINTER。

pascal

// 在 FB/FC 的 Input 或 Temp 区声明
myPointer : POINTER;
b) 为指针赋值

你可以使用 P# 地址常量或另一个 POINTER 变量为指针赋值。

pascal

// 方法 1:使用 P# 常量直接赋值
myPointer := P#M100.0;     // 指向 M100.0
myPointer := P#DB5.DBX30.0; // 指向 DB5 中的 DBX30.0

// 方法 2:通过参数传入指针
// 假设 Input 参数 inParamPointer 的类型也是 POINTER
myPointer := inParamPointer;
c) 通过指针访问数据 (间接寻址)

这是最核心的一步,使用 WORD 类型的存储区前缀配合指针进行读写。

  • 对于位 (Bool): 使用 %X

  • 对于字节 (Byte): 使用 %B

  • 对于字 (Word): 使用 %W

  • 对于双字 (DWord): 使用 %D

语法: [指针变量]

示例: 假设 myPointer 指向 DB5.DBX30.0(一个 Word 类型的数据)

pascal

// 1. 将指针指向的值读取到一个变量中
#myWord := %MW[myPointer]; // 等价于 #myWord := DB5.DBW30;

// 2. 通过指针写入数据
%MW[myPointer] := 16#ABCD; // 等价于 DB5.DBW30 := 16#ABCD;

// 3. 访问一个位
#myBool := %X[myPointer];  // 读取 DB5.DBX30.0 的状态
%X[myPointer] := true;     // 将 DB5.DBX30.0 置位

4. 完整示例:一个通用的数据移动函数

下面是一个使用 POINTER 的 FC,它可以将任意来源的数据复制到任意目标地址。

  1. 创建 FC,命名为 FC_CopyData。

  2. 接口定义:

    • Input

      • srcPointer : POINTER // 源数据起始地址指针

      • destPointer : POINTER // 目标起始地址指针

      • length : Int // 要复制的字节数

    • Temp

      • i : Int // 循环计数器

  3. FC 内部代码 (SCL 语言):

pascal

FOR #i := 0 TO #length - 1 DO
    // 通过源指针逐字节读取,并通过目标指针逐字节写入
    %DB[#destPointer] := %DB[#srcPointer];
    
    // 将两个指针都移动到下一个字节
    #srcPointer := #srcPointer + P#1.0;
    #destPointer := #destPointer + P#1.0;
END_FOR;
  1. 调用示例:

    • 将 DB1 中从 DBX0.0 开始的 100 个字节复制到 DB2 中从 DBX50.0 开始的位置。

    pascal

    #FC_CopyData(
        srcPointer := P#DB1.DBX0.0,
        destPointer := P#DB2.DBX50.0,
        length := 100
    );

5. POINTER 与 ANY 的区别

特性POINTERANY
大小6 字节10 字节
包含信息地址信息 (DB号,区域,字节/位地址)地址信息 + 数据类型和数量 (例如,P#DB1.DBX0.0 Byte 10)
灵活性固定指向一个地址可以描述一个数据区域(如 10 个字节的数组)
常见用途动态访问单个变量或位作为参数传递,处理数据块(如数组、结构体)
赋值P#M100.0P#DB1.DBX0.0 Byte 10 或直接传入 DB1.MyArray

6. 重要注意事项和最佳实践

  1. 有效性检查: 在使用指针前,务必确保指针已被正确初始化并指向一个有效的地址。访问非法地址可能导致 PLC 进入 STOP 模式。

  2. 优化块访问: 对于优化访问的数据块,不能直接使用 P#DB1.DBX0.0 这样的格式,因为优化块的偏移地址在编译时是不固定的。你需要使用 Tag 的绝对地址,或者先将优化块取消优化。

  3. 指针运算: 你可以对指针进行简单的算术运算来移动指针,如 myPointer := myPointer + P#2.0(向后移动 2 个字节)。

  4. 谨慎使用: 指针非常强大,但也容易引入错误,使代码难以调试。只有在必要时(如编写高度通用的库函数)才使用它。

总结

POINTER 是 TIA Portal 中用于实现间接寻址和动态内存访问的强大工具。它通过存储一个 6 字节的内存地址信息,允许你在程序运行时灵活地操作不同存储区中的数据。掌握 POINTER 和 ANY 的区别及用法,是编写高级、通用 PLC 程序的关键一步。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐