恭喜,你发布的帖子
发布于 2023-07-20 06:11:07
80楼
一个具体例子:运用分层解耦架构,给设备FB增加一项功能。
在此前开源的项目代码中,当在这5个温控器之间切换485通信执行权的时候,下一个获得执行权的设备是不会等待一个间隔扫描周期的。它是在上一个设备执行完成最后一个通信任务的同一个扫描周期内,立即开始执行自己的通信任务,除非上一个执行设备实例是位于扫描周期中的最后一个。
这个场景正如下面的Trace截图所描述。实践中这样做并不会有什么问题。
但是如果我就刻意想要:在切换设备执行权之后,首先空闲一个扫描周期,然后再开始自己的通信任务,该如何做呢?
既然说这是个分层解耦的设计,那么应该很容易扩展增加功能才对吧。具体做法如下。
【1】首先在设备FB的接口中增加一个变量如下。
这个变量的作用:让每个设备实例,知道自己在代码扫描周期中的前后调用次序的序号。具体数据是从实例外面传进来的。
这样只要把前一个拥有执行权设备的序号,和自己的对比一下,就知道前后顺序,也就知道什么时候该等待一个周期。
【2】既然每一个设备实例都需要获得前一个拥有执行权设备的调用序号,那么这一定需要增加一个公共变量,而它就应该被放在公共IO的竞争与协同信息交换公共区中,所以就在全局DB中增加变量如下。
其中ChannelControlling这个变量是不必要的。但是我不想改动原有架构,又想要用Trace来方便刻画:一个设备实例在获得执行权后(ChannelActive),它是什么时候才真正开始通信执行的。实践中这个变量是不必要的,只是对Trace表达和调试有用。
【3】既然增加了MyScanSequence这个接口变量,那么就应该在每个设备实例调用的地方,根据调用的规律为它们分配调用序号。在本案例中增加一句代码如下。
在实际工作中,在不同项目中,在不同的程序设计中,可以根据具体案例的架构特点,为每个设备分配自己的调用位置序号。
为每个实例分配调用序号的做法,会在很多的场合都有用处,做法也多样。
这样每个设备实例就拿到了:了解自己在扫描中的前后位置关系所必须的数据。
接下来,就需要在设备FB内部用这个数据来具体实现切换之后的间歇等待了。
【4】在设备FB的static变量中,增加两个变量。它们分别负责控制:间歇的开始和结束。
【5】然后在设备FB的通信层1中增加一段代码如下。
获得执行权之后,需要等待多久才启动通信执行,顾名思义,就应该在通信1这个层中被解决掉,不是吗?其它通信层于此无关。这就是解耦的一个体现。
我用两个变量来明确定义间歇等待的开始和结束。
同时ChannelControlling这个全局变量就是在此处获得了启动时机的信息。
【6】既然通信启动层有了变动,也需要在通信结尾层中增加相应的收尾动作。
前一个拥有执行权设备的调用序号就是在这个时候被刷新给全局环境的。另外,间歇等待的增加,意味着通信的启动条件被增加了一个,所以在结尾的时候也要把它复位掉才行。ChannelControling在此处被复位,这样在Trace中就能看到这个间歇的豁口表达。
这样就完成了。下载运行并用Trace监控,就可以看到获得执行权的时间,和它实际开始通信执行时间的间歇和差别。
这样,在不同设备之间,在同一个设备内部的不同任务之间,都会有一个扫描周期的间隔等待。
我写上面这一大堆,是想通过这一个例子来说明:在分层解耦架构把设备功能场景切分很精细的设计前提下,如何通过这种结构便利性和明确性,把具体的功能修改,局限到非常狭窄有限的环节中,来保证修改的健壮性、清晰条理性、不易出错,且容易细节监控。
这也是如何精细雕刻程序的一个展示。
请填写推广理由:
分享
只看
楼主