技术论坛

 回复:应用探讨——PLC 数据类型探讨

返回主题列表
作者 主题

总坛主
西门子官方工程师西门子官方工程师

经验值:23725
发帖数:3679
精华帖:8
楼主    2013-10-15 09:38:49
主题:应用探讨——PLC 数据类型探讨
各位同学是否有以下疑惑:
1. INT数据类型与WORD 数据类型有何区别?DINT与TIME呢?
2. S5 TIME数据类型结构是什么样的?怎样自行修改或生成符合S5 TIME数据类型的值?
3. 仪表传送一组流量数值,是用字符串方式发送,接收到数值后,怎样还原为浮点数?
4. MOVE指令与数据类型转换指令怎样区分?都有什么样的应用场合?
5. 隐式转换和显示转换是什么含义,在TIA 博途中,设置IEC检查对数据类型转换会有什么影响。
另外,复杂数据类型的应用,如:STRUCT与UDT的应用与区别、*数组、ANY数据类型,各种数据类型的存储与寻址方式,相互转换也在本话题讨论范围之内,大家不要吝啬笔墨,踊跃发言,谈谈应用过程中的疑惑与认识,希望大家收获多多!


活动奖励:
此次集中交流将持续至11月12日,其中所有精华帖作者将获得加倍精华奖励积分;最终所有有效留帖的网友将获得加倍发帖积分。更多积分带给您更多奖品兑换的自由。
对于有突出发言贡献的网友可获得金币奖励,可以在当前的兑换奖品中兑换奖品。
交流结束后也将专门整理重要内容,供广大网友分享参考。
预祝大家交流愉快,收获丰富!
Automann
至圣

经验值:18299
发帖数:6168
精华帖:137
5楼    2013-10-15 20:47:59
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
字符串转换为浮点数的方法
可以用程序编辑器的IEC库中的FC39 STRNG_R,将字符串转换为REAL数据类型格式变量。
用IEC库中的FC30 R_STRNG,可以将REAL格式的变量转换为字符串。
字符串由符号、小数点前的1位数字、小数点、小数点后的7位数字、E和2位指数数字字符组成。
下面是一个例程:
在DB1中定义字符串STR1[14],下面是OB1中的程序:
CALL "R_STRNG" //调用FC30,将REAL格式变量转换为字符串
IN :=1.234567e+003
RET_VAL:=DB1.STR1

CALL "STRNG_R" //调用FC39,将将字符串转换为REAL格式变量
S :=DB1.STR1
RET_VAL:=MD0

由监控可知FC30将1.234567e+003转换后,DB1.STR1中的字符串为’+0.1234567E+04’。用FC39将字符串DB1.STR1转换后,MD0中的浮点数为1.234567e+003。
追求完美
剑忠
奇侠

经验值:9641
发帖数:622
精华帖:57
8楼    2013-10-16 17:29:32
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
一、在S7编程中字符类型[CHAR]使用比较少见,但在一些与条码扫描的通讯设备中却较为常见,例如工装线产品质检和计数或商场收银系统。
二、这类条码扫描设备通常先与PLC进行RS232C或RS485串口通讯后读入CHAR数据类型,然后经组合和转换后,在触摸屏Touch中显示。
三、其实CHAR数据类型处理很简单,具体使用事项和方法如下:
1、首先CHAR字符采用ASCII编码;
2、其次CHAR字符占用一个Byte;
3、因此将读取的CHAR字符存放至定义为CHAR类型的存储区变量中,例如MB2→CHAR即可;
4、如果要对定义的CHAR类型的变量赋值,需对输入的字符常量加一对单引号,例如:'$'、'F'、'【'、'?'。
5、使用效果见以下ASCII码表与程序对照图。
大学之道,在明明德,在亲民,在止于至善。
只求进步
游侠

经验值:547
发帖数:125
精华帖:2
13楼    2013-10-17 14:43:15
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
2. S5 TIME数据类型结构是什么样的?怎样自行修改或生成符合S5 TIME数据类型的值?
1) S5TIME为16位数据,BCD码格式。当使用S5TIME时,最大计时为S5T#2h46m30s(9990s).
格式如:2#0011 1001 1001 1001,即S5T#2h46m30s
10s 9 9 9
第14,13位表示时间基准,00为10ms,01为100ms,10为1s,11为10s.上例为11,即10s时基。
后12位为BCD码表示的时间值,上例为999,则999*10s=2h46m30s.
2)知道S5TIME的格式后,就可以在程序中正确的使用了。常见的如在触摸屏中有个INT变量设定的时间, 在程序中要转换成S5TIME.(INT转S5TIME).
因为S5TIME为BCD码格式,所以要先将INT转BCD(ITB).记得一定要转。可以看3楼的例子。我们也可以 自己编程做一下实验。ITB不写的话就会报错。
L 999 //0000 0011 1110 0111
ITB //0000 1001 1001 1001
L W#16#3000 //0011 0000 0000 0000
OW
T MW 700 //0011 1001 1001 1001 (S5T#2h46m30s)
A M 100.0
L MW 700
SD T 1
3)其他关于INT,TIME和S5TIME的转换见下帖。
http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=4&a_id=898840
所有一切只不过是宇宙整体的彰显和表达!
剑忠
奇侠

经验值:9641
发帖数:622
精华帖:57
16楼    2013-10-17 20:37:37
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
字符串数据类型[STRING]的使用也比较少见,常用于存储消息文本。
关于STRING类型变量使用事项如下:
1、STRING变量字符串以ASCII编码存储每个字符,最大长度256Byte,前两个Byte存储字符串长度信息,所以STRING变量最多包含254个字符。其中第一个Byte存储最大长度;第二个Byte存储实际字符长度。
2、STRING类型的变量可传递至相同类型(即相同的STRING长度)的块参数中,也可以传递至POINTER或ANY类型的FC/FB块参数中。
3、给STRING变量赋值常量需使用一对单引号,例如:'String'、'S7'、'failure_4'。
4、如果用ASCII编码的字符赋值,则该字符也必需使用一对单引号,而如果包含用于控制术语的特殊字符,则必需在字符前添加前缀符号$。例如:$$→美元字符;$P→换页字符;$L→换行字符;$R→回车字符;$T→空格字符。
5、STRING变量定义声明和初始化方法:变量名称:STRING[最大字符数]: '初始化文本',变量定义声明时可以无初始化文本。例如:FALT_SIG:STRING 'Motor failure_4'、Warning:STRING [50] ''。
如果变量定义声明时未指定最大字符数,那么STL/LAD/FBD程序编辑器则自动默认长度最大为254个字符。
6、可使用基本的STL指令访问STRING变量的各个字符。例如:L FALT_SIG[5] //装载变量FALT_SIG的第5个字符,即'r'。
7、还可以使用IEC库的FC功能块实现对STRING变量的访问和处理。
大学之道,在明明德,在亲民,在止于至善。
Automann
至圣

经验值:18299
发帖数:6168
精华帖:137
17楼    2013-10-17 21:36:42
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
数据类型是什么?
数据类型是什么?数据类型是人为规定的数据的属性。在计算机和PLC中,数据实际上以二进制数的形式储存。按长度分为1位、8位、16位、32位的二进制数据。
除了数据的长度,数据类型包含了更多的内容,例如32位的数据类型有双字、32位整数、Time、浮点数、TIME_OF_DAY等。
数据的数据类型需要在符号表、块的局部变量表中定义,因此数据类型是人为指定的数据的属性。
指令和块的输入、输出参数的实参的数据类型必须与对应的形参要求的相同,否则程序将会出错。
OB40的参数OB40_MDL_ADDR的数据类型为WORD,不能直接用于要求数据类型为INT的整数比较指令。怎样解决这一难题呢?在梯形图中,可以用MOVE指令把OB40_MDL_ADDR的值传送给没有定义数据类型的一个绝对地址,例如MW10,MW10就可以用于比较指令了。MW10并没有因此自动获得数据类型INT,只是CPU“认为”MW10中的数据类型是INT,CPU被我们蒙骗了!
我见过不良小贩把白色的小鸡染成五颜六色来骗小孩,放到水里一洗,小鸡的彩色就消失了。如果把小鸡看成数据,染的颜色就是数据类型。把定义了数据类型的数据装入绝对地址MW10或累加器(累加器也是一个特殊的绝对地址),数据类型的属性就被剥去了,只剩下赤裸裸的数据,就像小鸡的颜色被水洗掉了一样。这时就可以把数据当作规定了长度的各种数据类型来使用。
追求完美
氢气
游侠

经验值:441
发帖数:47
精华帖:8
27楼    2013-10-21 16:15:47
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
quote:以下是引用YHKingKong在2013-10-15 13:04:12的发言:
利用MOVE指令,可以自动转换类型。
MOVE DBXX.DBD可以直接复制给MD。

主要是数据处理时,需要数据转换。

LAD中的“MOVE”指令,类似于STL中的装载指令“L”和传送指令"T",是将原数据原封不动的传送给目的地址。举个例子,DB1.DBD0为REAL数据类型(值为1.111),DB1.DBD4是DINT数据类型,使用"MOVE"指令将DB1.DBD0传送至DB1.DBD4中,得到的结果是什么呢?会是“L#1”吗?如果使用指令"ROUND"呢?
结果是使用"MOVE"指令,在DB1.DBD4中得到的结果是数据1.111按照IEE754标准存储的32个Bit组成的DINT值,即L#1066284351,使用ROUNT指令得到的是L#1。所以MOVE指令应理解为按位传送,而非数据类型转换指令。
17楼的小鸡穿衣比喻很形象,一组二进制数究竟是什么,不仅取决于小鸡本身,还取决于它的颜色。
---------------------来自西门子工程师
氢气
游侠

经验值:441
发帖数:47
精华帖:8
35楼    2013-10-22 09:38:22
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
quote:以下是引用Automann在2013-10-21 18:05:16的发言:
quote:以下是引用氢气在2013-10-21 17:09:53的发言:
quote:以下是引用Automann在2013-10-18 07:25:41的发言:
对ANY数据类型的错误理解的分析
最近看到有个下面的帖子(ANY指针可以这么用么?):

各位好,最近学习一下ANY指针,写了段测试代码,但是无法执行,请问是不是ANY指针不能这么使用呢?谢谢!
代码如下:
L P##TEMP0
LAR1
L W#16#1001
T W [AR1,P#0.0]
L W#16#0
T W [AR1,P#2.0]
L W#16#0
T W [AR1,P#4.0]
L DW#16#81000000
T D [AR1,P#6.0]

SET
A [AR1,P#0.0]
= Q 0.0

下面是我的分析:
楼主上面这段代码实际上是在填写ANY的10个字节的值,虽然辛苦,做的却是无用功。问题在于他没有理解ANY的使用方法。
ANY是参数类型,只是用来作块的输入、输出参数。在调用逻辑块时, ANY用于将任意的数据类型传递给声明的形参。ANY的实参可以是单个的任意地址,也可以是一片连续的地址区,例如P#DB1.DBX0.0 INT 50(DB1中从DW0开始的50个整数)。但是ANY的10个字节的值是操作系统根据块的实参的值自动生成的,而不是用户生成的。我们可以用寄存器间接寻址读取ANY的10个字节中包含的大量信息,例如实参的基本数据类型,数据块的编号,重复因子(变量的个数),地址区的起始地址等等。

其实ANY指针的值完全可以由用户自行生成,作为实参传给功能块的输入参数,这样就能实现“变址寻址”。例如使用SFC20将不同DB块的值传递给DB100:
L P##TempAny
LAR1
L W#16#1001 //数据类型BYTE
T W [AR1,P#0.0]
L W#16#10 //重复因子
T W [AR1,P#2.0]
L MW 10 //确定DB块
T W [AR1,P#4.0]
L DW#16#84000000 //DB存储区
T D [AR1,P#6.0]

CALL "BLKMOV"
SRCBLK :=#TempAny
RET_VAL:=MW12
DSTBLK :=P#DB100.DBX0.0 BYTE 10
这样,就实现了将某个DB块中前10个字节传送到DB100中,究竟是哪个DB,完全由MW10决定。关于间接寻址的相关内容,参考论坛其它帖子,或者下载中心文档F0595,这里不做过多讨论。

调用SFC 20,一般我们直接使用SRCBLK的指针格式的实参,DBx是数据块的地址:
CALL "BLKMOV"
SRCBLK :=P#DBx.DBX0.0 BYTE 10
RET_VAL:=MW12
DSTBLK :=P#DB100.DBX0.0 BYTE 10
氢气侠写的一大堆代码也可以实现同样的功能,但是工作量太大,也容易出错,比如说 数据类型BYTE 好像应该是W#16#1002,而不是16#1001。
氢气侠的用法当然也有好处,程序不容易读懂,有一定程度的保密性。

谢谢指正!确实是W#16#1002。
我举这个例子目的是告诉大家ANY的用法,不止局限于以类似“P#DB1.DBX0.0 BYTE 10”这样的格式去使用它。而是要根据ANY数据类型的结构去打造自己的“ANY数据”,此数据在作为参数传递的同时,还可以用于间接寻址。例如上例中,数据源地址不是固定的,究竟是哪个DB块,由MW10决定,而MW10可以是HMI传递过来的数据。比如程序中有90个配方,分别存储与DB1~DB90中,究竟将哪个配方传送至DB100中使用,由MW10(HMI)决定。所以程序这样书写跟保密性无关。
另外ANY的魅力不仅在于“重构”,还在于将其“解析”(通常都是这种用法),“解析”后可以得到其中的地址、长度、数据类型等信息。参考间接寻址的官方连接:
http://support.automation.siemens.com/CN/view/zh/24519683
其中的问题:如何计算ANY 型指针的偏移量或改变指针?
如何设置带有"ANY"或"POINTER"数据类型的功能块?
说明了如何将ANY数据类型“重构”与“解析”。更多间接寻址或ANY数据类型应用也可参考下载中心F0670和F0595或者相关书籍。
关于间接寻址的内容,请大家移步至坛子:主题:应用探讨——西门子指针编程使用探讨
http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=4&a_id=936225&s_id=0&num=142#anch
这里就不做深入探讨了,而是更多关注于数据结构方面的内容。
---------------------来自西门子工程师
Automann
至圣

经验值:18299
发帖数:6168
精华帖:137
50楼    2013-11-08 13:20:44
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
quote:以下是引用氢气在2013-11-08 09:45:47的发言:
我这有几个问题:
1.数组数据类型,初始值是怎么设定?
2.UDT 与 STRUCT的初始值怎么设定,如果改变UDT中的一个变量,那么程序中所有用到此数据类型的地方是否都改变?程序是否能编译通过?怎么处理方便?
3.在FB或者FC的接口参数定义区内,数据类型设定会有Block_FB,Block_FC,Timer,Counter等,在FB的静态变量里,有FB,SFB,作用是什么?
另外,很多工程师会发现在S7-1200和S7-1500中出现了更多的数据类型,如长实数(LReal),DTL(长日期和时间),长定时器(LTime),有用过的将经验分享下,呵呵。

给数组元素赋初值:在ARRAY所在的行的“初始值”列中给数组元素赋初值,各元素的初值之间用英语逗号分隔,例如有6个元素的初值可以写成“22,30,5,0,0,0”。若相邻元素的初值相同可以简写,上述初值可以简写为“22,30, 5,3(0)”。
UDT 与 STRUCT的元素要根据元素的数据类型逐个单独赋初始值。
FB、FC的参数类型Block_FB,Block_FC,Timer,Counter只能作输入参数的数据类型,用来设置定时器、计数器、FB、FC的地址。有了这些参数类型,在FB、FC的内部可以不使用定时器、计数器、FB、FC的绝对地址,保证了逻辑块的可移植性。
FB的静态变量里的FB,SFB(nr是块的编号或地址)用于多重背景。多重背景可以将FB、SFB的背景数据集中到它们所在的FB的背景数据块,从而减少背景数据块的个数。
追求完美
老学童
奇侠

经验值:8218
发帖数:765
精华帖:32
51楼    2013-11-10 15:49:54
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
DATE_AND_TIME类型的理解与实践
DATE_AND_TIME即DT类型是S7复杂类型的一种,由8个字节组成,从字节0到字节7用BCD码分别表示年、月、日、小时、分、秒、毫秒的十分位和百分位值、毫秒的千分位值和周日期(星期几),即:
字节0 -------->年
字节1 -------->月
字节2 -------->日
字节3 -------->小时
字节4 -------->分
字节5 -------->秒
字节6 -------->毫秒的十分位和百分位值
字节7 -------->7~4位为毫秒的千分位值,3~0位为周日期(星期几)
在实际运用中,常常需要将DT类型实参的每个字节进行BCD到INT的类型转换后才能使用,本人通过编辑以下程序增强了对DT类型的理解和运用,本程序完全自行编写并经过仿真验证,在此与大家分享:
OB1:
NETWORK
TITLE =
CALL SFC 1 ( //调用标准功能SFC1读取系统日期和时间
RET_VAL := DB6.DBW 26, //SFC1执行错误代码
CDT := DB6.VAR1_DT); //保存至DB6.DBX0.0开始的8个字节
NETWORK
TITLE =
CALL FC 1 ( //调用FC1进行数据转换
ActualDateTime := DB6.VAR1_DT);
FC1:
L P##ActualDateTime //读取并加载DB6.DBX0.0开始DT数据指针
LAR1 //将指针地址装入地址寄存器1
L 0
L W [AR1,P#0.0] //将指针中的DB块号加载至累加器1
==I
JC _001 //判断是否为DB数据块,否则跳转至_001
T #DB_NO //保存DB块号
OPN DB [#DB_NO] //打开DB块
_001: L D [AR1,P#2.0] //将指针中的区域指针加载至累加器1
LAR1 //将数据源(DT型)区域指针保存至地址寄存器1
LAR2 //将目标(INT型)区域指针保存至地址寄存器2
L 7 //设置循环次数
_002: T MW 10 //循环次数计数
L B [AR1,P#0.0] //依次加载DT数据前7个字节
BTI //BCD到INT转换
T W [AR2,P#8.0] //保存至DB6.DBX8.0开始的7个INT类型数据区
+AR1 P#1.0 //数据源(DT型)区域指针偏移1个字节
+AR2 P#2.0 //目标(INT型)区域指针偏移2个字节
L MW 10
LOOP _002 //通过LOOP循环依次将DT型的每个字节转换为INT型
L B [AR1,P#0.0] //将DT的第8个字节加载至累加器1
SRW 4 //将累加器1的低字右移4位(滤掉‘周日期’的BCD码)
BTI //BCD到INT转换
T W [AR2,P#8.0] //保存至DB6.DBX8.0开始的第8个INT类型数据区
L B [AR1,P#0.0] //将DT的第8个字节加载至累加器1
AW W#16#F //与W#16#F‘字与’(滤掉毫秒千分位BCD码)
+AR2 P#2.0 //目标(INT型)区域指针偏移2个字节
T W [AR2,P#8.0] //保存至DB6.DBX8.0开始的第9个INT类型数据区
BE //块结束
DB6:
DATA_BLOCK DB 6
TITLE =
VERSION : 0.1
STRUCT
VAR1_DT : DATE_AND_TIME ; //实际日期时间
YEAR_I : INT ; //INT类型的‘年’值
MONTH_I : INT ; //INT类型的‘月’值
DAY_I : INT ; //INT类型的‘日’值
HOUR_I : INT ; //INT类型的‘时’值
MINUTE_I : INT ; //INT类型的‘分’值
SECOND_I : INT ; //INT类型的‘秒’值
MILLIS_12_I : INT ; //INT类型的‘毫秒’的十分和百分位值
MILLIS_3_I : INT ; //INT类型的‘毫秒’的千分位值
WEEK_D_I : INT ; //INT类型的‘星期几’值
ERROR : INT ; //SFC1执行错误代码
END_STRUCT ;
BEGIN
VAR1_DT := DT#90-1-1-0:0:0.000;
YEAR_I := 0;
MONTH_I := 0;
DAY_I := 0;
HOUR_I := 0;
MINUTE_I := 0;
SECOND_I := 0;
MILLIS_12_I := 0;
MILLIS_3_I := 0;
WEEK_D_I := 0;
ERROR := 0;
END_DATA_BLOCK


参考:
http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=4&a_id=1071117&s_id=0&num=4#anch
http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=4&a_id=873506&s_id=0&num=35#anch
人的生命似洪水在奔流,不遇着岛屿、暗礁,难以激起美丽的浪花。
老学童
奇侠

经验值:8218
发帖数:765
精华帖:32
53楼    2013-11-12 17:32:01
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
友情提醒:
本人在51楼的原贴存在一些问题,现已在原贴中更正!
主要的问题在DT类型的第7字节和第8字节的理解和程序处理,本人发现很多以往的帖子对此陈述也不是非常清晰:
.xyz(秒)
x..........毫秒十分位值
y..........毫秒百分位值
z..........毫秒千分位值
DT类型的第7字节的BCD码是毫秒的十分位和百分位值
DT类型的第8字节的BCD码7~4位是毫秒千分位值,3~0位是星期几。
人的生命似洪水在奔流,不遇着岛屿、暗礁,难以激起美丽的浪花。
老学童
奇侠

经验值:8218
发帖数:765
精华帖:32
54楼    2013-11-12 19:56:53
精华帖  主题:回复:应用探讨——PLC 数据类型探讨
“DINT和TIME呢?”,我觉得坛主问到的问题一定有其深义,本人就此个问题经过以下思考:
咋一看这两种类型似乎很简单,手册上写的很清楚:
DINT是32位有符号双整数类型,值域:L#-2147483648~L#2147483647
TIME是IEC时间类型,值域:T#-24D_20H_31M_23S_648MS~T#24D_20H_31M_23S_647MS
仔细琢磨觉得真的很有意思,TIME类型在赋值时是按"T#xxDxxHxx...."格式赋值的,而在S7内部其实是:以1毫秒为基本时间单位的32位有符号双整数表示时间值,因此,将TIME的实参赋值给一个TIME的形参后或保存到一个DINT类型的存储单元时,就变成了DINT值,本人用以下程序进行了仿真:
OB1
CALL FC 1
T:=DB1.DBD0
D:=DB1.DBD4
FC1:
L #T //TIME类型
T #D //DINT类型
DB1:
DATA_BLOCK DB 1
TITLE =
VERSION : 0.1
STRUCT
T : TIME := T#1D1H;
D : DINT ;
END_STRUCT ;
BEGIN
T := T#1D1H;
D := L#0;
END_DATA_BLOCK






从以上仿真图片可以看出:
1. TIME类型在S7内部本质上就是一个DINT类型,就像廖老师说的不过是“染成五颜六色的小鸡”;
2. 当将TIME型变量赋值给DINT型变量(见上述程序)应该是隐式转换的一种。
从中也可以体会出IEC TIME的以下优点:
1. 具有唯一的基本时间(1毫秒);
2. TIME实参在赋值给形参后,无需转换就可以直接用其它32位类型一样计算方法进行计算,例如:+D, -D, *D, /D等等;
3.转换其它时间类型非常方便,例如:
L #T //TIME类型
L L#86400000 //一天(24小时)的毫秒值24*3600*1000
/D
T .... //得到的就是‘天’数
求模后的值可以继续计算小时、分、秒等等,实现IEC TIME到其它类型,例如DT类型等,的转换。
人的生命似洪水在奔流,不遇着岛屿、暗礁,难以激起美丽的浪花。
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。