5 引用(References)
先说一下我自己的感觉,在TIA博途V13 SP1(具体是哪一个版本忘了)以前是没有引用(References)的,指正介绍都是围绕着Variant进行的。后续的版本才推出了引用(References),原来为什么没有推出?要不就是计划有,但是没有开发出来;要不就是市场有新的需求,新加入的功能。既然推出引用(References),就有它的应用地方,例如程序块的开发者声明一个INOUT参数,数据类型为Variant,如果程序块的开发者想修改赋值变量中的一个元素怎么办? 参考上面Variant部分,是不是先使用typeof判断类型,然后使用指令VariantGet读出并复制到一个类型相同的副本中,再修改变量中一个元素(例如PLC数据类型),最后使用指令VariantPut写出,问题出现了,写的时候只写其中一个元素,其它元素怎么办?一定是使用读出的值替代,如果外面的值发生变化,就会将过程值覆盖。怎样才能修改其中一个元素又不覆盖变量中其它元素的值呢?只有在INOUT参数中声明一个复制类型(不能是引用类型)的变量才可以,例如DINT、real类型变量,这样将使程序的灵活性降低(不能使用Variant了),为了解决这样的问题才推出了引用(References)类型(只代表我的理解呀!)。好了下面开始介绍引用(References)了。
引用(References)是一种变量,不含任何值却指向其它变量的存储位置,参考图34。 通过引用,可在块外进行变量传递。因此,可直接修改变量的值,而无需创建变量副本。
图 34
使用加粗标记的就是引用(References)的特点。
5.1 引用声明
使用引用限制条件还是比较多的,看看下面的限制条件:
1:必须事先声明,也就是创建一个引用变量。引用可在优化访问的函数或函数块的接口中声明。并且地址区必须是临时变量区,例如:
● FC:Input, Output, Temp, Return
● FB:Temp
● OB:Temp
要进行引用声明,可使用关键字“REF_TO”指定被引用变量所需的数据类型。参考图35。
图 35
2:引用与被引用的数据类型必须相同,应用的数据类型如下:
● 位字符串(BYTE 、WORD、 DWORD、LWORD)
● 不支持 BOOL 引用。
● 整数
● 浮点数
● 字符串
● 不支持针对字符串的长度声明。
● IEC 定时器
● 支持 IEC_TIMER 和 IEC_LTIMER 引用。 不支持派生数据类型引用,例如 TON。
● IEC 计数器
● 支持 IEC_COUNTER/IEC_UCOUNTER、IEC_SCOUNTER/IEC_USCOUNTER、IEC_DCOUNTER/IEC_UDCOUNTER 引用。不支持派生数据类型引用,例如 CTU。
● PLC 数据类型 (UDT)
● 系统数据类型 (SDT)
● 已声明的数据类型的 ARRAY
● 不支持 ARRAY[*] 引用。不支持没有声明的数据类型的ARRAY,例如ARRAY of
● REF_TO<数据类型>。
5.2 变量的引用
引用声明只是创建了一个变量和引用的数据类型,没有指向有效的存储器,系统使用值NULL对其进行初始化,如果在编程中使用将导致编程错误,所以必须为引用分配实际地址。
引用只能指向优化的全局 DB 或FB块静态变量中的数据。
使用关键字“REF()”,可将声明的引用指向变量,如图36所示。LAD和SCL两种编程语言都支持变量的引用。
图 36
5.3 解引用
引用指向变量只是指向变量的实际地址或者物理地址,要读取或写入一个被引用变量的值,则可使用插入符号“^”,这种访问方式又称为“解引用”。解引用的使用参考图37所示,程序块运行一次,“c”的值为15,此时“a”的值为10,在第二条语句中,将“My refint”指向变量“a”(引用),在第三条语句中解引用变量“My refint”并赋值20,这样20赋值给引用变量“My refint”, 引用变量“My refint”指向变量“a”的地址,实际上是将20传递到变量“a”,这时“c”就变为25了,第四、五条语句作用相同。如果程序再次执行一次,第一条语句中“c”的值将被25替代。
图 37
引用指向的是变量的地址,而解引用得到变量的值,在应用中容易混乱出错,例如语句:#ref_int1 := #ref_int2; 这条语句是将#ref_int2引用的变量地址赋值给#ref_int1,如果#ref_int2没有分配地址,相
当于将NULL赋值给NULL,程序将报错。引用也可以应用到函数、函数块间的数据传递。例如FC1(Block_1)中使用接口声明计算A+B=C,在OB中调用FC1并赋值,示例参考图38,
图 38
可以看到调用FC1时为接口声明A和B指向了实际地址,但是C有问题,赋值的方向反了,可以在FC1直接为引用C分配变量,或者不使用引用,示例如图39。
图 39
5.4 引用与VARIANT
引用声明时,使用关键字“REF_TO”指定被引用变量所需的数据类型必须是确定的,如果是数据类型是VARIANT,则不能使用上面介绍的引用方式,可以使用赋值尝试“?=”,将 VARIANT 数据类型的变量分配给一个引用。由于引用是后期开发的指令,与VARIANT数据类型的结合使用使开发更加灵活和简单。
VARIANT可以读出输入变量的数据类型,然后通过VariantGet指令复制到一个类型相同的副本中进行分析判断,使用赋值尝试“?=”,将 VARIANT 数据类型的变量分配给一个引用将使这样的应用变得更加简单,参考图40。
图 40
引用声明一个变量“Ref_motorA”,指定的数据类型为“REF_TO "Motor_A"”("Motor_A"为PLC数据类型),通过赋值尝试“?=”而不是关键字“REF()”,将VARIANT变量分配给“Ref_motorA”,如果分配成功,则变量“Ref_motorA”不等于 “NULL”,否则等于“NULL”。然后将“电机A”赋值给变量“#Ref_motorA^.Info”。
赋值尝试“?=”的方式也支持LAD编程语言,如图41所示,使用LAD编程语言调用赋值尝试指令“?=”,如果分配成功,ENO等于1,否则等于0。
图 41
上述的应用如果使用先前的方法:首先需要使用指令type of判断数据类型,然后使用VariantGet指令将数据复制到一个副本中,修改以后再使用VariantPut指令写回(开头应用介绍的使用场景),使用赋值尝试“?=”和引用的方式,使函数和函数块的开发变得更加方便。
好了,所有变址寻址的方式已经介绍完了,希望大家可以受益。上面的描述大部分是自己多年的总结和目前学习的心得,不足之处还请大家指正和补充,也希望大家提供一些应用的案例(自己的案例都是猜想,有可能不符合实际),一起探讨,分享给其他工程师学习使用!
--------------------------------------------------------------------------------------------------------
上一篇:【8】Variant的使用——从S7-300_400到S7-1500看变址寻址的改变系列故事之八
汇总帖:技术Π活动故事、视频与案例分享汇总