作者 | 主题 |
---|---|
空果仁 侠圣 经验值: 4927 发帖数: 210 精华帖: 47 |
楼主 2020-04-02 11:23:53
主题:【9】引用(终结)——从S7-300_400到S7-1500看变址寻址的改变系列故事之九
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看变址寻址的改变系列故事之八
来自西门工业子技术支持 高级专家
|
YiMoon 至圣 经验值: 11064 发帖数: 1222 精华帖: 35 |
4楼 2020-04-02 22:13:39
主题:回复:从S7-300_400到S7-1500看变址寻址的改变-9
Keep calm and carry on!!!
|
YiMoon 至圣 经验值: 11064 发帖数: 1222 精华帖: 35 |
5楼 2020-04-02 22:18:27
主题:回复:从S7-300_400到S7-1500看变址寻址的改变-9 使用DB_Any to variant ,再reference ?= variant,之后再进行操作,这样可以替代variant to DB_ANY,解决了DB块中个别只读数据被写入的问题了。
Keep calm and carry on!!!
|
YiMoon 至圣 经验值: 11064 发帖数: 1222 精华帖: 35 |
6楼 2020-04-02 22:56:52
主题:回复:从S7-300_400到S7-1500看变址寻址的改变-9
Keep calm and carry on!!!
|
CoolCool的猪 至圣 经验值: 16719 发帖数: 1307 精华帖: 2 |
7楼 2020-04-03 23:09:30
主题:回复:从S7-300_400到S7-1500看变址寻址的改变-9 学习了厉害!!
同一个问题ID下,已经先回答此问题的人,如再参考我答案而修改自己答案的,就是王八蛋!
|
空果仁 侠圣 经验值: 4927 发帖数: 210 精华帖: 47 |
9楼 2020-04-04 18:29:56
主题:回复:从S7-300_400到S7-1500看变址寻址的改变-9
来自西门工业子技术支持 高级专家
|