作者 | 主题 |
---|---|
宝冬 至圣 经验值:10562 发帖数:1734 精华帖:26 |
楼主 2023-03-29 06:06:12
主题:【开源】Modbus设备的单FB封装和多设备平行调用的通用架构 ------ 一个温控器案例的完整项目文件 首先请注意:这不是通常所说的Modbus通信模块。而是一个具体设备的FB,和它在触摸屏上的交互界面。
Modbus是作为这个设备的IO被嵌入进FB。我追求的是:一个设备只需一个FB实例,通信只是它的IO管脚。 为什么要这样呢?因为作为买来的一个物理实体设备,485和Modbus是长在它身体里的。并不存在一个单独的可以拿在手里的实体物件叫Modbus模块,通信本来就是设备的内在功能的一项。而我喜欢抽象与现实的对称,也就是:现实中的一个可以拿在手里的完整东西,程序中就对应一个FB,这就是它的抽象孪生,除此没了。 我不想额外造出一个在现实中不存在单独对应体的抽象体。 解耦分隔在FB内部就可以了,正如现实中的一个完整设备,它的内部各个组件功能也可以相对独立一样。 设备FB内部采用的是分层解耦。 多个设备FB实例之间,是平行调用的,没有上级管理者。不管是同类设备,还是不同种类的,都可以。 开源的意义在于这个设计背后的思想。至于能理解和启发运用到什么程度,看代码吧。我在其它帖子中介绍过,其实是模仿了法治社会中的自由人的行为方式。
之所以说它是通用架构:如果你理解了,可以按照它的设计思想,很容易把它改写成任何种类Modbus设备,且可以灵活扩展和增减,适应多变且复杂的任何场景需求。这是个面向开放的设计。 其实并不局限于Modbus。任何多个实体之间,存在竞争性协调使用稀缺公共资源的场景下,都可以采用这个架构中的调度和解耦思想。这才是它的真正本意。
我以前分享过用自由口PtP做的MB-Master指令,还有可以运行在UDP上的MB-Master指令,它们可以被嵌入这个框架。 可以体验:一个设备FB,同时具备通过PLC本体485串口,和通过以太网UDP走串口服务器,可以在不同通道间,从HMI界面自由切换,来运转Modbus的效果。
项目是用博图V14Sp1的做的(PLC部分全部是SCL),体积大约40兆,归档后也有2.6兆,只好用网盘分享了,链接是永久的。 链接: https://pan.baidu.com/s/1BrLdX9dee_lPJErdFWTbmA?pwd=qixe 提取码:qixe
项目硬件:1214C + CB1241 + TP1200 + 5个West品牌的温控器 温控器型号:在HMI首页上可以看到。这个英国品牌现在国产也不贵。如果按照首页上的型号买两个,可以连上PLC实机体验效果,能帮助理解架构设计。
PLC与HMI之间采用的是:读写分离的、接口式的、上下位交互设计。 这个项目中的UDT没用放进库。HMI上没有用面板,用了多路复用。 --------------------------------------------------------------------- 退一步,用结构解决问题。不欢喜于局部算法。 用结构把复杂场景分解成简单元素。共性是一种结构,可以为元素进行分类。 把生活投射进结构设计,表里对称。 |
宝冬 至圣 经验值:10562 发帖数:1734 精华帖:26 |
70楼 2023-07-07 22:30:58
主题:回复:【开源】Modbus设备的单FB封装和多设备平行调用的通用架构 ------ 一个温控器案例的完整项目文件 如果你想要以一种透彻普适化的方式,去理解目前人类所有通信手段的根本,那OSI模型就是说这个的。 它是个逻辑模型。那7层结构是逻辑上的7个分层,所以它是个抽象模型,是个大的框架。 它不是在讲某一种具体的东西。它是想要说尽天下所有具体通信手段的共性,把万变不离其宗的东西说出来。所以它是按人类最大可能覆盖场景的集合去说的。 任何一个能叫出名的通信协议,比如应用最广泛的TCP/IP协议族中的多个协议,都是具体的通信方式。它们在逻辑上被抽象后,都可以归于OSI中的某一逻辑层 不同的具体通信协议,会省略或压缩不同的逻辑功能。毕竟每一类的场景还是有具体差别的。所以,每一个具体协议都是OSI的某个子集的一个具体实现方式。 因为历史和利益的缘由,不同的人、不同的公司,根据不同的需求和立场,就创造了这么多不同的通信协议。它们都以不同的各有所长的方式,实现了OSI中讲述的那些抽象功能。 按照工业上的基本现实来讲,就分两类:要么跑串口线,要么跑以太网线。 网线上跑的协议格外贴近OSI模型。如果你用网线上的抓包软件去看每一个抓到的以太网数据帧,它的代码都是层层包裹的。这层层中的每一层,就是对应OSI中的一个抽象层。 贴近物理的逻辑底层在最外面,贴近顶层应用的逻辑位于帧的最里面。现在的多种抓包软件,不仅把各个层给你分开,而且每一层中每一位的含义,以及进一步推演出来的信息,都说的清清楚楚,一览无余。 串口是比较老的东西,相对的当初的早期设计就简单一些,OSI中的靠近上部的一些层就省略了。但还是能和OSI中的不同层对应上。 串口最常用的协议modbus,就是相当于把上面的5个层给省略合并了。 MB-Master指令的职责,就是把PLC程序员用户在应用层面的信息需求,封装进Modbus协议中。封装完成后得到的东西,是要嵌入进第2层的,被第2层的协议包裹在里面。 这第2层的协议叫Uart,也就是波特率、起始位、数据位、校验位、停止位这些东西。MB-Comm-Load指令就是负责把master指令封装后的东西,进一步封装为Uart的协议格式,最后交给OSI底部第1层的485,用电信号去表达这个Uart报文。 485线路上的Uart报文,用示波器的探针搭在AB两根线上就能看到。如果你熟练的话,不借助工具,用眼睛就能解读其中的ModbusRTU报文。具体长下面的这个样子。 具体协议解读就是下面这样。可以看到ModbusRTU协议的报文,是如何嵌入在Uart报文的每一段8个数据位中的。 这上面的截图中,你能看到OSI模型的结构。 图中的连续锯齿波动,这就是最底层的485信号,这就是OSI的第1层物理层的表现。 连续的485信号锯齿中,出现了上下高低的错位排布。这些错位就是bit。不同高低排列的bit规律性,就是在表达uart协议中对于波特率、起始/数据/校验/停止等的约定。这就是OSI的第2层数据链路层的表现。 Uart信息格式中,每一段的8个数据位中嵌入的,就是Modbus报文的1个字节。把这些字节连起来,形成的RTU报文,就是OSI的第3-7层的一种实现。 串口通信中的自由口协议,和modbus协议,是平等的协议。只不过你需要自己定义Uart每一段的8个数据位中嵌入的内容,它所表达意思的规则。 明白了上面的叙述大意,就能理解ModbusTCP是什么。它就是把Modbus的基本报文略微调整一下,塞进以太网的TCP协议的纯数据部分之中。所以它是OSI中的第7层协议。 同理,西门子的S7协议也是OSI中的第七层协议。也是嵌入进TCP协议的纯数据部分之中。 这种从外到内的层层包裹,在编程上都是要耗费代码设计和计算时间的代价,所以包裹层数越多的协议,传输速度越慢。发送信息时候的层层打包,和接收时候的层层拆包,就和发快递一样,内外套好几个箱子就会费事,每一层箱子都要打标贴详述信息。越靠近OSI顶层的通信协议,因为封装代价就越慢。我用上位机测过,S7比TCP传输,总体上慢50倍。 但是仅有通信是远远不够的。 工控人面对的是项目工艺,这些工艺通过各种设备来实现。每个设备常常会用到不同的通信方式。 站在项目/工艺/设备的高度看通信,它们只是设备FB的IO。而且是非常固化的IO,因为你只能按照协议去执行,没有任何变化。 所有的变化,都是由于人的需求变化,导致的项目工艺需求的变化,导致的设备FB的使用变化,最后被表达为通信IO传送的内容变化。 在这个信息传递链中,通信单元本身的执行模式其实是完全不变的。快递小哥始终是快递小哥,区别是包裹中装的东西不同。 人是一切变化的根源。程序中越是靠近顶层的设计,越要包含各种可能的变化。而当你这么做到时候,会发现底层的通信执行,根本就是个固定跑龙套的。所有的复杂性都是来自于顶层。 这就注定了,在越来越复杂的需求框架设计中,通信执行底层本身,只会是越来越内聚化和边缘化。 这就是我把这种面向设备FB功能设计的通用解耦框架开源的原因。 ---------------------------------------------------------------------- 以前发的几篇相关帖子链接整理如下: 用自由口通信制作的ModbusRTU协议的Master指令的SCL源码 https://www.ad.siemens.com.cn/club/bbs/post_1725735_50_0_0.html#anch 通过以太网UDP协议经串口服务器进行ModbusRTU通信的SCL源码 https://www.ad.siemens.com.cn/club/bbs/post_1725940_50_0_0.html#anch Modbus设备FB接口设计背后的理念 https://www.ad.siemens.com.cn/club/bbs/post_1792331_50_0_0.html#anch 1200自由口通信的报文和长报文的底层分析 https://www.ad.siemens.com.cn/club/bbs/post_1683110_50_0_0.html#anch 如何分析Modbus通信的执行快慢 https://www.ad.siemens.com.cn/club/bbs/post_1687399_50_0_0.html#anch 擅用博图中的Trace功能 https://www.ad.siemens.com.cn/club/bbs/post_1794586_50_0_0.html#anch UDP的可靠传输与应用 https://www.ad.siemens.com.cn/club/bbs/post_1712883_50_0_0.html#anch |
宝冬 至圣 经验值:10562 发帖数:1734 精华帖:26 |
80楼 2023-07-20 06:11:07
主题:回复:【开源】Modbus设备的单FB封装和多设备平行调用的通用架构 ------ 一个温控器案例的完整项目文件 一个具体例子:运用分层解耦架构,给设备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监控,就可以看到获得执行权的时间,和它实际开始通信执行时间的间歇和差别。 这样,在不同设备之间,在同一个设备内部的不同任务之间,都会有一个扫描周期的间隔等待。 我写上面这一大堆,是想通过这一个例子来说明:在分层解耦架构把设备功能场景切分很精细的设计前提下,如何通过这种结构便利性和明确性,把具体的功能修改,局限到非常狭窄有限的环节中,来保证修改的健壮性、清晰条理性、不易出错,且容易细节监控。 这也是如何精细雕刻程序的一个展示。 |