现场总线控制系统功能块组态软件设计
(CFBClass *m_pDestFB,CFBParamClass *m_pDestParam),这些参数标记了链接线物件和功能块物件的逻辑关系,无论这些物件的存储方式如何,通过这些逻辑关系可以构建出一个功能块网络。
链接线物件中一个重要的成员变量是临时变量地址m_MemAddress。当用户在两个功能块的参数之间添加链接线时,程序为两个参数变量赋值“Temp”字符串,Temp表示的是用一个临时的位变量来保存,在编译后,会根据不同的连线将连线两端的位变量参数赋值“Temp_n”形式的字符串,其中的n值就是m_MemAddress,既然在下为机中需要这样一个位变量来做Temp变量,那就需要知道在下位机中的地址,m_MemAddress就表示这个地址。由此可知,在下为机中不需要一个数据结构来保存链接线结构,是由地址为m_MemAddress的位变量来做链接两个参数的中间变量。
链接线在可视化组态中是可以拖动的,所以要设计鼠标点击测试函数和调整连线位置的函数。
3.1.9网络物件设计
功能块和连线都是在网络中的,一个网络是一个程序段的容器,包括了功能块物件和连接线物件的集合,同时又是一个绘图的标尺,确定了功能块和连线的位置。
这里将功能块和链接物件的集合用List来保存起来。List中的保存顺序是由用户添加的顺序决定的,不能反应出功能块之间的任何逻辑,但是在链接线物件的集合中每个链接线都保留这源功能块参数和目的功能块参数,所以他们之间的逻辑是隐型存在的,这点非常重要,因为在编译程序中需要对功能块进行排序。 成员变量代码如下:
当前选中单元格的左上点坐标 CPoint ptLTCurCell 当前选中的单元格的行 int m_nRow 当前选中的单元格的列 int m_Col; …. 网络号 int m_nNetworkID 功能块集合 CList
图3-10 CNetWork 成员变量
–28–
现场总线控制系统功能块组态软件设计
CNetWork的成员函数大部分都是绘图的代码,绘制出一个可以改变大小的网格,这样可以规范功能块编程的格式,使功能块和连接线整齐的排列在网格中,展现一个良好的可视化编程界面,代码中需要注意的就是逻辑坐标和设备坐标的转换问题。
3.1.10功能块文档类的设计
一个功能块的文档是由若干的网络组成,功能块文档类是一个很庞大的类,因为作为MFC主框架文档/视图结构的文档类,它会与视图类承担绝大部分的软件功能,由视图类处理用户的操作,然后将操作保存到文档类中,同时文档类还承担了永久化保存的功能,所谓永久化保存,就是将程序运行在内存中的信息保存到硬盘中,这样在机器掉电的情况下可以继续保存当前软件的状态,在MFC中提供这样的永久化机制,MFC的CObject类添加一个虚重载函数到类中。[9]该函数为Serialize( )。我们将用我们自己的Serialize( )重载这个Serialize( ),使之装入和保存成员变量到磁盘上。这只是一种选择,现在更加流行的一种趋势是采用XML文件来保存数据结构实现永久保存,使用XML文件的好处在于各个平台通用,可移植性好,几乎所有的应用程序都能处理XML文件,并且通过DOM提供的方法可以很快捷的对XML文件进行操作,在本程序中将采用XML文件作为功能块的存储文件类型。
功能块文档类的数据成员和成员函数都很庞大,因为组态软件的很多功能都是在这里得以实现,例如功能块复制粘贴,网络的复制粘贴等,但是这些功能不能算作是整个功能块编辑程序设计的主线,所以在此就不讨论。
CFBDDoc 功能块网络链表CList
图3-11 功能块文档类
–29–
现场总线控制系统功能块组态软件设计
CFBDDocData类是一个用来与XML文件交互的辅助类,它定义了一组数据结构,与XML文件中的信息相映射,还提供了一组Serialize方法,用来实现数据读取和写入的功能,在读写参数过程中我们用到了TinyXML类,用TinyXML在描述文件中寻找节点读取或写入属性值。它是当前非常流行的一款开源的XML解析器,可以与微软的DOM相媲美。
SerializeXML函数是功能块文档类读取和写入XML文件的方法,通过一个布尔类型的变量来判断是读取还是写入。当为写入时首先调用SaveNetWorkPara函数将类中的信息保存到m_Data中,然后m_Data将信息保存到XML文档中。当为读取时,m_Data首先将XML文档中的信息读取出来,然后将数据赋值到类的成员变量中,生成一个功能块文档的实例。
SaveNetWorkPara函数是将当前的功能块文档类的成员变量保存到CFBDDocData类型的m_Data中去,m_Data中的数据结构基本上与功能块文档类的成员数据对应,这样可以将当前功能块文档类的实例的内部数据映射到了m_Data中去,通过保存保存到XML文件中去。
ReadNetWorkPara函数功能是相反的,通过读取XML文件,解析保存到m_Data中,然后通过ReadNetWorkPara将参数信息赋值到功能块文档类实例的成员变量中,在程序中运作。(XML文档结构看附录)
上述可知,CFBDDoc类实现了永久化保存的功能。
3.2编译程序(Compile.exe)的设计
3.2.1功能块编译程序的设计分析
功能块编译程序是一个独立的支持MFC框架的控制台程序,正如VC中的编译程序cl.exe,它编译的对象是功能块程序文件(XML文件),实现的功能是将功能块程序的描述文件通过编译生成可以下载到下位机的二进制文件,从数据结构角度看是将功能块的描述解析成下位机中功能块的数据结构,从组成结构角度看是将功能块描述的内在连接逻辑按找功能块程序地执行顺序转化为一个线性的逻辑。编译程序的输出是一个可以直接通过通信接口下载到下位机的二进制文件。这里的二进制信息就是要下载到下位机的功能块数据结构的队列。
功能块的编译程序不同于文本编译程序,文本编译程序可以通过读取文本符号通过文法分析生成中间代码,功能块程序的描述文件虽然也是文本,但是它是可以被XML解析器解析的文本,它描述的信息是功能块程序图形信息,采用文本编译程序的策略是
–30–
现场总线控制系统功能块组态软件设计
背道而驰的,我们应该才用一种更加面向对象的方式来解析描述文件中的信息,这里采用的策略是将描述文件抽象出功能块文档类,这里的功能块文档类和可视化编辑程序设计中的CFBDDoc类不同,它的成员变量不包括界面图形绘图信息,只包括在编译过程中可能用到的属性信息。同样,在功能块文档类中的功能块网络类,功能块类,链接线类,功能块参数类都不再需要界面绘图信息的成员变量。在成员函数方面,每种类型都有针对自己类型的编译策略。最后通过类之间的包含关系和函数的调用将编译方法合理的组织在一起,实现编译功能。如图:在编译程序中,类的命名还采用物件的名称,和编辑程序中的类命名是相同的。
XML文件 功能块文档类 二进制文件 解析 编译
图3-12 编译过程的信息的形式转化
编译程序的功能不只是将功能块程序描述文件转化为二进制文件,PLC_Config是支持将功能块程序从下位机上载到软件中的,这需要另外一种编译机制是将二进制文件转化为描述文件,这种反向编译的设计思想和正向编译大致相同,将从通信模块读取的二进制文件使用memcopy函数转化为有实际意义功能块结构体,再将结构体中的数据赋值到各个类的成员变量中去,这样就生成了功能块文档类的实例,再通过SerializeXML函数保存到描述文件中去。
作为一个编译程序,对程序的错误检测报告时必须的,报错信息将分布在整个编译过程中,怎样将子程序的报错信息传递给主程序,可以实现像VC那样的点击错误信息程序将定位在出错的代码,通过查阅资料,需要使用通道的进程间通信的技术。
3.2.2编译程序的接口设计
将PLC_Config的编译部分独立成一个单独的可执行文件,需要用命令行的方式为编译程序提供必要的参数。正如微软VC++ 中的编译程序cl.exe ,我们在编译时需要在项目属性中设置命令行,如:
/Od /I \/I \/I \/I \/D \/RTC1 /MDd /Zc:wchar_t /Yu\/Fp\/Fo\/Fd\
–31–