1. 前言
在企業(yè)"管控一體化"的信息系統(tǒng)建設(shè)中,實時信息系統(tǒng)起著非常重要的作用。它可以采集控制系統(tǒng)中的實時數(shù)據(jù),使管理者在辦公室里就可以監(jiān)測到生產(chǎn)現(xiàn)場的生產(chǎn)情況及報警信息;并可以對取得的實時數(shù)據(jù)進行優(yōu)化、分析,從而為保證生產(chǎn)設(shè)備正常運轉(zhuǎn)、降低成本提供重要基礎(chǔ)。作為制造執(zhí)行系統(tǒng),MES必然要求與企業(yè)其它生產(chǎn)管理系統(tǒng)有密切關(guān)系,MES在其中起到了信息集線器(Information Hub)的作用,它相當(dāng)于一個通訊工具為其它應(yīng)用系統(tǒng)提供生產(chǎn)現(xiàn)場的實時數(shù)據(jù)。
作為信息集線器的MES要將來自不同硬件生產(chǎn)廠商的控制系統(tǒng)的現(xiàn)場數(shù)據(jù)匯總在實時數(shù)據(jù)庫中,必須要和不同的設(shè)備,比如PLC,變頻器,現(xiàn)場總線的儀表等通訊,如果不同的設(shè)備廠家都遵守一個相同的程序接口標準的話,那么程序和不同設(shè)備的溝通將變得非常容易。OPC 就是這樣一種工業(yè)標準,它是OLE for process control 的英文縮寫。OPC 是基于微軟的COM(Component Object Model)和OLE(Object Linking and Embedding)技術(shù)之上的。和以前不同的是,現(xiàn)在設(shè)備廠家提供不同的OPC Server。OPC Server負責(zé)從設(shè)備中取數(shù)據(jù)和寫數(shù)據(jù)。用戶所要做的就是利用統(tǒng)一的COM 規(guī)范編寫OPC Client。客戶程序和OPC Server 打交道。OPC Server是一座在客戶和硬件設(shè)備之間的橋梁,通過它,我們可以很容易的取得現(xiàn)場的溫度,壓力,流量,位置等信號,以及控制現(xiàn)場的閥門開度,電機轉(zhuǎn)速等。注意客戶程序和服務(wù)器程序可以在同一臺計算機上,也可以在不同的計算機上,區(qū)別是使用COM 還是使用DCOM。
2. 項目背景
我們開發(fā)的OPC服務(wù)器的項目背景是貴鋁熱電廠的數(shù)據(jù)上網(wǎng)項目。此項目中的一個子項目需要將現(xiàn)場的一些重要輔機的溫度值上傳至熱電廠的熱網(wǎng)之中。在數(shù)據(jù)的接口上我們選擇使用OPC作為統(tǒng)一的數(shù)據(jù)接口,因此我們在輔機溫度巡檢系統(tǒng)中需要實際開發(fā)其相應(yīng)的數(shù)據(jù)訪問服務(wù)器,用于和實時數(shù)據(jù)庫服務(wù)器通訊以便于將數(shù)據(jù)上傳至熱電廠的熱網(wǎng)之中。以下我以此項目為例來介紹OPC數(shù)據(jù)訪問服務(wù)器的開發(fā)過程。服務(wù)器的開發(fā)工具通常是在VC6環(huán)境中使用MFC類庫搭配ATL,我選擇了Delphi7。因為Delphi是功能強大的應(yīng)用程序開發(fā)工具。它具有功能強大,運行速度快,易于學(xué)習(xí)和使用以及開發(fā)效率高等特點。它是可視化應(yīng)用編程環(huán)境,可重用性面向?qū)ο缶幊陶Z言,快速編譯器和數(shù)據(jù)庫的完美組合。編寫OPC定制接口的客戶程序的本質(zhì)就是編寫COM客戶程序,而使用Delphi進行COM開發(fā)時,我們會發(fā)現(xiàn)Object Pascal為COM提供了強大的語言支持。
圖表 1 輔機溫度巡檢網(wǎng)絡(luò)連接圖
3. OPC服務(wù)器的結(jié)構(gòu)
下面首先給出OPC服務(wù)器的內(nèi)部結(jié)構(gòu)。
圖表 2 OPC服務(wù)器的內(nèi)部結(jié)構(gòu)
OPC規(guī)范提供了兩套接口方案,即COM接口和自動化。COM接口效率高,通過該接口,客戶能夠發(fā)揮OPC服務(wù)器的最佳性能,采用C++語言的客戶一般采用COM接口方案;自動化接口一般為采用VB語言的客戶所采用。自動化接口使解釋性語言和宏語言編寫客戶應(yīng)用程序變得簡單,然而自動化客戶運行時需進行類型檢查,這一點則大大犧牲了程序的運行速度。OPC服務(wù)器必須實現(xiàn)COM接口,是否實現(xiàn)自動化接口則取決于供應(yīng)商的主觀意愿。通常可以直接使用OPC基金會提供的OPC自動化包裝DLL(OPCDAAuto.DLL),將OPC定制接口變換成OPC自動化接口。當(dāng)然也可以自己編制自動化包裝器。
圖表 3 OPC服務(wù)器通過自動化包裝器提供OPC自動化接口
4. OPC服務(wù)器對象模型
OPC服務(wù)器由三類對象組成,相當(dāng)于三種層次上的接口:服務(wù)器(Server)、組(Group) 和數(shù)據(jù)項(Item)。
1) 服務(wù)器對象(Server)
擁有服務(wù)器的所有信息,同時也是組對象(Group)的容器,一個服務(wù)器對應(yīng)于一個OPC Server,即一種設(shè)備的驅(qū)動程序。在一個Server中,可以有若干個組。
2) 組對象(Group)
擁有本組的所有信息,同時包容并邏輯組織OPC數(shù)據(jù)項(Item)。
OPC組對象(Group)提供了客戶組織數(shù)據(jù)的一種方法,組是應(yīng)用程序組織數(shù)據(jù)的一個單位。客戶可對之進行讀寫,還可設(shè)置客戶端的數(shù)據(jù)更新速率。當(dāng)服務(wù)器緩沖區(qū)內(nèi)數(shù)據(jù)發(fā)生改變時,OPC將向客戶發(fā)出通知,客戶得到通知后再進行必要的處理,而無需浪費大量的時間進行查詢。OPC規(guī)范定義了兩種組對象:公共組(或稱:全局組,public)和局部組(或稱:局域組、私有組,Local)。公共組由多個客戶共有,局部組只隸屬于一個OPC客戶。全局組對所有連接在服務(wù)器上的應(yīng)用程序都有效,而局域組只能對建立它的Client有效。一般說來,客戶和服務(wù)器的一對連接只需要定義一個組對象。在一個組中,可以有若干個項。
3) 項
項是讀寫數(shù)據(jù)的最小邏輯單位。一個項與一個具體的位號相連。項不能獨立于組存在,必須隸屬于某一個組。在每個組對象中,客戶可以加入多個OPC數(shù)據(jù)項(Item)。OPC數(shù)據(jù)項是服務(wù)器端定義的對象,通常指向設(shè)備的一個寄存器單元。OPC客戶對設(shè)備寄存器的操作都是通過其數(shù)據(jù)項來完成的,通過定義數(shù)據(jù)項,OPC規(guī)范盡可能的隱藏了設(shè)備的特殊信息,也使OPC服務(wù)器的通用性大大增強。OPC數(shù)據(jù)項并不提供對外接口,客戶不能直接對之進行操作,所有操作都是通過組對象進行的。每個數(shù)據(jù)項的數(shù)據(jù)結(jié)構(gòu)包括三個成員變量:數(shù)據(jù)值、數(shù)據(jù)質(zhì)量和時間戳。數(shù)據(jù)值是以VARIANT形式表示的。應(yīng)當(dāng)注意,數(shù)據(jù)項表示同數(shù)據(jù)源的連接而不等同于數(shù)據(jù)源,無論客戶是否定義數(shù)據(jù)項,數(shù)據(jù)源都是客觀存在的。可以把數(shù)據(jù)項看作數(shù)據(jù)源的地址,即數(shù)據(jù)源的引用,而不應(yīng)看作數(shù)據(jù)源本身。組與項的關(guān)系如下圖所示:
圖表 4 OPC服務(wù)器的對象模型
應(yīng)用程序作為OPC接口中的Client方,硬件驅(qū)動程序作為OPC接口中的Server方。每一個OPC Client應(yīng)用程序都可以接若干個OPC Server,每一個硬件驅(qū)動程序可以為若干個應(yīng)用程序提供數(shù)據(jù)。
5. OPC服務(wù)器對象接口
OPC服務(wù)器是通過接口向客戶提供服務(wù)的,接口實際上是一組相關(guān)函數(shù)的集合。
(1) OPCServer對象接口
OPCServer對象是OPC中的首要對象,它提供了如下接口:
IUnknown接口是COM的標準接口
IOPCServer接口可對OPCGroup對象進行有關(guān)操作
IOPCServerPublicGroups接口為客戶和服務(wù)器提供了管理公共組的功能
IOPCBrowseServerAddressSpace接口提供了客戶瀏覽服務(wù)器數(shù)據(jù)項的功能
IOPCItemProperties接口讓客戶能夠瀏覽與ItemID相關(guān)的可訪問屬性
IOPCCommon接口提供了設(shè)置和詢問LocaleID的功能
IPersistFile接口允許客戶裝載和保存服務(wù)器的配置信息
IConnectionPointContainer接口允許用戶探查發(fā)現(xiàn)連接點
圖表 5 OPCServer對象接口圖
(2) OPCGroup對象接口
OPCGroup對象是管理數(shù)據(jù)項集合的對象,它提供的接口如下:
IUnknown接口是COM的標準接口
IOPCItemMgt接口為客戶提供了添加,刪除和控制組中數(shù)據(jù)項的功能
IOPCGroupStateMgt接口允許客戶管理組中的所有狀態(tài)信息
IOPCPublicGroupStateMgt接口用來將私有組轉(zhuǎn)換為公共組
IOPCSyncIO接口允許用戶對服務(wù)器執(zhí)行同步讀寫操作
IOPCAsyncIO接口允許客戶對服務(wù)器執(zhí)行異步讀寫操作
IOPCAsyncIO2接口用來替代IOPCAsyncIO接口
IConnectionPointContainer接口允許用戶探查發(fā)現(xiàn)連接點
IDataObject接口允許客戶和使用OPC數(shù)據(jù)流格式的組之間產(chǎn)生連接
圖表 6 OPCGroup對象接口圖
6. OPC服務(wù)器的Delphi實現(xiàn)
本項目的輔機溫度巡檢OPC數(shù)據(jù)訪問服務(wù)器使用Delphi7開發(fā),其遵守OPC Data Access 2.05規(guī)范。本服務(wù)器功能如下:
服務(wù)器的注冊與反注冊
定時讀取現(xiàn)場數(shù)據(jù)并更新數(shù)據(jù)緩沖池
OPCServer對象的實現(xiàn)
OPCGroup對象的實現(xiàn)
服務(wù)器的界面顯示
程序?qū)崿F(xiàn)如下:
(1) 服務(wù)器的注冊與反注冊
OPC服務(wù)器必須按照規(guī)范要求正確注冊才能被OPC客戶訪問。OPC服務(wù)器按照組件模式可以劃分為進程內(nèi)組件、進程外組件。不同模式的服務(wù)器注冊的方法稍有差異。
通常OPC服務(wù)器要求的標識格式為:Vendor.Drivername.Version
我的溫度巡檢OPC服務(wù)器的標識為:HUA.DA2.1
按照OPC規(guī)范要求,我的OPC服務(wù)器在系統(tǒng)注冊表中建立如下注冊表項:
1至6項對于不同模式的服務(wù)器均需要:
1. HKEY_CLASSES_ROOT\Vendor.Drivername.Version = A Description of your server
2. HKEY_CLASSES_ROOT\Vendor.Drivername.Version\CLSID = {Your Server's unique CLSID}
3. HKEY_CLASSES_ROOT\Vendor.Drivername.Version\OPC
4. HKEY_CLASSES_ROOT\Vendor.Drivername.Version\OPC\Vendor =Your vendor name
5. HKEY_CLASSES_ROOT\CLSID\{Your Server's unique CLSID} = A Description of your server
6. HKEY_CLASSES_ROOT\CLSID\{Your Server's unique CLSID}\ProgID = Vendor.Drivername.Version
7至8項根據(jù)服務(wù)器的模式進行選擇注冊:
7. HKEY_CLASSES_ROOT\CLSID\{Your Server's unique CLSID}\InprocServer32 = Full Path to DLL
8. HKEY_CLASSES_ROOT\CLSID\{YourServer's unique CLSID}\LocalServer32 = Full Path to EXE
9. HKEY_CLASSES_ROOT\CLSID\{YourServer's unique CLSID}\InprocHandler32 = Full Path to DLL
步驟1的代碼示例如下:
aReg:=nil;
try
aReg:=TRegistry.Create;
aReg.RootKey:=HKEY_CLASSES_ROOT;
aReg.OpenKey(HUA.DA2.1,true);
aReg.WriteString('','HUA Data Access Server Version 2.0');
finally
aReg.CloseKey;
aReg.Free;
end;
此外,還應(yīng)根據(jù)規(guī)范創(chuàng)建組件的分類信息,以便與組件分類管理。對于數(shù)據(jù)訪問服務(wù)器規(guī)范提供的組件類別為:
"OPC Data Access Servers Version 1.0"
CATID_OPCDAServer10 = {63D5F430-CFE4-11d1-B2C8-0060083BA1FB}
"OPC Data Access Servers Version 2.0"
CATID_OPCDAServer20 = {63D5F432-CFE4-11d1-B2C8-0060083BA1FB}
創(chuàng)建類別的程序代碼為:
CreateComponentCategory(CATID_OPCDAServer20,'HUA OPC Data Access');
RegisterCLSIDInCategory(CLASS_HUA_DA2,CATID_OPCDAServer20);
實現(xiàn)服務(wù)器的反注冊就簡單了,逐一清除掉以上所建立的注冊表項即可:
aReg:=nil;
try
aReg:=TRegistry.Create;
aReg.RootKey:=HKEY_CLASSES_ROOT;
aReg.DeleteKey(name);
finally
aReg.CloseKey;
aReg.Free;
end;
還應(yīng)刪除自己組件類別信息
UnRegisterCLSIDInCategory(CLASS_HUA_DA2,CATID_OPCDAServer20);
UnCreateComponentCategory(CATID_OPCDAServer20,'HUA OPC Data Access');
(2) 定時讀取現(xiàn)場數(shù)據(jù)并更新數(shù)據(jù)緩沖池
OPC服務(wù)器本身就是一個可執(zhí)行程序,該程序以設(shè)定的速率不斷地同物理設(shè)備進行數(shù)據(jù)交互。服務(wù)器內(nèi)有一個數(shù)據(jù)緩沖區(qū),其中存有最新的數(shù)據(jù)值,數(shù)據(jù)質(zhì)量戳和時間戳。時間戳表明服務(wù)器最近一次從設(shè)備讀取數(shù)據(jù)的時間。服務(wù)器對設(shè)備寄存器的讀取是不斷進行的,時間戳也在不斷更新。即使數(shù)據(jù)值和質(zhì)量戳都沒有發(fā)生變化,時間戳也會進行更新。客戶既可從服務(wù)器緩沖區(qū)讀取數(shù)據(jù),也可直接從設(shè)備讀取數(shù)據(jù),從設(shè)備直接讀取數(shù)據(jù)速度會慢一些,一般只有在故障診斷或極特殊的情況下才會采用。
OPC客戶和OPC服務(wù)器進行數(shù)據(jù)交互可以有兩種不同方式,即同步方式和異步方式。同步方式實現(xiàn)較為簡單,當(dāng)客戶數(shù)目較少而且同服務(wù)器交互的數(shù)據(jù)量也比較少的時候可以采用這種方式;異步方式實現(xiàn)較為復(fù)雜,需要在客戶程序中實現(xiàn)服務(wù)器回調(diào)函數(shù)。然而當(dāng)有大量客戶和大量數(shù)據(jù)交互時,異步方式能提供高效的性能,盡量避免阻塞客戶數(shù)據(jù)請求,并最大可能地節(jié)省CPU和網(wǎng)絡(luò)資源。
本服務(wù)器的數(shù)據(jù)緩沖池的數(shù)據(jù)格式是按照OPC數(shù)據(jù)訪問規(guī)范中的 OPCITEMSTATE格式設(shè)計的。
type
TOPCItem=record
strID:string;//點的ID編號
bActive:longbool;//點的激活狀態(tài)
ItemState:OPCITEMSTATE;//點的客戶訪問項
end;
type
OPCITEMSTATE = record
hClient: OPCHANDLE;//點的客戶句柄
ftTimeStamp: TFileTime;//點的時間戳
wQuality: Word;//點的品質(zhì)
wReserved: Word;//保留
vDataValue: OleVariant;//點的值
end;
本溫度采集項目選用研華的亞當(dāng)4000系列模塊,OPC服務(wù)器通過計算機串口與ADAM-4520模塊連接,這是一塊隔離RS232到RS422/485轉(zhuǎn)換器。現(xiàn)場模塊通過485總線與其連在一起。數(shù)據(jù)的采集方式如下圖所示
圖表 7 溫度巡檢系統(tǒng)配置圖
對于服務(wù)器來說實現(xiàn)現(xiàn)場數(shù)據(jù)的采集,只需要對串口進行編程即可。串口編程的方法很多,例如:Windows API方式、在程序中嵌入?yún)R編語言操作端口、使用控件等。我選擇了使用控件。不同公司開發(fā)的串口控件很多,我使用的是微軟的MSComm控件。編程時只需要參照研華的相關(guān)模塊操作命令表,然后使用MSComm控件發(fā)出相應(yīng)的命令進行操作即可。例如根據(jù)如下命令表
圖表 8 ADAM-4015命令表摘錄
對于命令#AAN 意思是讀取地址為AA的模塊的第N通道數(shù)據(jù)。如果操作正確則模塊響應(yīng)為>(data)(cr)
如果在程序中發(fā)出如下命令:
MSComm1.Output :='#021'+#13; //讀取2號模塊的第一通道數(shù)據(jù)
2號模塊的響應(yīng)為:>+1.4567(cr)
(3) OPCServer對象的實現(xiàn)
必須嚴格按照規(guī)范要求,實現(xiàn)所要求的所有接口函數(shù)。但是這并不意味著所有的接口函數(shù)都必須自己編寫,我們可以充分利用COM的包容與聚合機制來復(fù)用一些常規(guī)的接口。在Delphi中有很多現(xiàn)成的類已經(jīng)實現(xiàn)了眾多的接口,我們可以充分利用這一點來簡化我們的編程過程。例如在我的 OPCServer服務(wù)器對象中IUnknown接口是通過父類TAutoObject 實現(xiàn)的,IConnectionPointContainer 接口是通過創(chuàng)建一個Delphi的TConnectionPoints對象,然后將其接口暴露給客戶實現(xiàn)的; OPCServer的Delphi描述如下,限于篇幅具體實現(xiàn)過程從略:
type
THUA_DA2 = class(TAutoObject,IHUA_DA2,
IOPCServer,IConnectionPointContainer,IOPCCommon,IOPCItemProperties,
IOPCServerPublicGroups,IOPCBrowseServerAddressSpace,IPersist,IPersistFile)
public
ClientIUnknown:IUnknown;
Grp:TOPCGroup;
procedure Initialize; override;
procedure ShutdownOnConnect(const Sink: IUnknown; Connecting: Boolean);
destructor Destroy;override;
private
FIConnectionPoints:TConnectionPoints;
protected
property iFIConnectionPoints:TConnectionPoints read FIConnectionPoints
write FIConnectionPoints implements IConnectionPointContainer;
//IOPCServer 接口描述省略
//IOPCCommon接口描述省略
//IOPCServerPublicGroups接口描述省略
//IOPCBrowseServerAddressSpace接口描述省略
//IPersistFile接口描述省略
//IOPCItemProperties接口描述省略
end;//end type
(4) OPCGroup對象的實現(xiàn)
OPCGroup對象是由OPCServer對象創(chuàng)建的。當(dāng)OPC客戶程序調(diào)用OPCServer對象的接口函數(shù)AddGroup時,在AddGroup函數(shù)體內(nèi)生成OPCGroup對象。以后用戶依賴與指向這個OPCGroup接口的指針,便可以方便的創(chuàng)建和管理點項目,從而獲得現(xiàn)場的實時數(shù)據(jù)。OPCGroup對象的描述如下:
type
TOPCGroup = class(TTypedComObject,IOPCGroup,IOPCItemMgt,IOPCGroupStateMgt,
IOPCPublicGroupStateMgt,IOPCSyncIO,
IConnectionPointContainer,IOPCAsyncIO2)
private
FIConnectionPoints:TConnectionPoints;
protected
property iFIConnectionPoints:TConnectionPoints read FIConnectionPoints
write FIConnectionPoints implements IConnectionPointContainer;
//IOPCItemMgt 接口描述省略
//IOPCGroupStateMgt接口描述省略
//IOPCPublicGroupStateMgt接口描述省略
//IOPCSyncIO接口描述省略
//IOPCAsyncIO2接口描述省略
end;
(5) 服務(wù)器的界面顯示
OPC服務(wù)器的主要功能在于數(shù)據(jù)的傳遞,它常常并不需要過多的人機交互過程。項目中的OPC服務(wù)器只是為了調(diào)試的方便,在界面中通過兩個按鈕向用戶提供了服務(wù)器的注冊與反注冊功能。在服務(wù)器中還顯示了所連接的OPC客戶數(shù)和OPC客戶創(chuàng)建的OPC組數(shù)目,以及數(shù)據(jù)緩沖池中的數(shù)據(jù)更新情況。
7. 結(jié)語
總的來說,進行OPC服務(wù)器程序的開發(fā)就是嚴格按照OPC規(guī)范編寫各種接口函數(shù)來向客戶提供服務(wù),在定時更新緩沖池中的數(shù)據(jù)的同時,還應(yīng)對緩沖池中的數(shù)據(jù)提供較快的查詢服務(wù)從而減少系統(tǒng)延遲。