• {{item.name}}
{{item.name}}
{{item2.name}}
更多
常问问题

西门子STL间接寻址常问问题集

star star star star star
4.0 分
  • 软件编程
文档编号:F0595| 文档类型:常问问题| 发布时间:2024年02月02日
  • 0
  • 1322
  • 7293
内容预览: 描述: 间接寻址可以实现程序执行时动态修改程序变量的地址和内容,从而有效地提升程序的灵活性和适用范围,但是由于地址值只会在运行时才可以确认,因此错误的间接寻址会导致错误的结果甚至导致程序的异常响应,工程师需要正确的使用间接寻址,必须避免一些常见的问题,本文使用问答的方式为学习和使用间接寻址功能的工程师参考。 ......

1.1如何获得指针或者间接寻址有关的信息?
指针的类型包括16位指针、32位指针、Pointer(6Byte)和Any(10Byte)。16位指针用于定时器、计数器、程序块的寻址;32位指针用于I/Q/M/L/数据块等存储器中位、字节、字以及双字的寻址,其中第0~2位表示位地址(0~7)、第3~18位为字节地址,其余位未定义;Pointer和Any一般应用在复杂数据类型(比如Date_and_Time /Array/String等)在FB、FC之间的传递。而Any可以看做是对Pointer的延伸,因为由10Byte组成的Any中Byte4~Byte9就是一个Pointer。
了解指针的格式十分重要,为正确使用指针,应阅读如下内容:
1、 "SIMATIC Programming with STEP 7 V5.5" 05/2010 第27.3.4章 参数类型
2、文档:1008用于S7-300 和S7-400 的语句表(STL)编程
3、文档:F0215,S7-300和S7-400寻址

1.2为什么语句 LAR1 P##PointerInput 在一个函数(FC)中是无效的,然而,同样的语句在一个功能块(FB)中是有效的?
在FC被调用时,复杂数据类型例如指针是被复制到调用者的临时变量区中,在FC内部对此V区地址直接取址放入到地址寄存器AR1或AR2是不被编译器规则接受的(导致MC7寄存器信息过长),也就是说在FC内部通过P#进行地址寄存器取址仅能支持Temp临时变量。因此如果需要在FC中操作指针等复杂输入输出变量地址需要使用累加器进行中转。
考虑到程序的一致性、遵守编译器规则和STL手册中LAR1指令说明,建议用户使用如下指令操作:
L P##PointerInput
LAR1

1.3 STEP 7 中哪些操作会覆盖DB/DI寄存器或者地址寄存器AR1/AR2的内容?
下面说明了可能引起DB/DI寄存器或者地址寄存器AR1/AR2内容改变的一些操作:

  • DB寄存器和AR1受到影响的操作
    1. 使用完整的DB路径(如L DB20.Val)或者调用FC/FB时使用DB块完整地址作为其参数,则DB寄存器内容被覆盖。
    例如在OB1中调用FC1后,DB寄存器变成20。
    OPN DB1
    Call FC1
    Input(bit):DB20.DBX0.2
    因此在编程的时候,OPN 指令打开数据块,通过DBX x.y的方式访问其中内容, 但是如果在打开数据块后DB寄存器的内容被修改了,则DBX x.y的方式访问变量则 会访问到错误的地址。可以通过使用符号寻址的方式或者使用完整路径编程避免,当 然重新使用 OPN指令也是可以的。
    2. 调用FC时使用string, array, structure ,UDT作为其形参或者调用FB时使用string, array, structure 或者UDT作为其in out形参,在FC/FB程序中访问这些地址则AR1寄存器内容被覆盖,因此当使用AR1进行间接寻址时需要注意AR1内容的正确性。
  • AR2地址寄存器和DI寄存器在FB中作为参数和静态变量的基址寻址使用。AR2和DI如果被修改,会影响FB的参数访问,如果希望在FB中使用DI寄存器或者地址寄存器AR2,必须预先保存它们中的内容,并在使用后恢复它们,例如:
    TAR2 #AR2_SAVE; //AR2寄存器状态保存到#AR2_SAVE
    L                     DINO;
    T                     #DB2_SAVE; //DI寄存器状态保存到#DB2_SAVE

User Program

LAR2 #AR2_SAVE; //AR2寄存器恢复到使用前状态OPN DI [#DB2_SAVE]; //DI寄存器恢复到使用前状态

1.4 如何得到多重背景FB中的变量在背景DB里的绝对偏移量呢?
可以用下面的方法处理:
TAR2 (得到多重背景FB在背景DB里的偏移地址)
AD DW#16#00FFFFFF (屏蔽掉存储区ID,可参考32位指针格式)
L P##Variable (得到变量在多重背景FB里的地址)
+D (多重背景FB的偏移地址与变量在多重背景FB里地址相加,即得到实际绝对偏移量)
LAR1
上述语句就是就得到了变量在背景DB中的绝对偏移量,从而供后续程序处理。

1.5如何在程序中使用ANY 型指针?

简要说明如下:
L             P##Input                 //指向存储地址指针Input首地址
//这个参数是一个Any类型,P##Input指向参数Input的值所在地址,这就是指针的指针
LAR1                                                                 //装载到地址寄存器AR1中。
L                 W [AR1,P#4.0]             //打开DB块
// 由Any类型结构知道Any类型的Byte4、Byte5存放的数据块号
T                 #BLOCK_NO
OPN             DB [#BLOCK_NO]                 //如果是DB块,打开指定的DB块。
L                 W [AR1,P#2.0] //判断ANY指针中数据长度
// Any类型的Byte2、Byte3是重复系数,如P#DB1.DBX0.0 Byte 8后面的Byte 8
_001:T             #DATA_LEN                     //通常此处做loop循环!!
L                 D [AR1,P#6.0]                         //找出需要计算数据区的开始地址
// Any类型Byte6~Byte9是32位区域地址
理解Pointer、Any的类型的数据结构,对于正确使用指针有很大帮助。
为正确使用指针,应仔细阅读如下内容:
"SIMATIC Programming with STEP 7 V5.5" 05/2010 第27.3.4章 参数类型

如下的程序实现了SFC20的部分功能,可以作为Any使用的参考。
FUNCTION FC 1 : VOID
TITLE =
VERSION : 0.1
VAR_INPUT
SRCBLK : ANY ;
END_VAR
VAR_OUTPUT
RETVAL : INT ;
DSTBLK : ANY ;
END_VAR
VAR_TEMP
LOOP : INT ;
BLOCK_NO_DB : WORD ;
BLOCK_NO_DI : WORD ;
SRC_ADD : DWORD ;
DST_ADD : DWORD ;
END_VAR
BEGIN
NETWORK
TITLE =
L P##SRCBLK; //读取输入any的首地址
LAR1 ; //装载到ar1
L P##DSTBLK; //读取输出any的首地址
LAR2 ; //装载到ar2
L W [AR1,P#4.0]; //打开DB块
T #BLOCK_NO_DB;
L W [AR2,P#4.0]; //打开DI块
T #BLOCK_NO_DI;
OPN DB [#BLOCK_NO_DB]; //打开DB块
OPN DI [#BLOCK_NO_DI]; //打开DI块
L D [AR1,P#6.0];
T #SRC_ADD; //读取地址
L D [AR2,P#6.0];
T #DST_ADD; //读取地址

L W [AR1,P#2.0]; //读取循环次数
_001: T #LOOP;
L DBB [#SRC_ADD];
T DIB [#DST_ADD]; //赋值
//地址偏移1个字节
L P#1.0;
L #SRC_ADD;
+D ;
T #SRC_ADD;
L P#1.0;
L #DST_ADD;
+D ;
T #DST_ADD;
L #LOOP; //循环
LOOP _001;
END_FUNCTION

1.6 当FC 或FB的输入参数类型为:BLOCK_DB, TIMER或者 COUNTER,如何确定其编号?
例1 :FB 块
FB1 变量声明中定义了“ Timer” 类型的变量“ Time_1” ,在 FB2 中调用 FB1,将定时器“T5”传递给变量“ Time_1”。如图 01 所示程序代码中数值 5 表示“T5”。



图 01 FB中确定定时器编号

在使用多重实例时,需要在图 01 所示程序中增加以下代码:
TAR2 //多重实例偏移地址
LAR1 P##Time_1
+AR1 //多重实例偏移地址与当前地址相加
L W[AR1,P#0.0]
T MW0
例 2 FC
FC1 变量声明中定义了“ Timer” 类型的变量“ Time_1” ,在 FC2 中调用 FC1,将定时器“T8”传递给变量“ Time_1”。如图 02 所示程序代码中数值 8 表示“T8”。


图 02 FC中确定定时器编号

“BLOCK_DB”类型参数在调用 FC 时不可以直接传送给 FC 。如果在调用功能时试图使用此参数类型,将产生如下的错误消息: “非法的参数传输<参数名>” 。“BLOCK_DB”类型参数仅在 FB 被调用(从一个 FB 或 FC 中)时可被传送。 “BLOCK_DB”类型参数不可以在 FC 被调用(从一个 FB 或 FC 中)时可被传送。
相关详细信息可参考 STEP7 在线帮助中“合法的传输参数类型”。
然而,如果希望将 BLOCK_DB 参数类型传送给 FC, DB 块的编号可以通过基本数据类型(例如 WORD)传送。 在下面的例子中,FB100 拥有一个“BLOCK_DB” 的输入参数类型。为了在调用 FC101 时将参数传送给它,“BLOCK_DB”中的 DB 块编号被传送给 WORD 临时变量(DB_No)。当 FC 被调用,数据块序号以一个 WORD 参数类型替代 BLOCK_DB 参数类型。


图 03 FB中确定Block_DB编号

如果 FB 的接口参数能被定义成 WORD 参数类型来传送 DB 块编号,当 FC 被调用时,此参数可以被直接传送给 FC。


图 04 FC中确定DB编号

1.7 参数传递有何限制?
当分配实际参数给形式参数时,可以指定绝对地址、符号名称或常数。STEP 7 限制不同参数的分配。例如,输出和输入/输出参数不能被分配常数值(因为输出或输入/输出参数的目的是改变其值)。这些限定尤其适用于具有复杂数据类型的参数,这些参数既不能分配绝对地址也不能分配常数。下表关明涉及分配给形式参数的实际参数数据类型的限制(--)和允许的分配(由 符号显示)。


图 05 允许的参数传递

详细信息请参考手册中附录27.3.4.8节内容:45531107

1.8 如何传递any参数到其他程序块的参数中?
下面的例子将说明如何为系统功能 SFC50 “RD_LGADR” (读取模块逻辑地址)参数化 ANY 指针。例如对于功能块 FB1,按下述步骤编程:
1. 声明一个输入变量“test”和一个临时变量“test2”为 ANY 类型(图05)。
2. 例如,把 SFC50 的参数“PEADDR”传递给变量“test2”(图06)。
3. 通过判断 ANY 指针“test”,能够传递临时变量“test2”的数据。


图 06 any的临时变量传递

语句 L P##test 先把地址加载到 Accu1,然后通过语句 LAR1 把地址加载到地址寄存器 AR1 (可简写为:LAR1 P##test)。每次读取地址寄存器 AR1 并存储数据(例如 T LW0)到临时变量“test2”(ANY 指针)中。Network 1 中的语句复制数据传送到功能块 FB1 的 ANY 数据到临时变量“test2”。


图 07 临时变量的建立

1.9 如何通过UC或CC指令调用FB?
当使用UC,CC指令调用不带参数的FB可以通过手动修改DI值的方式进行背景数据块的动态分配,此操作相当于模仿系统调用FB的过程。
例如: OPN DI[FB1_DI_Number]
LAR2 P#DBX0.0
UC FB1

关键词
间接寻址,指针,地址寄存器


您可以前往全球资源库查看此文档


剩余80%未阅读,请登录后下载/查看文档

  • 评论
更多
  • 分享

    扫码分享

提示
您即将前往“全球技术资源库”。
“全球技术资源库”的用户名与本地支持中心(下载中心、技术论坛、找答案、1847工业学习平台)的用户名不通用。如果需要在全球技术资源库下载文档,您需要重新登录或注册。
确定

扫码进入移动端

信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。