關於OPC Client 編寫


昨天又有人問我 OPC Client 編寫,實際是他們不了解OPC 客戶端的工作原理,要想寫客戶端程序,必須知道OPC對象, OPC邏輯對象模型包括3類對象:OPC server對象、OPC group對象、OPC item對象,每類對象都包括一系列接口。

    OPC Server對象

    主要功能為:1、創建和管理OPC Group對象;

                2、管理服務器內部的狀態信息;

    OPC Group對象

    主要功能為:1、管理OPC Group對象的內部狀態信息;

                2、創建和管理Items對象。

                3、OPC服務器內部的實時數據存取服務(同步與異步方式)。

    OPC組中有以下幾個主要屬性:Name :組的名字 ;Active:組的激活狀態標志 ;Update Rate OPC:服務器向客戶程序提交數據變化的刷新速率;Percent Dead band:數據死區,即能引起數據變化的最小數值百分比。

    OPC ITEM 是非COM對象,在OPC標准中用來描述實時數據,是客戶端不可見的對象。代表了與服務器中的數據的連接,它並不是數據源,而僅僅是與數據源的連接。每個項都有以下主要屬性: Active項的激活狀態、Value項的數值、類型為VARIANT、Quality項的品質,代表數值的可信度,類型為SHORT、TimeStamp時間戳,代表數據的存取時間。

    你不管用什么開發語言只要了解上面幾個對象,就會寫程序了

    下面舉個VC的例子

    HRESULT  r1;
 CLSID  clsid;
 LONG  TimeBias = 0;
 FLOAT  PercentDeadband = 0.0;
 DWORD  RevisedUpdateRate;
 LPWSTR  ErrorStr;
 char  str[100];
 CString  szErrorText;

 m_pItemResult = NULL;

 客戶端程序必須對DCOM進行初始化設置,以保證OPC服務器端回調函數不會被堵塞。 
 r1 = CoInitialize(NULL);
 if (r1 != S_OK)
 { if (r1 == S_FALSE)
  { MessageBox("COM Library already initialized",
              "Error CoInitialize()", MB_OK+MB_ICONEXCLAMATION);
  }
  else
  { szErrorText.Format("Initialisation of COM Library failed. Error Code= %4x", r1);
   MessageBox(szErrorText,"Error CoInitialize()", MB_OK+MB_ICONERROR);
   SendMessage(WM_CLOSE);
   return;
  }
 }
 
 通過OPC服務器的ProgID查詢注冊表中相關CLSID。每個COM服務器都有一個字符串型的ProgID,通過ProgID可以得到全球惟一的CLSID,使用CLSIDFromProgID( )函數實現ProgID到CLSID的轉換。 r1 = CLSIDFromProgID(L"OPC.SimaticNET", &clsid);
 if (r1 != S_OK)
 { MessageBox("Retrival of CLSID failed",
       "Error CLSIDFromProgID()", MB_OK+MB_ICONERROR);
  CoUninitialize();
  SendMessage(WM_CLOSE);
  return;
 }

 連接OPC服務器,查詢對象的IID_IOPCServer接口。在連接OPC服務器前,OPC客戶端需要事先指定計算機名和OPC數據訪問服務器名,建立連接后,創建OPC組並添加OPC數據項。

 r1 = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServer, (void**)&m_pIOPCServer);
 if (r1 != S_OK)
 { MessageBox("Creation of IOPCServer-Object failed",
             "Error CoCreateInstance()", MB_OK+MB_ICONERROR);
  m_pIOPCServer = NULL;
  CoUninitialize();
  SendMessage(WM_CLOSE);
  return;
 }

 創建OPC組,查詢IOPCItemMgt接口。IOPCServer接口的AddGroup()方法可以創建一個有指定名稱和屬性的OPC組。

r1=m_pIOPCServer->AddGroup(L"grp1",   // [in] group name
      TRUE,     // [in] active
      500,     // [in] request this Update Rate from Server
      1,      // [in] Client handle
      &TimeBias,    // [in] no time interval to system UTC time
      &PercentDeadband,   // [in] no deadband, so all data changes are reported 
      LOCALE_ID,    // [in] Server uses English language for text values
      &m_GrpSrvHandle,  // [out] Server handle to identify this group in later calls
      &RevisedUpdateRate,  // [out] the answer form the Server to the requested update rate
         IID_IOPCItemMgt,  // [in] requested interface type of the group object
      (LPUNKNOWN*)&m_pIOPCItemMgt); // [out] pointer to the requested interface
 
 if (r1 == OPC_S_UNSUPPORTEDRATE)
 { 
  szErrorText.Format ("Revised Update Rate %d is different from Requested Update Rate 500",RevisedUpdateRate );
  AfxMessageBox(szErrorText);
 }
 else
  if (FAILED(r1)){
   MessageBox("Can't add Group to Server!", "Error AddGroup()", MB_OK+MB_ICONERROR);
   m_pIOPCServer->Release();
   m_pIOPCServer = NULL;
   CoUninitialize();
   SendMessage(WM_CLOSE);
   return;
  }
添加OPC數據項。使用IOPCItemMgt接口的AddItem()方法可以添加具有特殊屬性的指定數量的數據項。

// define an item table with one item as in-paramter for AddItem
 m_Items[0].szAccessPath    = L"";   

 m_Items[0].szItemID     = szItemID;  // 影響數據類型
 m_Items[0].bActive     = TRUE;   
 m_Items[0].hClient     = 1;
 m_Items[0].dwBlobSize    = 0;
 m_Items[0].pBlob     = NULL;
 m_Items[0].vtRequestedDataType = 0;    
             // defined by the item itself

 r1 = m_pIOPCItemMgt->AddItems(1,    // [in] add one item
       m_Items,    // [in] see above
       &m_pItemResult,   // [out] array with additional information about the item
       &m_pErrors);   // [out] tells which of the items was successfully added.
             // For any item which failed it provides a reason

程序退出時

OPC連接斷開,釋放接口指針。當程序退出或停止服務器時,依次刪除Item(RemoveItems)、Group(RemoveGroups),釋放資源。

void CAsynOPCDlg::OnStop( ) 停止服務器。
h1=m_IOPCItemMgt->RemoveItems(1,phServer,&pErrors);刪除Items。
h1=m_IOPCServer->RemoveGroup(m_GrpSrvHandle,TRUE);刪除Group。
m_IOPCServer->Release( );釋放服務器。
m_IOPCServer=NULL;
CoUninitialize( );關閉COM庫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM