故事作者:万泉河

最近创作

看看TA的故事

1120 【万泉河】又见SID

已锁定

万泉河

  • 帖子

    10904
  • 精华

    132
  • 被关注

    1012

论坛等级:至圣

注册时间:2003-06-06

钻石 钻石 如何晋级?

1120 【万泉河】又见SID

733

3

2022-11-20 18:23:59

1120 【万泉河】又见SID

 

我在2022年初,即农历春节假期的时候,给同行们出过一道编程题目:《【万泉河】征集FB的编程题:获取SID》

 

要求做一个库函数,当有一些特殊功能需求的库函数需要的时候,通过它,得到被调用的次数编号,即对于设备类型的站,每一次实例都得到一个独立的站号。所以叫做SID或者UID。

 

这在标准化编程烟台方法当中,几乎作为一个基石般的存在。 因为时时刻刻会有可能遇到它。 而这块基石如果提前已经有了,那么遇到的时候只需要从库里面拎出来即可。 而如果不晓得这种基石的重要性,那除了没有准备之外, 很有可能压根不会想过有这样的解决问题的方式。

 

所以,你大致也可以用SID来鉴定自己与烟台方法的差距还有多大。 那些质疑烟台方法能实现的效率和真实性的人,我觉得需要先质疑下你自己:懂得SID的重要性了吗?

 

最近做了PLC中编程实现触摸屏多路复用的功能,即把设备的控制数据打包存储到一个专用的全局数据块的数组中。如果按照大家习惯的编程方法,这当然没什么难度。 只需要规划好地址分配, 挨个儿整理数据双向拷贝数值即可。 即运行状态和运行值向上拷贝,控制指令和参数值向下拷贝。

 

这里面规划就比较重要,需要通过规划,划分好各自对应的位置号,具体的地址,到了HMI中,再根据这个地址表进行变量读取,使用。

 

而烟台方法是比较抵制规划的,希望能免规划,能自动分配,自动使用。这样就减少了规划的工作量,以及因为规划不足导致的冲突。

 

我在这回遇到之后,就只是在FB上建立了一个UID的管脚,然后暂时搁置一边了。可以等多路复用的功能完成之后再把SID的功能叠加进来即可。

 

然而这次多了个心眼,因为对以前所做的并不太满意,也因为近一年又有些积累,就用新的方法重新做了一个GETSID的函数,后面又花了一点时间专门调试了一下。感觉跟以前的实现方法思路上简单了些,但具体效果仍不太满意,有待以后实际的检验。

 

这里把具体的功能和实现思路再梳理一下。

 

如果对模块化的调用,对低耦合要求并不高的话,SID的实现本身其实很简单。

 

方法1,每个站的调用时,人工输入编号值就好了嘛!除了人工工作量大一点点点,需要耗费点记忆力,没有别的缺点。

这个最简单。但缺点就是要累人, 工程师自己随时要规划避免有错误。 比如设计调试时增加减少一个站,都要来检查和维护这部分的编号。比如一个新项目要使用旧项目中的现成模块单元,这部分的编号又要全部重新检查一遍。 这和不建议用MT的理由一样的,会一直占据工程师的工作量。

 

方法2:在所有的站调用之前,即OB1刚开始的时候,做一个编号清零的操作。然后每个站的调用过程中SID自加一。

这个方法其实更简单,而且也更稳定可靠。我在很多应急的情况下都直接拿来实现。

然而,也经常出问题。 经常是,自己做的示范功能很好用,但别人要继续复用的时候就用不好。 因为时常会把清零部分的功能给疏忽漏掉忘记拷过来。一旦疏漏,ID的增加就没有了刹车,就会跑飞了,整个系统功能都乱掉了。

 

我甚至会做一个专用的FC,名字就叫做“标准化功能初始化”,时刻叮咛后面的使用者不要遗漏,然而仍然不能完全避免。 而且,随着系统功能变多,这种清零需求会越来越多,需要在这里写很多个ID的清零,这个所谓标准化的模块,也逐渐垃圾化了,需要经常维护。

这里的清零,其实是在帮助实现找到站号为1的站,我称之为火车头。

 

方法3:直接给火车头的输入信号做个标记。而其余的非火车头的站,标记为非。

这和方法2几乎效果一样,然而使用过程会比2更混乱。我无法保证别人调用时只有一个火车头,或者火车头也恰巧被删掉了,而没有了火车头。

 

方法4:通过PLC变量上电后统计初始值的数量以获得站的总数。然后在技术不断累加的过程中,通过对站数量的相除求余得到固定的站号,余数为1的站,自然是火车头。

这种方法得到的站号比较简单,但在实际应用中BUG颇多。

 

比如程序调试过程中, 有可能不断的增加减少站调用,那么每次运行中下载程序之后,站数量改变, 所有站号就要重新分配,逻辑中稍不严谨,也会飞掉。

 

而站号重新分配,对这次遇到的应用,是不可以接受的。我们可以接受站号有跳跃,不连续,但不可以接受站号频繁修改。 哪怕是交工后的程序运行已经稳定,不会再改动,但仅仅在调试过程中的频繁改动,导致HMI中的程序都要修改,也是不可以接受的。

 

这一点缺陷甚至在前面几种简单方法中,也存在。

 

方法5:给GESID功能函数,在SID管脚之外,增加一个INOUT管脚,用于反向存储火车头标记。 函数功能中一旦标记了火车头,以后就可以在以后再调用读回来的时候,确认它是火车头。而且除非火车头自己被删除,其后的所有站号就不会再改变,即便有增删改查, 新站的站号增加,而删掉的旧站,站号会被保留。

当然,这种方法也仍然会有一些隐患,我发现了一些可能性,也增加了审核功能以避免各种可能导致跑飞的机会 ,然而仍然需要实际应用的考验。

 

 

最后一种方法5的缺点,是在原有管脚基础上,增加了一个看起来没用的管脚,增加了使用的难度。 与我一直在践行的高内聚低耦合的理念不甚相符。

 

为什么会想到用这样的方法,是因为想明白了一件事情。

 

高内聚与低耦合,是要看使用者的。 比如我们做高内聚的程序逻辑,让小学生都能做耦合部分的工作,实现了设计工作的优雅。

 

然而, 使用者如果不是小学生,而是有一定编程设计能力的工程师,比如在进行二次开发应用的我自己,我自己新做的多路复用的功能中需要用到的模块功能,我当然也希望越简单越好,重复使用时不需要费心力,但如果实在做不到最低的低耦合,即便有那么一点点复杂度,我自己显然也可以接受的嘛!

 

而那些跟我学习烟台方法的学员,在开发自己的库函数过程中,遇到这样的次低难度的耦合应用,也不会太在意。

 

所以,是我以前的认知太偏执了,太追求完美了。完美主义者通常都有一些自身难以客服的缺陷。

 

所以,以后知道了, 高内聚和低耦合之外, 还有内聚过程中的次低耦合。

 

还有一个比较重要的SID的应用场景,MODBUS TCP通讯中,有一个CONN_OUC的参数,代表的是分给这个站的端口号,1-4095。

然而要求的是,跟不同的站通讯,每个站使用的端口号必须唯一,不可以重复。

甚至,如果除了MODBUS TCP之外,还要有其它的TCP通讯,这些端口号之间也必须唯一不重复。

 

我在做GML (MODBUS优雅通讯库)的时候,这方面就准备不充分,其中多次遇到了SID的需求,即,GML应用实现过程中就需要多个SID的实例。而当时的项目中还有另外2000个其它协议的站需要通过多台网关走TCP通讯,弄得就比较慌乱,没顾得上整合,也担心互相之间干扰,所以最终甚至对不同的功能,用了分别不同的方法实现的各自的SID。

 

这回根据新的思路方法做出来的SID功能,会比以前的更稳定可靠。所以下一步打算把GML库函数部分再升级一下,正式开源的时候会用新的SID方法。

 


 


1120 【万泉河】又见SID 已锁定
编辑推荐: 关闭

请填写推广理由:

本版热门话题

网友专栏

共有3366条技术帖

相关推荐

热门标签

相关帖子推荐

guzhang

恭喜,你发布的帖子

评为精华帖!

快扫描右侧二维码晒一晒吧!

再发帖或跟帖交流2条,就能晋升VIP啦!开启更多专属权限!

  • 分享

  • 只看
    楼主

top
X 图片
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。