关于西门子博途的高级应用-指针的用法
西门子博途的指针,主要用来进行数据的运算、传递等,因为对于数据运算,西门子的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-1 | DB 号 (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,它可以将任意来源的数据复制到任意目标地址。
-
创建 FC,命名为
FC_CopyData。 -
接口定义:
-
Input-
srcPointer:POINTER// 源数据起始地址指针 -
destPointer:POINTER// 目标起始地址指针 -
length:Int// 要复制的字节数
-
-
Temp-
i:Int// 循环计数器
-
-
-
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;
-
调用示例:
-
将
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 的区别
| 特性 | POINTER | ANY |
|---|---|---|
| 大小 | 6 字节 | 10 字节 |
| 包含信息 | 地址信息 (DB号,区域,字节/位地址) | 地址信息 + 数据类型和数量 (例如,P#DB1.DBX0.0 Byte 10) |
| 灵活性 | 固定指向一个地址 | 可以描述一个数据区域(如 10 个字节的数组) |
| 常见用途 | 动态访问单个变量或位 | 作为参数传递,处理数据块(如数组、结构体) |
| 赋值 | P#M100.0 | P#DB1.DBX0.0 Byte 10 或直接传入 DB1.MyArray |
6. 重要注意事项和最佳实践
-
有效性检查: 在使用指针前,务必确保指针已被正确初始化并指向一个有效的地址。访问非法地址可能导致 PLC 进入 STOP 模式。
-
优化块访问: 对于优化访问的数据块,不能直接使用
P#DB1.DBX0.0这样的格式,因为优化块的偏移地址在编译时是不固定的。你需要使用Tag的绝对地址,或者先将优化块取消优化。 -
指针运算: 你可以对指针进行简单的算术运算来移动指针,如
myPointer := myPointer + P#2.0(向后移动 2 个字节)。 -
谨慎使用: 指针非常强大,但也容易引入错误,使代码难以调试。只有在必要时(如编写高度通用的库函数)才使用它。
总结
POINTER 是 TIA Portal 中用于实现间接寻址和动态内存访问的强大工具。它通过存储一个 6 字节的内存地址信息,允许你在程序运行时灵活地操作不同存储区中的数据。掌握 POINTER 和 ANY 的区别及用法,是编写高级、通用 PLC 程序的关键一步。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)