Red de conocimiento informático - Material del sitio web - Cómo implementar el acceso OPC en C++

Cómo implementar el acceso OPC en C++

Hay muchos documentos OPC en Internet. El tema que quiero presentar aquí es el uso de C ++ para acceder al servidor OPC a través de la interfaz de automatización. El propósito de escribir este artículo es que no lo he buscado. documento en Internet si tengo esta necesidad, y creo que debe haber otros amigos en Internet que también tienen esta necesidad, espero que pueda ser de alguna ayuda para estos amigos.

Usar C++ para acceder al servidor OPC En comparación con el uso de una interfaz personalizada, la interfaz de automatización es mucho más simple porque usa la misma interfaz que yo he usado Visual Basic para acceder al servidor OPC. esta experiencia. El primer paso es preparar el entorno de desarrollo. Generalmente, las pruebas se realizan en un entorno de simulación. Esto es más seguro y puede utilizar algunos servidores OPC de simulación. Lo que estoy preparando aquí es el servidor de simulación de Matrikon, una vez instalado el simulador. El entorno de programación es VC++ 6.0 y el uso de 200X y 2010 es similar.

Para una demostración sencilla, cree un nuevo proyecto de consola Win32 agOPC, cree un nuevo archivo fuente agOPC.cpp y agréguelo al proyecto.

// ---------------------------------- agoOPC.cpp ---- - ------------------------------------

//Agregue la siguiente línea al principio de agOPC.cpp

#import "C:Program FilesMatrikonOPCCommonOPCAuto.dll" no_namespace

//Esto se genera mediante la información de la biblioteca de tipos contenida en OPCAuto.dll El archivo de encabezado al que C++ puede acceder generará dos archivos, OPCAuto.tlh y OPCAuto.tli, en la carpeta Debug del proyecto.

//Agregue los archivos de encabezado requeridos

#pragma advertencia (deshabilitar: 4786) // Para evitar la advertencia C4786 reportada por vector

#include < comdef .h> // _bstr_t, _variant_t y _com_error se utilizan y están todos definidos en este archivo

#include< iostream>

#include< vector>

usando el espacio de nombres std;

//Declarar variables globales

typedef struct OLEInit {

OLEInit() { CoInitialize( NULL }

~OLEInit() { CoUninitialize(); }

} OLEInit;

OLEInit oleInit; // Debe definirse al principio porque la biblioteca COM debe inicializarse. antes de usar COM, de lo contrario el programa fallará

// Dado que se llama al constructor de la variable global oleInit antes de llamar a los constructores de todos los objetos,

// se llama al destructor después de los destructores de todos los objetos Luego llame

IOPCAutoServerPtr opcSvr; // Estos tipos de punteros inteligentes se definen en OPCAuto.tlh

IOPCGroupsPtr opcGrps;

IOPCGroupPtr opcGrp;

vector opcItms; // Usa vector para guardar tres elementos de prueba.

//Conéctate al servidor OPC, el parámetro que uso es "Matrikon.OPC.Simulation.1"

void agOPCConn( const char *opcSvrName) {

HRESULT hr;

hr = opcSvr.CreateInstance( __uuidof( OPCServer ) );

if( FAILED( hr ) ) {

cerr<< " OPCServer CreateInstance falló, hr = " << hr<< endl;

exit(1);

}

opcSvr->Connect( opcSvrName );

}

//Desconectarse del servidor OPC

void agOPCDisc() {

opcGrps->RemoveAll(); / / Eliminar todos los grupos , este ejemplo de demostración tiene solo un grupo

opcSvr->Disconnect(); // Desconectarse del servidor OPC

}

//Crear un grupo

}

//Crear un grupo

}

//Crear un grupo

}

//Crear un grupo

}

// p>

void agOPCCreateGroup() {

//OPCGroups es un atributo especial Cuando se ejecuta, IOPCGroupsPtr en OPCAuto.tlh se llamará GetOPCGroups();

opcGrps = opcSvr. ->OPCGroups;

opcGrp = opcGrps->Add( _variant_t( "group1" ) ) // El nombre del grupo se puede elegir como desee

}

//Agregue tres tipos diferentes de elementos de prueba en el grupo. El tipo se puede ver en el nombre del elemento

void agOPCAdItems() {

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 );

}

//Usado Muestra el valor de el elemento leído

void agDumpVariant(VARIANT *v)

{

switch(v->vt)

{

caso VT_I2:

printf(" valor(VT_I2) = %d ", v->iVal );

romper;

caso VT_I4 :

printf(" valor(VT_I4) = %ld ", v->lVal );

>

romper;

caso VT_BSTR:

printf(" valor(VT_BSTR) = %ls ", v->bstrVal );

romper;

predeterminado:

printf(" valor(tipo desconocido:%d) ", v->vt );

romper;

}

}

// Leer los valores de tres elementos de forma sincrónica. La sincronización es una opción simple y efectiva en muchos casos. C++ Puede crear un subproceso de trabajo para realizar operaciones de lectura sincrónicas y, cuando haya un nuevo valor de Elemento, notificar al subproceso principal del evento de "cambio de datos" a través de algún tipo de comunicación entre subprocesos

void agOPCReadItems () {

_variant_t calidad;

_variant_t marca de tiempo;

SAFEARRAY *pServerHandles;

SAFEARRAY *pValues;

SAFEARRAY *pErrors;

SAFEARRAYBOUND rgsabound[ 1 ];

long dim[ 1 ];

long svrHdl;

vector valores <_variant_t>;

errores vectoriales;

int i;

valor_variant_t;

error largo;

// El índice de la matriz VC comienza desde 0, pero en OPCAuto.dll comienza desde 1, por lo que es rgsabound[0].cElements = 4, y al asignar valores a pServerHandles, los índices deben ser 1, 2 y 3 en consecuencia. Asigne el identificador del servidor

rgsabound[ 0 ].cElements = 4;

rgsabound[ 0 ].lLbound = 0;

pServerHandles = SafeArrayCreate( VT_I4, 1, rgsabound ); //Construye una matriz unidimensional de tipo VT_I4

for( i = 0; i < opcItms.size(); i++ ) {

svrHdl = opcItms[i ]->ServerHandle;

dim[ 0 ] = i + 1;

// Asigna un valor a cada elemento de la matriz, el correspondiente los valores de índice son 1, 2, 3

SafeArrayPutElement( pServerHandles, dim, &svrHdl );

}

opcGrp->SyncRead( OPCDevice,

3, // lee el número de elementos

& pServerHandles, // ingresa la matriz de identificadores del lado del servidor

& pValues, //

Matriz de valores del elemento de salida

& pErrors, // Matriz de estado de error del elemento de salida

& calidad, // Estado del valor de lectura

& marca de tiempo // Leer); sello de evento

for( i = 1; i <= opcItms.size(); i++ ) {

dim[ 0 ] = i;

SafeArrayGetElement( pValues, dim, &value ); // Lee el valor del elemento en value

SafeArrayGetElement( pErrors, dim, &err ); // Lee el valor del estado de error en err

values.push_back; ( valor );

errs.push_back( err );

}

for( i = 0; i < valores.size(); i++ ) {

agDumpVariant( &values[ i ] ); // Muestra el valor del elemento leído

cout<< ", err = "<< errs [ i ]<< endl;

}

SafeArrayDestroy( pServerHandles );

SafeArrayDestroy( pValues ​​​​);

SafeArrayDestroy( pErrors );

}

// Escribe los valores de 3 elementos. Para simplificar el ejemplo de demostración, a los parámetros se les pasan 3 valores de elemento correspondientes

void agOPCWriteItems( vector). <_variant_t> valores) {

_variant_t calidad;

_variant_t marca de tiempo;

SAFEARRAY *pServerHandles;

SAFEARRAY *pValues; p>

SAFEARRAY *pErrores;

long dim[ 1 ];

long svrHdl;

int i;

SAFEARRAYBOUND rgsabound[ 1 ];

rgsabound[ 0 ].cElements = valores.size() + 1;

rgsabound[ 0 ].lLbound = 0;

pServerHandles = SafeArrayCreate( VT_I4, 1, rgsabound );

pValues ​​​​= SafeArrayCreate(VT_VARIANT, 1, rgsabound);

for( i = 0; i < valores. tamaño(); i++ ) {

svrHdl = opcItms[i]->ServerHandle;

dim[ 0 ] = i + 1;

SafeArrayPutElement( pServerHandles , tenue, &svrHdl );

SafeArrayPutElement( pValues, dim, &values[i] );

}

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

SafeArrayDestroy( pServerHandles );

SafeArrayDestroy( pValues ​​​​);

SafeArrayDestroy( pErrors );

}

/ /main Programa principal

int main()

{

try

{

agOPCConn( "Matrikon .OPC .Simulación.1" );

agOPCCreateGroup();

agOPCADdItems();

// Primero escribe y lee

vector<_variant_t> valores;

valores.push_back( ( largo )156 );

valores.push_back( ( corto )11 );

valores. push_back( "opc" );

agOPCWriteItems( valores );

agOPCReadItems();

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

// Segunda escritura y leer

vector<_variant_t> valores1;

valores1.push_back( ( largo )123456 );

valores1.push_back( ( corto )666 );

valores1.push_back( "hola" );

agOPCWriteItems( valores1 );

agOPCReadItems();

}

catch ( _com_error &e ) {

// La excepción debe detectarse en la subfunción anterior, pero por simplicidad, la excepción se detecta en la función principal

_bstr_t bstrSource( e.Source ( ) );

_bstr_t bstrDescription( e.Descripción() );

cout<< "Código = "<< e.Error()< < endl;

cout<< "Significado del código = "<< e.ErrorMessage()<< endl;

cout<< "Fuente = "<< ( LPCTSTR ) bstrSource< < endl;

cout<< "Descripción = "<< ( LPCTSTR ) bstrDescripción<< endl;

}

return 0;

}