解耦为不同的模块,还是在一个模块内部解耦,是一个并不显而易见的选择。
正如CPU指令集的CISC与RISC,操作系统内核设计的宏内核与微内核。现实情况是,选择复杂设计的性能占上风,选择直接模块解耦的都不太能打,而很多人都认为直接模块解耦更好。这其中道理复杂,不是三言两语说清。但问题的本质就在于:定义固定接口、数据分隔、上下文关联。简单情景没问题,但是随着复杂和动态,事情变得并非想当然,负面凸显。
在PLC中,以先前的Modbus开源案例为例子,我选择的是:首先高内聚为一个单一模块,然后在模块内部去分解为四个部分,每一个部分内部再分解成数量不等的层,层由元素组成。
这四个部分是:UI、调度、IO公共管理、IO。
这个四部分的逻辑划分,适用于任意行业应用任意案例的模块。不论是底层的设备模块,还是顶层的工厂或生产线模块。
下面是这个具体案例内部的分层解耦情况。目前四个部分有很多层(12 + 5 + 2 + 9)。这些分层,与以前的开源案例代码相比,做了进一步的提纯归并,添加了一些辅助元素,以求更清晰和便于诊断。其中带有星号的层,是说如果把这个模块改写为其它任意串口Modbus设备,需要改动内容的层。
近期听了一点龙芯公司总裁胡伟武讲的计算机体系结构,其中谈到冯诺依曼体系结构,又有了新的感悟:芯片指令集的设计高手,必定很大程度上也是顶层软件设计思想的高手,其中是相通的。由此可以联想到INTEL和ARM内部那些顶级设计师的事业生涯历程。
在知乎上看到从reddit转载的SpaceX软件工程师问答。形式上和工控研发是一回事的,第一性原则真的贯彻到底,但本质上其实是用软件定义了该公司的管理和流程。这个问答摘要信息量很高,揭示了很多问题和差别的根源。
SpaceX软件工程师问答摘录.pdf
--------------------------------------------------------------------------
在后来增加的一些额外元素中,其中有一个元素是把当前IO正在执行的层,也就是步骤,显示到HMI上,用于辅助诊断。这个modbus案例的IO执行分为七个层。
分为两种场景
1、通过HMI上的按钮,把任意一个正在占用IO的设备,停止到这7个IO步骤中的任何一个。按钮是循环切换的,点一下切换到下一步骤。
如下图,3号设备主动停止到IO第五层读数据转移,并且485轮询停止在那里,直至切换退出这七个步骤。退出后,左侧的计时器会显示总共卡顿了多长时间。
2、当IO某层中的代码出现错误,会导致IO执行逻辑卡死在该层,HMI上也会显示出来。如下图,1号设备的IO第4层出现故障卡死。
这个元素便于加速诊断,多设备公共IO的执行问题出现在哪个步骤,快速定位。