當前位置:首頁 » 密碼管理 » vc如何對opc數據的訪問

vc如何對opc數據的訪問

發布時間: 2023-06-29 02:04:51

1. 如何在C++中實現OPC訪問

OPC的文檔網上很多,我在這里要介紹的主題是使用C++通過自動化介面來訪問OPC Server,寫這篇文章的目的是我在網上沒有搜索到這方面的文檔,如果我有這方面的需要,我想在網上一定也有其他朋友有這個需要,希望能對這些朋友有一些幫助。
使用C++來訪問OPC Server, 相對於使用自定義介面來說,自動化介面要簡單很多,因為這和Visual Basic使用的是同一個介面,使用過Visual Basic來訪問OPC Server的朋友一定能有這個體會。首先是准備好開發環境,一般測試是在模擬環境中進行,這樣比較保險,可以使用一些免費的模擬OPC Server。我這里准備的是Matrikon的模擬伺服器,模擬器安裝以後。編程環境是VC++ 6.0,使用200X和2010也都大同小異。

為了演示簡單,新建一個Win32控制台工程agOPC,新建agOPC.cpp源文件並加到工程里。

// --------------------------------- agOPC.cpp -----------------------------------------------
//在agOPC.cpp開頭添加如下一行
#import "C:Program FilesMatrikonOPCCommonOPCAuto.dll" no_namespace
//這是通過OPCAuto.dll里所包含的類型庫信息產生C++能訪問的頭文件,此時在工程的Debug文件夾下產生OPCAuto.tlh和OPCAuto.tli兩個文件。

//添加需要的頭文件
#pragma warning( disable : 4786 ) // 為了避免vector報出的C4786警告
#include< comdef.h> // 使用到了_bstr_t,_variant_t,_com_error都在這個文件里定義
#include< iostream>
#include< vector>
using namespace std;

//聲明全局變數
typedef struct OLEInit {
OLEInit() { CoInitialize( NULL ); }
~OLEInit() { CoUninitialize(); }
} OLEInit;

OLEInit oleInit; // 必須在最前面定義,因為在使用COM之前必須初始化COM庫,否則程序會崩潰
// 由於是全局變數oleInit的構造函數在所有對象的構造函數調用之前調用,
// 析構函數在所有對象的析構函數調用之後調用
IOPCAutoServerPtr opcSvr; // 這些智能指針類型在OPCAuto.tlh中定義
IOPCGroupsPtr opcGrps;
IOPCGroupPtr opcGrp;
vector<OPCItemPtr> opcItms; // 使用vector來保存三個測試Item。

//連接到OPC Server, 我所使用的參數是"Matrikon.OPC.Simulation.1"
void agOPCConn( const char *opcSvrName ) {
HRESULT hr;
hr = opcSvr.CreateInstance( __uuidof( OPCServer ) );
if( FAILED( hr ) ) {
cerr<< "OPCServer CreateInstance failed, hr = " << hr<< endl;
exit(1);
}
opcSvr->Connect( opcSvrName );
}

//斷開和OPC Server的連接
void agOPCDisc() {
opcGrps->RemoveAll(); // 刪除所有的組, 這個演示實例只有一個組
opcSvr->Disconnect(); // 斷開和OPC Server的連接
}

//創建一個組
void agOPCCreateGroup() {
// OPCGroups是特殊的屬性,執行的時候會調用OPCAuto.tlh中的IOPCGroupsPtr GetOPCGroups();
opcGrps = opcSvr->OPCGroups;
opcGrp = opcGrps->Add( _variant_t( "group1" ) ); // 組名隨意取
}

//在組里添加三個不同類型的測試Item, 類型可以從Item的名字可以看出
void agOPCAddItems() {
OPCItemPtr opcItm;

opcItm = opcGrp->OPCItems->AddItem( _bstr_t( "Bucket Brigade.Int4" ), 1 );
opcItms.push_back( opcItm );

opcItm = opcGrp->OPCItems->AddItem( _bstr_t( "Bucket Brigade.Int2" ) , 1);
opcItms.push_back( opcItm );

opcItm = opcGrp->OPCItems->AddItem( _bstr_t( "Bucket Brigade.String" ) , 1);
opcItms.push_back( opcItm );
}

//用來顯示讀取的Item的值
void agDumpVariant(VARIANT *v)
{
switch(v->vt)
{
case VT_I2:
printf(" value(VT_I2) = %d ", v->iVal );
break;
case VT_I4:
printf(" value(VT_I4) = %ld ", v->lVal );
break;
case VT_BSTR:
printf(" value(VT_BSTR) = %ls ", v->bstrVal );
break;
default:
printf(" value(unknown type:%d) ", v->vt );
break;
}
}

//同步讀取三個Item的值,同步在很多情況下都是簡單有效的選擇方案,其實讀取的非同步方式在C++中可以建立一個工作線程來執行同步讀的操作,等有新的Item值的時候再通過某種線程間通信的方式告訴主線程「數據改變」的事件
void agOPCReadItems() {

_variant_t quality;
_variant_t timestamp;
SAFEARRAY *pServerHandles;
SAFEARRAY *pValues;
SAFEARRAY *pErrors;
SAFEARRAYBOUND rgsabound[ 1 ];
long dim[ 1 ];
long svrHdl;
vector<_variant_t> values;
vector<long> errs;
int i;
_variant_t value;
long err;

// VC數組索引從0開始,而在OPCAuto.dll需要中從1開始,所以是rgsabound[ 0 ].cElements = 4,而給pServerHandles賦值的時候應該給索引是1,2,3相應的賦值Server Handle
rgsabound[ 0 ].cElements = 4;
rgsabound[ 0 ].lLbound = 0;
pServerHandles = SafeArrayCreate( VT_I4, 1, rgsabound ); //構建一個1維數組,類型是VT_I4

for( i = 0; i < opcItms.size(); i++ ) {
svrHdl = opcItms[i]->ServerHandle;
dim[ 0 ] = i + 1;
// 給數組的每個元素賦值,對應的索引值是1, 2, 3
SafeArrayPutElement( pServerHandles, dim, &svrHdl );
}

opcGrp->SyncRead( OPCDevice,
3, // 讀取的Item數目
& pServerHandles, // 輸入的伺服器端句柄數組
& pValues, // 輸出的Item值數組
& pErrors, // 輸出的Item錯誤狀態數組
& quality, // 讀取的值的狀態
& timestamp ); // 讀取的事件戳

for( i = 1; i <= opcItms.size(); i++ ) {
dim[ 0 ] = i;
SafeArrayGetElement( pValues, dim, &value ); // 讀取Item值在value中
SafeArrayGetElement( pErrors, dim, &err ); // 讀取錯誤狀態值在err中
values.push_back( value );
errs.push_back( err );
}

for( i = 0; i < values.size(); i++ ) {
agDumpVariant( &values[ i ] ); // 顯示讀取的Item值
cout<< ", err = "<< errs[ i ]<< endl;
}

SafeArrayDestroy( pServerHandles );
SafeArrayDestroy( pValues );
SafeArrayDestroy( pErrors );
}

// 寫入3個Item的值,為了演示實例簡單,參數傳遞3個對應的Item值
void agOPCWriteItems( vector<_variant_t> values) {
_variant_t quality;
_variant_t timestamp;
SAFEARRAY *pServerHandles;
SAFEARRAY *pValues;
SAFEARRAY *pErrors;
long dim[ 1 ];
long svrHdl;
int i;

SAFEARRAYBOUND rgsabound[ 1 ];
rgsabound[ 0 ].cElements = values.size() + 1;
rgsabound[ 0 ].lLbound = 0;

pServerHandles = SafeArrayCreate( VT_I4, 1, rgsabound );
pValues = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

for( i = 0; i < values.size(); i++ ) {
svrHdl = opcItms[i]->ServerHandle;
dim[ 0 ] = i + 1;
SafeArrayPutElement( pServerHandles, dim, &svrHdl );
SafeArrayPutElement( pValues, dim, &values[i] );
}

opcGrp->SyncWrite( 3,& pServerHandles, &pValues,& pErrors );

SafeArrayDestroy( pServerHandles );
SafeArrayDestroy( pValues );
SafeArrayDestroy( pErrors );
}

//main主程序
int main()
{
try
{
agOPCConn( "Matrikon.OPC.Simulation.1" );
agOPCCreateGroup();
agOPCAddItems();

// 第一次寫和讀
vector<_variant_t> values;
values.push_back( ( long )156 );
values.push_back( ( short )11 );
values.push_back( "opc" );
agOPCWriteItems( values );

agOPCReadItems();

cout << "---------------------------------------"<< endl;

// 第二次寫和讀
vector<_variant_t> values1;
values1.push_back( ( long )123456 );
values1.push_back( ( short )666 );
values1.push_back( "hello" );
agOPCWriteItems( values1 );

agOPCReadItems();
}
catch ( _com_error &e ) {
// 應該在上面的子函數裡面捕捉異常,但為了演示簡單,在主函數裡面捕捉異常
_bstr_t bstrSource( e.Source( ) );
_bstr_t bstrDescription( e.Description( ) );
cout<< "Code = "<< e.Error()<< endl;
cout<< "Code meaning = "<< e.ErrorMessage()<< endl;
cout<< "Source = "<< ( LPCTSTR ) bstrSource<< endl;
cout<< "Description = "<< ( LPCTSTR ) bstrDescription<< endl;
}

return 0;
}

2. vc開發的opc客戶端怎麼鏈接opc伺服器

很簡單,wincc裡面添加一個opc通道,就象添加一個s7協議(與300-400plc通訊)一樣

熱點內容
硬碟存儲伺服器怎麼連接 發布:2025-02-04 10:00:55 瀏覽:27
javaip埠 發布:2025-02-04 09:27:09 瀏覽:856
國產存儲科技進步二等獎 發布:2025-02-04 09:13:00 瀏覽:693
編程課v 發布:2025-02-04 08:45:00 瀏覽:108
模擬器能有手機腳本么 發布:2025-02-04 08:39:50 瀏覽:760
android顯示html圖片 發布:2025-02-04 08:35:31 瀏覽:793
如何查學信網賬號及密碼 發布:2025-02-04 08:33:55 瀏覽:504
linux32位jdk 發布:2025-02-04 08:33:55 瀏覽:249
康佳伺服器連接失敗是怎麼回事 發布:2025-02-04 08:18:51 瀏覽:918
編譯編譯有什麼 發布:2025-02-04 08:05:52 瀏覽:737