使用示例程序
該程序包括多個元素,操作員可使用這些元素觸發(fā)以下動作:
啟動程序時,僅啟用“啟動示例” (Start Sample) 按鈕。單擊此按鈕后,程序?qū)⑸伤璧?OPC 對象。隨即會啟用其它按鈕。
單擊“ 啟動示例” (Start Sample) 按鈕后,以 C# 編寫并使用 .NET- Framework 的 OPC 自定義接口(異步通信)的示例程序的啟動對話框 .
程序說明:
1 選擇 .NET 組件
2 將 ProgID 轉(zhuǎn)換為 CLSID
3 建立與 OPC 服務(wù)器的連接
4 創(chuàng)建 OPC 組
5 添加數(shù)據(jù)項
6 請求 IConnectionPointContainer 接口
7 請求 IOPCAsyncIO2 接口
8 創(chuàng)建回調(diào)對象
9 連接 OPC 服務(wù)器與客戶端的回調(diào)對象
10 執(zhí)行所需的寫入和讀取操作
11 接收 OPC 服務(wù)器的通知
12 刪除對象并釋放內(nèi)存
步驟 1:選擇 .NET 組件
要配合使用 OPC 數(shù)據(jù)訪問的自定義接口和 .NET,必須在您的 Visual Basic 項目中使用上述運行時可調(diào)用包裝 (RCW) 。在該示例項目中,OpcRcw.Da 和 OpcRcw.Comn 組件已添完畢。
如果它們未出現(xiàn)在選項中,也可使用“瀏覽” (Browse) 按鈕從下列文件夾中進(jìn)行選擇:“ <安裝路徑> SIEMENS SIMATIC.NET opc2in”
步驟 2:將 ProgID 轉(zhuǎn)換為 CLSID
為了對其進(jìn)行標(biāo)識,每個 COM 服務(wù)器都有一個 ProgID 且該 ProgID 分配給世界上唯一的類型。使用 GetTypeFromProgID() 函數(shù)可實現(xiàn)上述操作。SIMATIC NET 的 OPC 服務(wù)器的 ProgID 是 L"OPC.SimaticNET":
Type svrComponenttyp = Type.Get TypeFromProgID(L"OPC.SimaticNET");
步驟 3:建立與 OPC 服務(wù)器的連接
Activator 類的 CreateInstance() 函數(shù)生成一個具有之前指定類型的類的實例:
pIOPCServer =
(IOPCServer)Activato r.CreateInstance(svrComponenttyp
);
該程序段的結(jié)果是 IOPCServer 類型的接口變量 pIOPCServer。
步驟 4:創(chuàng)建 OPC 組
IOPCServer 接口具有用于創(chuàng)建組的 AddGroup() 方法:
pIOPCServer.AddGroup(GROUP_NAME,
0,
dwRequestedUpdateRate,
hClientGroup,
hTimeBias..AddrOfPinnedObject(),
hDeadban d.AddrOfPinnedObject(),
dwLCID,
out pSvrGroupHandle,
out pRevUpdateRate,
ref out pobjGroup1)
注意
hDeadband 和 hTimeBias 的內(nèi)存分配由 GCHandle.Alloc() 函數(shù)完成。
GCHandle hTimeBias;
hTimeBias = GCHandle.Alloc(tim ebias,GCHandleType.Pinned);
GCHandle hDeadband;
hDeadband = GCHandle.Alloc(deadband,GCHandleType.Pinned);
這些函數(shù)處理傳送變量時間偏倚和死區(qū)(百分比死區(qū))的非管理型內(nèi)存。
當(dāng)不再需要管理句柄時,必須按如下所示再次將其釋放:
if (hTimeBias.IsAllocated) hTimeBias. Free();
if (hDeadband.IsAllocated) hDeadband.Free();
該程序段的結(jié)果是一個具有指定名稱和所需屬性的組。AddGroup() 還返回 pobjGroup1變量作為返回參數(shù),即組對象的接口。
使用類型調(diào)整調(diào)用 IOPCGroupStateMgt ,可以只從返回的組接口 pobjGroup1 獲取該接口。該調(diào)用的簡化形式對應(yīng)于 COM 方法 Queryinterface()。
稍后需使用 IOPCGroupStateMgt 接口的 S etState() 方法激活和禁用組。
pIOPCGroupStateMgt = (IOPCGroupStateMgt)pob jGroup1;
步驟 5:添加數(shù)據(jù)項
IOPCItemMgt 接口具有用于創(chuàng)建 OPC 數(shù)據(jù)項的 AddItems() 方法:
((IOPCItemMgt)pobjGroup1).AddItems(2,ItemDeffArray,out
pResults,out pErrors);
該程序段的結(jié)果是服務(wù)器添加兩個具有 itemd efs 參數(shù)中所指定屬性的數(shù)據(jù)項。此外,還會對結(jié)果結(jié)構(gòu) OPCITEMRESULT 的變量(服務(wù)器句柄、目標(biāo)系統(tǒng)上數(shù)據(jù)項的數(shù)據(jù)類型等)進(jìn)行初始化。
由于結(jié)果通過基礎(chǔ) COM 接口寫入至非管理型內(nèi)存,因此來自管理型 .NET 代碼的訪問必須利用封送函數(shù):
OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure(pos,
typeof(OPCITEMRESULT));
Ite mSvrHandleArray[0] = result.hServer;
pos = new IntPtr(pos.ToInt32() +
Marshal.SizeOf(typeof(OPCITEMRESULT)));
OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure
(pos,typ eof(OPCITEMRESULT));
ItemSvrHandleArray[1] = result.hServer;
步驟 6:請求 IConnectionPointContainer 接口
IConnectionPointContainer 類型的 pIConnectionPointContainer 變量可源自 m_group_1 變量。
pIConnectionPointContai ner =
(IConnectionPointContainer)pobjGroup1;
定位 IConnectionPoint 接口需要使用該接口。
步驟 7:請求 IOPCAsyncIO2 接口
pIOPCAsyncIO2 類型的 pIOPCAsyncIO2 變量可源自 pobjGroup1 變量。
pIOPCAsyncIO2 = (IOPCAsyncIO2)pobjGroup1;
該接口提供用于異步讀取和寫入值的方法。
步驟 8:創(chuàng)建回調(diào)對象
為了允許 OPC 服務(wù)器返回異步操作的值,必須在客戶端上執(zhí)行 I OPCDataCallback 接口。
public class OPCAsync :System.Windows.Forms.Form ,
IOPCDataCallback
使用 IConnectionPointContainer 接口的 FindConnectionPoint() 方法建立 OPC 服務(wù)器的 IConnectionPoint 和 IOPCDataCallback 接口間的連接。該連接將為異步調(diào)用生成一個回調(diào)對象。
Guid iid = typeof(IO PCDataCallback).GUID;
pIConnectionPointContainer.FindConnectionPoint(ref iid,
out
pIConnectionPoint);
步驟 9:連接 OPC 服務(wù)器與客戶端的回調(diào)對象
OPC 服務(wù)器的回調(diào)對象與客戶端應(yīng)用程序間的連接通過 Advise() 方法來建立。返回變量 dwCookie 是該連接的 ID 。
pIConnectionPoint.Advise(this,out dwCookie);
步驟 10:執(zhí)行所需的寫入或讀取操作
在步驟 7 中生成的 Read() 和 Write() 方法可通過 IOPCAsyncIO2 接口來訪問:
pIOPCAsyncIO2.Read(1,ItemSvrHandleArray,nTransactionID+1,
out nCancelid,out pErrors);
步驟 11:接收 OPC 服務(wù)器的通知
如果激活組中激活數(shù)據(jù)項的數(shù)據(jù)發(fā)生更改,服務(wù)器將調(diào)用回調(diào)對象的 OnDataC hange 方法。讀取操作完成后,服務(wù)器調(diào)用 OnReadComplete() 方法;寫入操作完成后,服務(wù)器調(diào)用 OnWriteComplete() 方法。服務(wù)器將返回值以參數(shù)的形式傳遞至方法。
virtual void OnDataChange(
Int32 dwTransid,
Int32 hGroup,
Int32 hrMasterquality,
Int32 hrMastererror,
Int32 dwCount,
int[] phClientItems,
object[] pvValues,
short[] pwQualities,
FILETIME[] pftTimeStamps,
int[] pErrors,
)
步驟 12:刪除對象并釋放內(nèi)存
退出程序前或單擊“ 停止”(Stop) 后,必須刪除已生成的 OPC 對象并釋放所占用的內(nèi)存。
pIConnectionPoint.Unadvise(dwCookie);
Marshal.ReleaseComObject(pIConnectionPoint);
Mar shal.ReleaseComObject (pIConnectionPointContainer);
Marshal.ReleaseComObject(pIOPCAsyncIO2);
Marshal.ReleaseComObject(pIOPCGroupStateMgt);
Marshal.ReleaseComObject(pobjGroup1);
Marshal.ReleaseComObject(pIOPCServer);
釋放內(nèi)存
使用 COM 時,客戶端有時需要釋放服務(wù)器所請求的內(nèi)存。相關(guān)規(guī)則如下:
? [out]:將從服務(wù)器請求具有該屬性的參數(shù)的內(nèi)存。
? [in,out] :將從客戶端請求此類參數(shù)的內(nèi)存。服務(wù)器可以再次釋放內(nèi)存并對其進(jìn)行重新分配。
? [in] :客戶端將請求內(nèi)存。服務(wù)器不負(fù)責(zé)釋放內(nèi)存。
原文標(biāo)題:以 C# 編寫的 OPC 自定義接口(異步通信)
-
接口
+關(guān)注
關(guān)注
33文章
8691瀏覽量
151909 -
OPC
+關(guān)注
關(guān)注
7文章
350瀏覽量
46326
原文標(biāo)題:以 C# 編寫的 OPC 自定義接口(異步通信)
文章出處:【微信號:gh_a8b121171b08,微信公眾號:機(jī)器人及PLC自動化應(yīng)用】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論