手把手教你|VBS或VBA中的排序算法

最近有朋友向我咨询一个需要在RSViewSE环境中实现的排序算法问题,背景是将若干个PLC内共约2000个DI点的状态变化按先后顺序排列出来,这2000个DI点大约可以分为100组,每组20个DI标签,每组之标签之间无关联。根据排序结果可以实现一些其他的控制功能。

在RSViewSE中,复杂的算法依然需要VBA脚本的参与,在这个需求中,需要先明确以下几点:

算法程序需要不间断运行来捕获DI点的变化

每组DI点在变为1后就一直保持,直到PLC程序内将该组所有的状态复位为0

排序的结果需要能记录下来

算法程序可以随时停止

VBA编写的算法程序可以引申到VBS,因此,该算法不止适用于RSViewSE,还适用于WINCC及其他能够使用VBA或VBS脚本控制的组态软件

算法内参与排序的标签不能局限于20个,可以自由调整。

基于以上条件,本着以往没有条件也要创造条件的态度来实现这种排序算法。

准备工作:

01

有PLC的就在PLC内创建20个标签,用于跟SE通讯。没有PLC的就使用仿真变量来通讯。只要能够模拟控制20个标签的状态变化就行。本文中使用一个软件模拟出OPC UA的变量与SE建立通讯,并且在SE的标记库内创建变量关联起来。

02

自行学习在SE内使用VBA脚本获取标记库标签值的方法,可参考SE帮助文档。

03

 自行学习VBA内将数据写入到本地磁盘的txt文件的方法,可百度获取到源码(跟排序算法无关,这是为了比较清楚地查看到排序结果)。

04

理清逻辑思路,设计排序算法,主要思路是将需要参与排序的标签都先引入到SE的VBA环境中,再一一存储到数组,使用数组功能进行排序。

04

排序时,一个数组用于存储需要参与排序的标签值,称为数据数组,便于持续监测标签值有没有变化,来确定改DI点是否有动作。另一个数组用于存储排序的结果,称为排序数组,排序数组内每个元素上存储的内容为数据数组的元素编号,以便能快速于实际的标签对应起来。比如,数据数组arrData(1)和arrData(2)存储的是标签P1和P2的值,那么在排序结束后,排序数组arrOrder(1)和arrOrder(2)中将会分别存储1或2来表示数据数组是arrData(1)还是arrData(2),依次类推即可。

准备好以上基础知识后,在SE内创建一个新项目,本例中使用v12版本SE软件。标记库内创建一组变量,并且关联到PLC或者仿真变量上,以便程序获取标签值。

图片

在SE内创建一个画面,放置一个文本框和2个按钮,文本框用于关联系统标签秒,从而实现每秒变化时在文本框的值变事件内执行算法程序。2个按钮分别为初始化并开始排序和停止排序。程序都在VBA内。 

图片

图片

图片

图片

打开按钮VBA程序,VBA环境内编写算法。 

图片

编写程序如下:

01 

SE标记库内标签值读取到VBA内

图片

图片

图片

02

VBA内数据写到本地文件的txt文档内

图片

03

程序初始化,声明一些变量和数组

图片

04

初始化按钮及开始排序标志置位

图片

05

停止排序按钮

图片

06

排序算法子过程

图片

07

在SE画面的文本显示框的值变事件中调用排序算法

图片

程序编写完毕,将SE运行起来后,可在仿真变量中依次修改DI的状态变化,系统会自动将这些标签的变化顺序记录下来,实现整个排序过程。本例子中,为了避免判断冲突,假想在PLC中将DI点变化的状态转换为一个模拟量标签,默认为0,DI变为1后,对应的模拟量标签值变为9999。DI变为0后,模拟量也需要变为0。因此在算法程序中会出现判断标签值是否为9999的语句。

将SE运行起来后,文本框内数值会随着系统时间的变化每秒变化1次,此时VBA程序会相应地执行一次。 

图片

在没有点击初始化按钮时,系统会将排序标签的默认状态记录到本地磁盘的文件内,本例子中如下: 

图片

图片

图片

点击初始化并开始排序按钮,系统会按每秒一次的频率监测需要排序的标签值状态。需要注意的是,参与排序的一组标签值默认必须是状态为0的,否则系统无法判断出已经不为0的标签的变化顺序。当PLC内本组DI点都没有变化时,系统会记录默认值到本地磁盘内。

图片

图片

修改PLC内DI点的状态,模拟标签值变化,本例中,自由修改仿真数据的变化。

(1) 模拟第5个DI点状态变化 

图片

查看文本文件 

图片

图片

其中OrderData文件内第一个位置变为5,表示该组标签值中第5个标签最先发生状态变化。

(2) 模拟第3个DI点状态变化 

图片

查看文本文件: 

图片

图片

其中OrderData文件内第2个位置变为3,表示该组标签值中第3个标签发生状态变化。依次模拟下来会发现,系统会将每个DI状态变化的顺序都记录下来。如下图所示 

图片

图片

图片

排序完成,可根据排序数组内记录的内容从程序内可轻松获知对应DI点的变化顺序。本例中,参考初始化获取SE标记库内的标签对应关系,即可获知。排序数组中记录的数值与标记库内标签取值时定义的数组下标为一一对应关系。比如在OrderData文件中,第一个5表示arrData(5),也就是”Order\P5”这个标签。第二个3表示arrData(3),也就是”Order\P3”这个标签。 

图片

   但是,需要注意的是,本程序中算法只适用于每组内DI点位状态变化间隔大于1秒的情况,也就是说第一个DI点变化后,间隔1秒之后的其他DI点状态变化才能准确的捕捉到,因为本程序扫描时间为1秒。

   本程序中,参与排序的标签可以有很多,理论上不设置上限,但是因为采用了循环嵌套方式进行排序,一旦标签过多,会影响程序执行时间。修改标签数量时,需要注意:

①将数据数组arrData和排序数组arrOrder的默认初始化长度修改为实际需要的即可(如果有30个标签参与排序,就设置数组长度为31,因为程序中奖第0个元素空置了)。修改下图中的21为实际需要的数字即可。 

图片

②将标记库内需要参与排序的标签都创建出来,并且在VBA程序内将标签值传递给数据数组,必须将需要参与本次排序的所有标签值都写进来。 

图片

图片

图片

 

2024年05月