摘 要:本文分析了開(kāi)放式工控組態(tài)軟件系統(tǒng)的優(yōu)勢(shì)和不足,介紹了自定義的Child-C語(yǔ)言編譯和解釋系統(tǒng)。使用該系統(tǒng)可以較大地增強(qiáng)組態(tài)軟件系統(tǒng)在流程控制和應(yīng)急處理方面的能力。同時(shí)還引進(jìn)了事件的概念。文章重點(diǎn)介紹了在解釋執(zhí)行環(huán)境中處理二進(jìn)制可執(zhí)行代碼的一種有效方案。
關(guān)鍵詞:編譯;解釋執(zhí)行;事件;COM;自動(dòng)化;工控;組態(tài)
1 基于COM的工控組態(tài)軟件的框架分析
傳統(tǒng)的工控組態(tài)軟件[1]一般可以分為兩部分:組態(tài)設(shè)計(jì)系統(tǒng)和組態(tài)運(yùn)行系統(tǒng)。組態(tài)設(shè)計(jì)系統(tǒng)可以按照實(shí)際工業(yè)流程的需要選擇工控功能模塊,設(shè)置各個(gè)模塊間的關(guān)聯(lián)和數(shù)據(jù)流向等系統(tǒng)參數(shù),從而建立一套完整的控制系統(tǒng)。組態(tài)運(yùn)行系統(tǒng)建立在組態(tài)設(shè)計(jì)系統(tǒng)基礎(chǔ)之上,它按照設(shè)計(jì)系統(tǒng)設(shè)定的參數(shù)啟動(dòng)相應(yīng)的工控功能模塊,并負(fù)責(zé)模塊之間數(shù)據(jù)的傳輸和并發(fā)控制等。
基于COM的工控組態(tài)軟件[2]以面向?qū)ο蟮娜嵝栽O(shè)計(jì)與控制理論為基礎(chǔ)[3],將面向?qū)ο蠹夹g(shù)應(yīng)用于控制領(lǐng)域,把控制領(lǐng)域中的功能模塊和對(duì)應(yīng)的控制數(shù)據(jù)抽象封裝成COM組件,按照開(kāi)放式軟件平臺(tái)的原則將這些COM組件以插件的形式被加載到軟件系統(tǒng)中。COM組件是與語(yǔ)言無(wú)關(guān)的二進(jìn)制組件,使用任何語(yǔ)言開(kāi)發(fā)的符合接口規(guī)定的COM組件都可以在組態(tài)軟件系統(tǒng)中使用,因此提高了組態(tài)軟件的開(kāi)放性和收縮性,在系統(tǒng)設(shè)計(jì)階段,設(shè)計(jì)人員可以像搭積木一樣快速而直觀的搭建出一條控制流水線。
每個(gè)COM組件是被單獨(dú)開(kāi)發(fā)的高度抽象的功能模塊,它偏重于數(shù)據(jù)的計(jì)算處理而缺乏對(duì)系統(tǒng)環(huán)境變化的應(yīng)變能力,組件之間的數(shù)據(jù)交互能力也較差。它與系統(tǒng)和其它的控制組件的耦合性較小,要完全同其它組件融合在一起并在大的系統(tǒng)環(huán)境中良好地運(yùn)轉(zhuǎn)和適度靈活的應(yīng)變系統(tǒng)的變化是比較困難的。這就需要在組態(tài)設(shè)計(jì)系統(tǒng)中使用輔助控制語(yǔ)言對(duì)這些組件的活動(dòng)加以控制,規(guī)范控制流程。如圖1所示,在組態(tài)設(shè)計(jì)系統(tǒng)中引入事件(Event)的概念,在事件的響應(yīng)函數(shù)中使用輔助控制語(yǔ)言規(guī)范控制流程和組件的活動(dòng),經(jīng)過(guò)編譯后生成中間代碼提交給組態(tài)運(yùn)行系統(tǒng)。相應(yīng)地在組態(tài)運(yùn)行系統(tǒng)中建立解釋環(huán)境對(duì)中間代碼進(jìn)行解釋執(zhí)行,從而達(dá)到規(guī)范流程控制的目的。
[align=center]
圖1 編譯和解釋運(yùn)行原理圖[/align]
2 COM組件和自動(dòng)化對(duì)象
COM是用于開(kāi)發(fā)分布式軟件模型的組件化程序設(shè)計(jì)模型,它是建立在二進(jìn)制可執(zhí)行代碼級(jí)基礎(chǔ)上的。支持IDispatch接口的COM組件對(duì)象稱為自動(dòng)化對(duì)象,該接口允許將一個(gè)函數(shù)的名稱以字符串的形式提交給組件,組件根據(jù)函數(shù)的名稱自動(dòng)調(diào)用相應(yīng)的函數(shù)。該接口提供的這種機(jī)制可實(shí)現(xiàn)對(duì)COM組件的統(tǒng)一調(diào)度。本文介紹的編譯器和解釋器的工作就建立在該機(jī)制之上,它為如何在解釋執(zhí)行環(huán)境中啟動(dòng)二進(jìn)制可執(zhí)行代碼提供了很好的解決方案。
3 編譯器和解釋器體系的框架分析
3.1 控制語(yǔ)言功能的選擇
C語(yǔ)言功能豐富,表達(dá)能力強(qiáng),目標(biāo)程序效率高,可移植性好,控制靈活,普及面廣,非常適用于工業(yè)控制領(lǐng)域。C語(yǔ)言功能強(qiáng),語(yǔ)法規(guī)則也很龐大,但是要構(gòu)造一個(gè)完整的C語(yǔ)言編譯器用于流程的控制則顯得過(guò)于浪費(fèi)。我們構(gòu)造了C語(yǔ)言語(yǔ)法規(guī)則的一個(gè)子集——Child-C,該子集保留了C語(yǔ)言的分支、循環(huán)、賦值、常量和變量的定義以及函數(shù)調(diào)用等基本語(yǔ)法規(guī)則,去掉了匯編語(yǔ)言的處理能力。
3.2 中間代碼編譯器與二進(jìn)制代碼編譯器邊界的劃分
由上面的分析可以看出,整個(gè)控制系統(tǒng)要實(shí)現(xiàn)的功能代碼要經(jīng)過(guò)中間代碼編譯器與二進(jìn)制代碼編譯器兩種編譯器共同編譯。如圖2所示,我們可以把完整編譯器所具備的功能看成是一個(gè)大的集合,在這個(gè)集合中可以找到一條分界線:分界線左邊的功能是中間代碼編譯器必須具備的,它需要我們自己設(shè)計(jì)實(shí)現(xiàn);分界線右邊的功能是二進(jìn)制代碼編譯器所具備的,可以編譯出高效的具有數(shù)據(jù)運(yùn)算處理等功能的二進(jìn)制機(jī)器碼,它不需要我們動(dòng)手實(shí)現(xiàn)。這條分界線是可以移動(dòng)的,我們需要盡量使它向左移動(dòng),壓縮中間代碼編譯器的功能,從而減少開(kāi)發(fā)的工作量。把復(fù)雜的數(shù)據(jù)處理能力和底層訪問(wèn)能力放到右邊。
[align=center]
圖2 兩類編譯器的分界[/align]
3.3 運(yùn)行時(shí)存儲(chǔ)空間組織
Child-C能夠處理的數(shù)據(jù)類型除了C語(yǔ)言中傳統(tǒng)的長(zhǎng)短整形、浮點(diǎn)、實(shí)數(shù)、字符、數(shù)組、指針和結(jié)構(gòu)體外還有COM對(duì)象。如圖3a所示,它描述了操作系統(tǒng)、組態(tài)軟件運(yùn)行系統(tǒng)和解釋器運(yùn)行時(shí)三者存儲(chǔ)空間之間的關(guān)系。它們是包含的關(guān)系,解釋器是被組態(tài)軟件運(yùn)行系統(tǒng)建立的,所以它實(shí)際上屬于組態(tài)軟件運(yùn)行系統(tǒng)的一部分。如圖3b所示,解釋器運(yùn)行時(shí)存儲(chǔ)空間可以分為6部分。第一部分占64個(gè)字節(jié),它存儲(chǔ)了兩組共16個(gè)虛擬寄存器,名稱為R0,R1,R2…依次類推。第一組包含8個(gè)寄存器,它用來(lái)完成除了變長(zhǎng)字符串之外的所有中間指令數(shù)據(jù)操作。第二組包含8個(gè)寄存器,它專門用來(lái)完成變長(zhǎng)字符串相關(guān)指令的操作。第二部分占12個(gè)字節(jié),它存儲(chǔ)了3個(gè)32位的無(wú)符號(hào)整數(shù),分別記錄了全局堆基址、全局變量基址和運(yùn)行時(shí)堆基址。第三部分是COM組件地址映射區(qū),該區(qū)的作用將在后面詳細(xì)描述。第四部分是全局堆存儲(chǔ)區(qū),它用來(lái)存儲(chǔ)Child-C代碼中用 new 操作符動(dòng)態(tài)申請(qǐng)的數(shù)據(jù)空間以及所有的變長(zhǎng)字符串?dāng)?shù)據(jù),該區(qū)的大小是在解釋器啟動(dòng)前設(shè)定的,解釋器一但運(yùn)行該值就不能改變。第五部分為全局變量存儲(chǔ)區(qū),該區(qū)存儲(chǔ)的是可以被所有函數(shù)訪問(wèn)的全局參數(shù),如控制環(huán)境的平均溫度和濕度等。第六部分為運(yùn)行時(shí)棧存儲(chǔ)區(qū),Child-C編寫的函數(shù)全部運(yùn)行在這個(gè)空間之上,它不但存儲(chǔ)函數(shù)體定義的形參、變量和返回值,還要存儲(chǔ)過(guò)程調(diào)用和返回時(shí)所需的控制鏈數(shù)據(jù)。
[align=center]
圖3 存儲(chǔ)空間關(guān)系圖(a)和運(yùn)行時(shí)存儲(chǔ)空間示意圖(b)[/align]
3.4 中間代碼操作數(shù)的定義
Child-C程序被編譯成中間代碼指令被解釋器執(zhí)行,如以下的Child-C語(yǔ)句執(zhí)行相加操作:
int a,b,c; a=b+c;
它被編譯為如下幾條中間代碼指令:
LOD R0 Ox00000010 4; ①—— 加載變量a到寄存器R0,Ox00000010是變量a在運(yùn)行時(shí)堆存儲(chǔ)區(qū)內(nèi)的偏移地址,4表示加載的數(shù)據(jù)為4個(gè)字節(jié)
LOD R1 Ox00000014 4; ②—— 加載變量b到寄存器R1
ADD ③—— R1+R0->R2,三個(gè)寄存器的意義是固定的
STR R2 Ox00000018 ④— 將寄存器R2的值保存到變量c中
其中指令③的ADD指令是二元操作數(shù)指令,但是它的操作數(shù)固定為R0和R1寄存器,計(jì)算結(jié)果也固定放到R3中。
3.5 字符串的兼容和特殊處理
C語(yǔ)言中的字符串是通過(guò)字符數(shù)組進(jìn)行處理的,Child-C繼承了這種字符串處理方法。字符數(shù)組是長(zhǎng)度固定的字符串,而在使用Child-C與COM組件交互時(shí)經(jīng)常要處理COM標(biāo)準(zhǔn)的BSTR類型變長(zhǎng)字符串,為了兼容該數(shù)據(jù)類型,在Child-C中增加了bstr類型的變長(zhǎng)字符串?dāng)?shù)據(jù)類型。bstr由頭尾兩部分組成:頭部信息由head和len兩個(gè)32位無(wú)符號(hào)整形組成,頭部信息代表了字符串實(shí)體,它可以作為局部和全局變量存儲(chǔ),head是一個(gè)指針,它指向字符數(shù)據(jù)在全局堆中的首地址,len記錄了字符串的長(zhǎng)度。尾部信息保存在全局堆存儲(chǔ)區(qū)中,字符信息在該區(qū)中并不是連續(xù)的,這也適應(yīng)了字符串長(zhǎng)度變化的需要。bstr可以直接代替BSTR類型,中間代碼指令集中有專門的轉(zhuǎn)換指令COMTOC和CTOCOM進(jìn)行數(shù)據(jù)轉(zhuǎn)換。當(dāng)需要將bstr轉(zhuǎn)換成BSTR時(shí),編譯器自動(dòng)添加COMTOC指令,該指令根據(jù)bstr的頭信息讀取字符數(shù)據(jù)組裝成BSTR數(shù)據(jù)提交給COM組件,而CTOCOM是一個(gè)逆過(guò)程。這兩條指令使用特設(shè)的第二組虛擬寄存器進(jìn)行轉(zhuǎn)換操作。
3.6 COM組件的訪問(wèn)
COM對(duì)象的訪問(wèn)需要進(jìn)行特殊處理,它是在解析運(yùn)行環(huán)境建立之前就已經(jīng)存在的。如圖3a所示,它存儲(chǔ)在組態(tài)軟件系統(tǒng)的存儲(chǔ)空間中,它不會(huì)隨著解釋運(yùn)行環(huán)境的消亡而消亡。而除此之外的數(shù)據(jù)都存儲(chǔ)在解釋器的存儲(chǔ)空間中,它們會(huì)隨著解釋運(yùn)行環(huán)境的消亡而消亡。為了便于編譯器和解釋器統(tǒng)一存儲(chǔ)空間的處理,需要將COM組件映像到解釋器存儲(chǔ)空間中,圖3b中的COM組件地址映射區(qū)就用來(lái)保存COM組件地址的映像。在編譯器和解釋器的運(yùn)行過(guò)程中,所有對(duì)COM組件的訪問(wèn)都被映射到該區(qū)域,從而避免了存儲(chǔ)空間的交叉訪問(wèn)。
3.7 解釋器環(huán)境中對(duì)COM組件方法的調(diào)用
COM組件的各種函數(shù)已經(jīng)被編譯成可被計(jì)算機(jī)直接執(zhí)行的機(jī)器代碼,自動(dòng)化COM對(duì)象允許使用IDispatch接口的統(tǒng)一調(diào)度函數(shù)Invoke()調(diào)用組件的函數(shù),被執(zhí)行的函數(shù)可以當(dāng)作一個(gè)字符串參數(shù)被傳送。因此在構(gòu)造的中間代碼指令集中有一條INVOKE指令,該指令格式為:INVOKE ComOffset FuncOffset ParaOffset;該指令有三個(gè)操作數(shù):ComOffset為要訪問(wèn)的COM組件在COM組件地址映射區(qū)的偏移,F(xiàn)uncOffset為被調(diào)用函數(shù)的名稱bstr變量地址,ParaOffset是該函數(shù)參數(shù)的個(gè)數(shù)和參數(shù)的存儲(chǔ)單元地址,該存儲(chǔ)區(qū)之后是一個(gè)4字節(jié)的單元,它用來(lái)保存Invoke()函數(shù)執(zhí)行的返回值。就是說(shuō),對(duì)COM組件的所有操作,解釋器只需通過(guò)執(zhí)行Invoke()函數(shù)就能完成。
4 事件體系的構(gòu)造
Child-C函數(shù)是通過(guò)事件觸發(fā)而被調(diào)用的。事件包含兩種類型,一種是組件運(yùn)行系統(tǒng)定義的事件,該類型事件屬于整個(gè)系統(tǒng),它與具體組件無(wú)關(guān),但可以被COM組件和系統(tǒng)觸發(fā)。另一種是COM組件自定義的事件,該類型事件屬于COM組件,它只能被組件自身觸發(fā)。事件發(fā)生時(shí)觸發(fā)解釋器解釋運(yùn)行事件的相應(yīng)函數(shù)。事件的處理工作全部交給事件槽來(lái)處理,事件槽實(shí)際上是一個(gè)可鏈接對(duì)象接收器[5],它可以接受系統(tǒng)和COM組件觸發(fā)的事件,同時(shí)它還維護(hù)了一張事件映射表,該表記錄了所有添加了響應(yīng)函數(shù)的事件和該事件響應(yīng)函數(shù)的入口地址以及有關(guān)參數(shù)信息。當(dāng)有事件到達(dá)時(shí),首先檢查事件映射表該事件是否有被注冊(cè),如果有則根據(jù)響應(yīng)函數(shù)的參數(shù)信息分配存儲(chǔ)空間并調(diào)用響應(yīng)函數(shù)。
5 結(jié)束語(yǔ)
在實(shí)際的生產(chǎn)應(yīng)用中可以證明,Child-C完全可以勝任絕大部分流程控制的需要,提高了工控組態(tài)軟件的靈活性。解釋器環(huán)境開(kāi)發(fā)難度小但是程序執(zhí)行效率低,自動(dòng)化COM組件的函數(shù)調(diào)度機(jī)制可以很好的解決這種矛盾,該機(jī)制還可以廣泛地應(yīng)用于其它領(lǐng)域。
參考文獻(xiàn):
[1] 李志剛.工控組態(tài)軟件及其在工業(yè)控制中的應(yīng)用[J].微機(jī)算計(jì)信息,1998;14(3)
[2] 夏坤,張建國(guó),蔣洪. COM+及其在組態(tài)軟件中的應(yīng)用研究[J].計(jì)算機(jī)工程與應(yīng)用,2002,20.117-119
[3] 王培進(jìn).面向?qū)ο蟮娜嵝栽O(shè)計(jì)與控制理論(I)[J].計(jì)算機(jī)工程與應(yīng)用,2001;36(16):17-19
[4] 潘愛(ài)民.COM原理與應(yīng)用[M].北京:清華大學(xué)出版社,1999.12
[5] KennethCLouden.編譯原理與實(shí)踐[M].北京:機(jī)械工業(yè)出版社,1998.
[6] 熊清平,張正勇,李作清.CNC系統(tǒng)巨量NC程序解釋實(shí)現(xiàn)的方法[J].中國(guó)機(jī)械工程,1999,10(6):673-675.