作者 | 主题 |
---|---|
宝冬 至圣 ![]() ![]() 经验值:10158 发帖数:1527 精华帖:30 |
楼主
![]() 主题:不使用UDT的设备FB封装---ModbusRTU通信的温控器的例子 ![]() ![]() 偶然看了万泉河版主的反UDT同盟的帖子。反不反不一定,但觉得万版说得某些方面看有点道理。 以前曾用UDT和模块组合的方式实现过Modbus的通用化。所以想试一试这种相反的做法,还是同样以走ModbusRTU通信的温控器为例,不用UDT,封装成单个的温控器FB,感受一下不同特点。 找了老版本程序中用UDT最少的,改写省事,做个FB,生成5个温控器,测试OK。 每个温控器只要填进去自己的从站号,引入公共资源就行。下图中圈红框的是和公共资源有关的,其它都是设备自己的内部功能。 设备都要使用PLC资源,有的独占,有的共享。Modbus设备就属于需要共享485端口资源的设备。其它通信资源一般也有共享,可以参考这种模式。 给每个设备标准FB匹配一个界面交互标准UDT,这个UDT就和这个FB的接口衔接对应。一种FB一种UDT,成对儿的,从底层到视觉交互。 这种FB内部没有UDT,所以需要用struct来包含很多的等长数组,便于间接寻址关联操作。 原来设备UDT中,与界面交互有关的元素(例如按钮命令、参数设置、数值和状态反馈等等)都变成了FB的接口参数,而原来UDT中其它与内部功能相关的数据,就都被封装到FB内部去了。所以FB封装这种方式,把原来UDT中封装的数据,分成了内外两类,这对某些操作成为一种便利。 FB封装好处是:并行调用,复制即用,设备对外呈单个界面。缺点是:数据结构定义复杂了,逻辑聚合不好分块调试,通用功能块内化不能多个设备间共享了。 亲自动手同样的东西用相反的方式各做一套,还是挺有收获。用不用UDT和是不是单模块封装,是两种相反的策略,互有代价。 模块中采用了优先级策略。多个站点轮询中,任意站点出现写任务,会优先跳转到该站点首先执行写任务。改善界面的敏捷性和用户体验。多个站点如果都有写任务,会按照出现的先后次序来。 |
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
1楼
![]() ![]() ![]()
看下来,我不觉得有什么特别的地方,所谓收之桑榆失之东隅,一味排斥UDT,并不见得是件好事,许多系统定义变量实质也是UDT,只是不是user defined,而是system defined罢了。
用与不用,怎么用还是个权衡吧。至少,我认为使用结构变量是程序模块化与标准化,必不可少的一个手段,另外,除此之外,UDT解决的是一个结构变量重复定义的问题,编程效率的问题
Zane
注册自动化系统工程师
Always save before download
|
will666 奇侠 ![]() 经验值:8872 发帖数:2001 精华帖:12 |
2楼
![]() ![]() 我就是使用UDT定义FB与上位机的接口,这样可以把上位机接口放在统一的DB里面管理,使用起来也非常方便,一个设备用一个输入UDT和一个输出UDT就完成了HMI接口定义。UDT虽然有他的不方便之处,但是我举得用好了可以很方便。
污水处理自控工程师,简称污师。
|
宝冬 至圣 ![]() 经验值:10158 发帖数:1527 精华帖:30 |
3楼
![]() ![]() DB块中:能用就尽量用UDT 非标准FB或FC块中:可以用UDT 标准FB或FC块中:能不用就不用UDT,或者说干脆就不用。 上面做的走ModbusRTU通信的West温控器的FB块,里面没用UDT。它的主要特点是:可以做到使用上的平行调用,非常简单。 用的时候,直接拖拽几个实例。管脚填写各自的从站号,12345,并连接到485模块初始化时候绑定的那个MB-Master背景数据块就可以了。 无需额外搞多个从站之间的轮询控制。这些实例在各自内部会协调依次轮询,而且通信质量不好的(3次错误)淘汰,修复了可召回。根据内部工作模式变化,提供按钮可见性反馈,及内部Pretune停止后的回馈以自动关闭界面按钮。提供每个通信任务成败的历史数据。写数据成功了就不再写,除非数据再变化。因为没有UDT牵绊,复制到哪就可以用。 写优先的操作:不论当前正在执行哪个站点,有任意站点触发了一个或多个写任务操作,会立即切换到该站点执行。 |
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
4楼
![]() ![]() ![]() 这就是打10发子弹要用10杆枪的逻辑。 平行调用是有代价的,内部协调依次轮询从表面上看更罗嗦,而且更死板,换个轮询次序,至少要涉及3个调用的更改。 有多少个通信对象就至少要调用多少次,结果里面还要搞任务轮询,怎能和管你几个站几个任务,我就调用一次相提并论呢,况且没有UDT同样能够实现呀。 其他的就更不是事儿了,什么出错淘汰召回,出错记录,
Zane
注册自动化系统工程师
Always save before download
|
宝冬 至圣 ![]() 经验值:10158 发帖数:1527 精华帖:30 |
5楼
![]() ![]() 拜读过Zane版那个通用的Modbus程序,写得干净利索。但我这个FB是站在一个有完整功能调控界面的具体设备的角度来做的,只是设备内部的执行环节需要Modbus。侧重点不同,它不是面向modbus的。 关于更换从站调度次序,可以从外部通过接口变量,直接临时更改下一个站点的地址。这个FB内部默认是按照从站地址加1的次序,可以用外部设定覆盖,代码加一句就可以。如果寻求长久的,可以用地址数组做接口,数组内的地址次序可以动态更改。 即使内部不加代码,就在当前站点modbus执行过程中临时暴力切换从站,测试中只会引起一次8200错误(Master处于Busy状态,但是Done和Error都不出现,强行断掉造成)。再比如当前站点只有5个,地址是12345,外部输入地址8,整个轮询就会停止,模块的灯灭掉,因为没有这个站点。再改回有效从站中的任意一个,站点会按照默认继续轮询。 这个FB可以从HMI触发内部的master指令断掉,也内置了防轮询卡死的代码。 经过多次测试,胡乱修改从站地,或强行断掉站点内的Master指令,会有一次8200错误,但轮询会依然继续OK。只要报错就好办了,Error是正常处理的一部分,之后就纳入正轨了。 |
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
6楼
![]() ![]() 理解,但程序会趋于复杂,并且牺牲了灵活性及代码效率,虽然还是在标准化,模块化的大框架下。 基于TCP的通信,我觉得问题不大,大不了每次调用就是一个通信链接,但基于458轮询还是差点。
Zane
注册自动化系统工程师
Always save before download
|
一串奇怪的数字 侠士 ![]() 经验值:1326 发帖数:114 精华帖:4 |
7楼
![]() ![]() 我非常赞同Zane版主的观点,没必要一味排斥UDT。 否则就真没有必要排斥UDT。
人生没有边界,一切皆有可能。
|
xiatianyun 侠圣 ![]() 经验值:4857 发帖数:735 精华帖:10 |
8楼
![]() ![]() 我也注意到万版主的观点,不过我不知道他为什么提倡不用UDT,这点不好做判断。 西门子的Step7中,包括博图,关键字struct的使用很特别,只能作为一次定义的类型使用,或者说就不能复用已经定义好的struct,要二次使用只能再次定义。有点类似C中的不声明struct类型时的结构变量定义。这点让人无语。如果需要同类型的struct变量就只能使用UDT了。其实UDT也是ST的关键语言元素,为的就是封装这些自定义类型。 不过使用UDT也带来一些不便,比如说需要配合第三方HMI,很难做到完备支持这一数据类型。不要说第三方,WinCC都做不好。(我初学WinCC,有不对的地方指出来) |
宝冬 至圣 ![]() 经验值:10158 发帖数:1527 精华帖:30 |
15楼
![]() ![]() @Zane和@万泉河,两位版主都是站得高看得远的人,他们都是基于丰富的见识和经历,面对整个行业给出的关于UDT的各自不同看法。这和通常我们大多数所在平台比较狭窄的人也能说出的类似观点,内涵不在一个层面上,是有境界差别的。 反正我自己的经验是没法让我确定性的得出哪种更好的结论,因为没见识过的场景太多,所谓人外有人,天外有天。只能是见招拆招。 |
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
16楼
![]() ![]() ![]() 本来想专门写篇文章来说明UDT的使用,因为发展到现在,对IO的直接访问也可以使用UDT了,我想今后的博途版本还会赋予UDT更多的灵活性与应用场景的,今天先简单的说一下。 主要的依据是出自于手册《 Programming Styleguide for S7-1200/1500 》 的第3.6.4节与第3.6.5节 在编程中使用结构化数据已然成为博途编程的一种大的趋势,这一点是毋庸置疑的。 结构化数据在博途中存在两种形式,一种是STRUCT(结构变量),另一种是UDT(PLC数据类型),显然后者的层面要远高于前者。STRUCT是无法全局存在的,但UDT可以,基于此两者之间的应用就产生了很大的差别。 首先,STRUCT每一个FB/FC/DB中的使用都是新建,虽然可以拷贝,但仍旧属于新建范畴,而UDT是直接的引用; 其次,如果多个FB/FC/DB使用了相同定义的STRUCT,一旦发生修改的需求,就需要逐一到调用的FB/FC/DB中去修改,大项目中调用众多,容易发生遗漏;而UDT则是集中更改,全局自动更新。 结构化数据的使用,一定会涉及到数据的传递,既然是数据传递,就一定有数据传递的双方,也即是说同样的结构数据一定会被使用两次以上;如果是STRUCT则使用多少次,我就要定义多少次,同样发生修改的话,就需要修改多少次;而 UDT则只要定义一次,多次的引用即可,修改也是只要修改一次,自动全部更新。 第三,UDT可以添加到全局库中,实现项目间的重复使用,STRUCT则无法实现;当然,有人会说FB/FC/DB都是可以添加到全局库的,STRUCT在这些块里面,就不用再去操心了,但这只是应用的一个方面而已,实际应用还存在很多其他的可能性,比如功能完全不同的多个块,共同需要使用同一个结构数据。 所以我说,UDT解决的是一个结构变量的重复定义的问题,同时也解决了重复修改的问题,其使用效率要远高于STRUCT
Zane
注册自动化系统工程师
Always save before download
|
万泉河 至圣 ![]() 经验值:28649 发帖数:10889 精华帖:131 |
18楼
![]() ![]() ![]() 观点我全部都支持。 其中前两条,论证了STRUCT完全可以实现所有UDT的功能, 无非在重复数量大的时候,麻烦些。当变更的时候, 需要做重复性工作。 我一直也是这么认为的。 然后最重要的是第三条,讲到了使用UDT的前提:比如功能完全不同的多个块,共同需要使用同一个结构数据。 这里面,几个算多?如果只有2个, 你需要建立一个UDT TYPE, 然后生成2个实例, 是3步工作。 而如果用结构,是两步工作。 修改的时候也是2步。 所以,我认为至少要5个以上的程序块,使用了同样的数据结构,才有价值。 而且不能是INPUT和OUTPUT,因为暂时IO本身还不支持结构, 还需要另外做前处理, 又多了一步。而且这还是面对具体实例的时候。 我的意思是如果我做项目, 遇到同一个数据结构需要重复使用5次以上的时候,我会选择使用UDT, 除此之外不会考虑。 而不幸的是,在我的认知里,工业控制里面用到的数据结构都还算叫简单,我的经历中也基本没遇到过这样的需求。 前面有一个程序框架,配方部分原本有可能使用UDT的,那倒是顺着控制逻辑使用了3-4回,但我暂时没用UDT,还是用结构做的,打算做好了以后再统一改的。可等到调试的时候, 发现数据类型不能通用,有一个块里结构改掉了,增减了内容,所以计划的改造为UDT的设想也泡汤了。 因为,不值得。
微信公众号:PLC标准化编程,ZHO6371995
|
万泉河 至圣 ![]() 经验值:28649 发帖数:10889 精华帖:131 |
19楼
![]() ![]() 我也提醒大家, 不要误解了数据类型实例的数量,比方说你项目里面有用到了20台伺服,你就觉得你的数据结构使用了20次,所以用struct效率低不划算, 认为要用UDT。 我建议你这个时候应该反思下,是不是应该着重于建立个通用的程序功能,提高逻辑的通用性,而不是只看到了数据结构的通用性。
微信公众号:PLC标准化编程,ZHO6371995
|
一串奇怪的数字 侠士 ![]() 经验值:1326 发帖数:114 精华帖:4 |
20楼
![]() ![]() UDT 必然要和数据挂钩,所以完全可以由FB替换。 这个FB完全可以体现UDT的功能,一样实现STRUCT 的全局应用。这个FB就是一个特殊数据类型。 重复定义,多次调用,统一修改等等都不再是问题。 不过这个FB需要占用一点点工作内存。
人生没有边界,一切皆有可能。
|
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
21楼
![]() ![]() ![]() STRUCT在博途的定义是数据结构,是一种匿名结构,不能全局定义 UDT在博途的定义是PLC数据类型,可全局定义 因此,我们通常所指的结构变量/结构数据,在博途中就是指UDT 这种重复性的程序,只是结构数据使用的一个方面,在这里使用UDT也好,STRUCT也好,功能上其实并无太大的区别,功能块只有一个,UDT可以全局定义,STRUCT可以依附FB/FC,相当于全局定义。但在性能上SRTUCT更加耗费系统资源。并且,此类应用没有体现结构数据传递的特征。 我在之前的帖子里讲了,UDT解决了结构变量重复定义的问题,其前提是结构数据的传递需求,既然是传递必然是双方的,现实应用中存在着许多这样的数据传递需求,比如配方的传递
Zane
注册自动化系统工程师
Always save before download
|
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
22楼
![]() ![]() 逻辑的标准化与模块化,最终也是体现在结构数据的标准化的,以数据的变化改变逻辑的变化
Zane
注册自动化系统工程师
Always save before download
|
Zane 版主 ![]() 经验值:76318 发帖数:19347 精华帖:378 |
23楼
![]() ![]() 从博途的手册的观点来讲,一再强调应使用UDT,而对于STRUCT是能不使用就不使用,这恰好与某些网友的观点相左。 其中一个原因在于对于匿名结构的解析,系统需要更多的开销 而使用 PLC 数据类型有以下优点: PLC 数据类型元素也可以间接寻址,这意味着地址可变,并且到运行时才会计算。 基于 PLC 数据类型的变量继承 PLC 数据类型的所有属性。 如果对 PLC 数据类型进行了更改,所有基于此 PLC 数据类型的变量都会自动修改。 使用统一的符号表示可以提高程序可读性,这是因为 PLC 数据类型各个元素的名称都显示在程序中。 可以对 S7-1500 CPU 高性能进行最佳利用。 PLC 数据类型可以作为块调用的完整结构进行传送。 由于需要提供的参数更少,因而简化了调用接口。
Zane
注册自动化系统工程师
Always save before download
|
百夫长 侠圣 ![]() 经验值:3343 发帖数:650 精华帖:1 |
24楼
![]() ![]() 曾经碰到这么一个需求 PLC跟IT系统连接,需要上传工检的加工信息到IT系统 信息包括,工位号 加工完成 信号,合格信号,工件号,等等 PLC这边需要做的是, 生成这些信息 可以缓存50条信息,以防网络中断而漏传信息 网络通时,从缓存中按照先后顺序,传送信息到IT系统 再这种需求下,就比较适合用UDT了, 定义一个UDT,然后一个长度50的数组。简单明了。
罢了,罢了.
|
百夫长 侠圣 ![]() 经验值:3343 发帖数:650 精华帖:1 |
27楼
![]() ![]() 也可能我讲的不全, 这里用到的同样数据结构的有这么些地方 1.生成信息的功能块 输出接口 。 2.生成信息存储的区域 3.信息缓存的功能块 输入接口 4.缓存的数组区域 5.从缓存中读取最早的信息的功能块 输出接口 6.跟IT通讯的指定 数据块 就这样可以有6个地方使用同样的结构了。 一台PLC可能上传多个工位的数据,算起来肯定超过6个了
罢了,罢了.
|