OPC技术是通常是用于PLC和上位机通讯的一个基于COM的一个通讯组件。比如某个项目是用西门子系列的PLC控制的自动化系统通过西门子的中间件通常会安装S7-200 PC Access或者SimaticNet的OPC服务端软件。这两个软件的目的就是在上位机的系统中搭建了一个OPC Server并提供访问可以编程实现遵循OPC技术使上位机与PLC通讯的功能。
    此外,需要强调一点,OPC并不是西门子的技术,它是一个标准,凡是遵循OPC技术的PLC都能共通过其标准与下位机通讯 。

几个关于OPC的概念:
    同步读:在调用OPC的接口函数时实时的将数据(组)通过出口参数传出
    同步写:在调用OPC的接口函数时实时的将数据写入寄存器
    异步读:调用OPC接口不会直接写入PLC寄存器,而是在注册的回调函数中拿到数据的相关信息
    异步写:也是在回调函数中将数据写入

组的概念:
    组中可以包含项,是多个项的一个集合
    组是和OPC提供的IO接口绑定的,OPC的IO接口是用于读写数据

项的概念:
    项其实就是对于了PLC上的对应地址,每种OPC服务器根据厂商不同定义的格式不同

关于封装的类

情况说明(这个类是本人在开发上位机软件与西门子S200系列PLC通信是所编写的 OPC服务器是SimaticNet)

几个疑惑点说明:

OPC服务器提供了几个接口的头文件需要在项目中添加

需要加到工程中的文件:

opc.h

Pre_OPC.h

Pre_OPC.cpp

以下几个文件不用添加到工程中但需要放在工作目录下

opcerror.h

opcda_i.c

opcda.h

opccomn_i.c

opccomn.h

相关文件OPC实现文件(c++)

封装的OPC 操作类

#ifndef OPCRES_H_
#define OPCRES_H_#include "Pre_OPC.h"#define    LOCALE_ID 0x409// Code 0x409 = ENGLISH
#define    ASYNC    0x01
#define    SYNC    0x10class OPCRes{
public:OPCRes(int SyncItemNum,int AsyncItemNum,IOPCServer *pIOPCServer,HWND hWnd);~OPCRes();void UninitRes();void OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName);void OPC_AddItem(BOOL IsActive);void OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString Name);void OPC_ReadItem(DWORD flag);int  OPC_ReadItem(DWORD flag,CString Name);int  OPC_WriteItem(DWORD flag,int Order,int in_Value);void OPC_Subscribe(BOOL IsActiveCheck); DWORD  GetAsyncCount();static void InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID);//传递IOPCServer指针类型的引用将外部声明的变量传进来static void UninitCOM(IOPCServer* &pIOPCServer);private:OPCHANDLE              m_GrpSrvHandle;IOPCServer            *m_pIOPCServer;IOPCSyncIO            *m_pIOPCSyncIO_S;//用于同步访问数据项的同步读写IOPCSyncIO            *m_pIOPCSyncIO_A;//用于异步访问数据项的同步写入IOPCAsyncIO2          *m_pIOPCAsyncIO2;//用于异步访问数据项的异步读取IOPCGroupStateMgt     *m_pIOPCGroupStateMgt;IOPCItemMgt           *m_pIOPCItemMgt[2];    //数据项状态指针1异步0同步OPCITEMRESULT         *m_pAsyncItemResult;//异步数据项返回信息OPCITEMDEF            *m_AsyncItem;        //异步数据项指针CString               *m_AsyncItemName;    //异步数据项的指定名字HRESULT               *m_pAsyncErrors;    //异步数据错误信息DWORD                  m_AsyncItemCount;    //异步数据项的个数OPCITEMRESULT         *m_pSyncItemResult;    //同步数据项返回信息OPCITEMDEF            *m_SyncItem;        //同步数据项指针CString               *m_SyncItemName;    //同步数据项的指定名字HRESULT               *m_pSyncErrors;        //同步数据错误信息DWORD                  m_SyncItemCount;    //同步数据项的个数DWORD    m_flag;        //标记当前对象存在那种类型的数据项DWORD    m_dwAdvise;    //用于OPC Server返回的回调接口标识public:    BOOL     m_ActiveCheck;int            *m_ReadVal_A;    //存放异步数据项的值CString        *m_ReadQu_A;    //存放异步数据项的品质标签CString        *m_ReadTs_A;    //存放异步数据项的时间戳int            *m_ReadVal_S;    //存放同步数据项的值CString        *m_ReadQu_S;    //存放同步数据项的品质标签CString        *m_ReadTs_S;    //存放同步数据项的时间戳
};#endif //OPCRES_H_

实现

#include "stdafx.h"
#include "callback.h"
#include "OPCRes.h"CComModule _Module;//必须定义此全局变量否则无法使用COM组件/*****************************************************
函数名称:构造函数
参数说明:
in 1、指定同步组的数据项个数
in 2、指定异步组的数据项个数
in 3、传进窗口类定义的OPC服务接口指针
******************************************************/
OPCRes::OPCRes(int SyncNum,int AsyncNum,IOPCServer *pIOPCServer):m_SyncItemCount(SyncNum),m_AsyncItemCount(AsyncNum),m_pIOPCServer(pIOPCServer),m_ActiveCheck(FALSE),m_flag(0x00)
{    if(!(AsyncNum+SyncNum)){AfxMessageBox("必须设置监控的数据项",MB_ICONERROR);ExitProcess(0);}if( SyncNum>0 ){m_flag|=SYNC;m_SyncItem=new OPCITEMDEF[SyncNum];//同步的数据项数组m_SyncItemName=new CString[SyncNum];m_ReadVal_S=new int[SyncNum];m_ReadQu_S=new CString[SyncNum];m_ReadTs_S=new CString[SyncNum];}if( AsyncNum>0 ){m_flag|=ASYNC;m_AsyncItem=new OPCITEMDEF[AsyncNum];//异步的数据项数组m_AsyncItemName=new CString[AsyncNum];m_ReadVal_A=new int[AsyncNum];m_ReadQu_A=new CString[AsyncNum];m_ReadTs_A=new CString[AsyncNum];}m_pAsyncItemResult = NULL;m_pSyncItemResult = NULL;
}/*****************************************************
函数名称:析构函数
说明:    释放OPC资源
******************************************************/
OPCRes::~OPCRes()
{if( (m_flag&SYNC) == SYNC){delete[] m_SyncItem;delete[] m_ReadVal_S;delete[] m_ReadQu_S;delete[] m_ReadTs_S;delete[] m_SyncItemName;}if( (m_flag&ASYNC) == ASYNC){delete[] m_AsyncItem;delete[] m_ReadVal_A;delete[] m_ReadQu_A;delete[] m_ReadTs_A;delete[] m_AsyncItemName;}
}
/*****************************************************
函数名称:增加数据组
参数说明:
in 1、指定同步组名
in 2、指定异步组名
返回值:        无返回值
情况说明:    每个对象各有一个同步组一个异步组
******************************************************/
void OPCRes::OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName)
{HRESULT     r1;                //接收AddGroup函数的返回值用于判断long        TimeBias = 0;        //in     与标准时间的校正值float       PercentDeadband = 0.0;    //in     要舍弃的数据DWORD       RevisedUpdateRate;        //out     服务器的数据刷新率CString     szErrorText;        //记录输出信息//创建同步的数据组if( (m_flag & SYNC) == SYNC){//添加组对象并查询IOPCItemMgt接口r1=m_pIOPCServer->AddGroup(SyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\&m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[0]);if(r1 == OPC_S_UNSUPPORTEDRATE){szErrorText.Format ("同步数据组的实际刷新率为%d,与请求值不同",RevisedUpdateRate );AfxMessageBox (szErrorText);}else if (FAILED(r1)){    AfxMessageBox("无法创建同步数据组到服务器", MB_OK+MB_ICONERROR);m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}}//创建异步的数据组if( (m_flag & ASYNC) == ASYNC){r1=m_pIOPCServer->AddGroup(AsyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\&m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[1]);if (r1 == OPC_S_UNSUPPORTEDRATE){szErrorText.Format ("异步数据组的实际刷新率为%d,与请求值不同",RevisedUpdateRate );AfxMessageBox (szErrorText);}else if (FAILED(r1)){    AfxMessageBox("无法创建异步数据组到服务器", MB_OK+MB_ICONERROR);m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}}}
/*****************************************************
函数名称:设置数据项
参数说明:
in 1、指定设置同步/异步类型
in 2、指定要设置的数据项序号(数组序)
in 3、指定数据项的ID(例如:L"S7:[S7 connection_1]DB1,W4326")
in 4、指定数据项的名称(同数据项的序号对应)
返回值:        无
情况说明:    通过参数设置每个数据项的ID和名字
******************************************************/
void OPCRes::OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString in_Name)
{if(SYNC == flag){m_SyncItem[Order].szItemID=in_ID;m_SyncItemName[Order]=in_Name;}else if(ASYNC == flag){m_AsyncItem[Order].szItemID=in_ID;m_AsyncItemName[Order]=in_Name;}else{AfxMessageBox("指定标记错误",MB_ICONERROR);}
}
/*****************************************************
函数名称:添加数据项
参数说明:    无
返回值:        无返回值
情况说明:    将设置好的数据项添加到组中
******************************************************/
void OPCRes::OPC_AddItem(BOOL IsActive)
{HRESULT        r1;            //接收AddGroup函数的返回值用于判断LPWSTR        *ErrorStr;    //out 存放返回的错误信息字符串DWORD        i;            //循环控制if( (m_flag & SYNC)==SYNC){for(i=0;i<m_SyncItemCount;i++){m_SyncItem[i].szAccessPath= L"";        //OPC服务器存取路径m_SyncItem[i].bActive= TRUE;            //活动状态m_SyncItem[i].hClient= i;                //操作句柄(主要用于异步项的回调)m_SyncItem[i].dwBlobSize= 0;            //pBlob大小m_SyncItem[i].pBlob= NULL;                //二进制指针m_SyncItem[i].vtRequestedDataType = 2;    //数据类型(2:int型)}CString    szOut="";//用来输出提示信息ErrorStr=new LPWSTR[m_SyncItemCount];r1 = m_pIOPCItemMgt[0]->AddItems(m_SyncItemCount,m_SyncItem,&m_pSyncItemResult,&m_pSyncErrors);if ( (r1 != S_OK) && (r1 != S_FALSE) ){AfxMessageBox("同步数据项添加失败!",  MB_OK+MB_ICONERROR);m_pIOPCItemMgt[0]->Release();m_pIOPCItemMgt[0] = NULL;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}else{for(i=0;i<m_SyncItemCount;i++){m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息}CString *tempInfo;//存放每一个数据项的提示信息tempInfo=new CString[m_SyncItemCount];for(i=0;i<m_SyncItemCount;i++){tempInfo[i].Format("Sync Item%d :%ls\n",i,ErrorStr[i]);szOut+=tempInfo[i];//把每一项的提示信息组合到输出提示字符串中CoTaskMemFree(ErrorStr[i]);}AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);delete[] tempInfo;}//检查数据项的读写性for(i=0;i<m_SyncItemCount;i++){if (m_pSyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE)){szOut.Format("同步数据项%d不可读写!\n",i);AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION);}}//查询同步IO接口r1 = m_pIOPCItemMgt[0]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_S);if (r1 < 0){AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR);CoTaskMemFree(m_pAsyncItemResult);m_pIOPCItemMgt[0]->Release();m_pIOPCItemMgt[0] = 0;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}}//添加异步数据项if( (m_flag & ASYNC) == ASYNC){for(i=0;i<m_AsyncItemCount;i++){m_AsyncItem[i].szAccessPath= L"";m_AsyncItem[i].bActive= TRUE;m_AsyncItem[i].hClient= i;//操作句柄(项的序号),在异步回调函数中和参数phClientItems[?]对应m_AsyncItem[i].dwBlobSize= 0;m_AsyncItem[i].pBlob= NULL;m_AsyncItem[i].vtRequestedDataType = 2;}CString    szOut="";ErrorStr=new LPWSTR[m_AsyncItemCount];r1 = m_pIOPCItemMgt[1]->AddItems(m_AsyncItemCount,m_AsyncItem,&m_pAsyncItemResult,&m_pAsyncErrors);if ( (r1 != S_OK) && (r1 != S_FALSE) ){AfxMessageBox("异步数据项添加失败!",  MB_OK+MB_ICONERROR);m_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1] = NULL;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}else{for(i=0;i<m_AsyncItemCount;i++){m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息}CString *tempInfo;tempInfo=new CString[m_AsyncItemCount];for(i=0;i<m_AsyncItemCount;i++){tempInfo[i].Format("Async Item%d :%ls\n",i,ErrorStr[i]);szOut+=tempInfo[i];CoTaskMemFree(ErrorStr[i]);}AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);delete[] tempInfo;}//检查数据项的读写性for(i=0;i<m_AsyncItemCount;i++){if (m_pAsyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE)){szOut.Format("异步数据项%d不可读写!\n",i);AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION);}}//为了异步组的对象可以同步写入所以也要查询同步接口r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_A);if (r1 < 0){AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR);CoTaskMemFree(m_pAsyncItemResult);m_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1] = 0;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}//获得GroupStateMgt组状态接口r1=m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCGroupStateMgt, (void**)&m_pIOPCGroupStateMgt);if (r1 != S_OK){AfxMessageBox("组状态接口IOPCGroupStateMgt未找到!", MB_OK+MB_ICONERROR);CoTaskMemFree(m_pAsyncItemResult);m_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1]= 0;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}//查询组对象异步接口r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCAsyncIO2,(void**)&m_pIOPCAsyncIO2);if (r1 < 0){AfxMessageBox("异步接口IOPCAsyncIO未找到!", MB_OK+MB_ICONERROR);CoTaskMemFree(m_pAsyncItemResult);m_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1] = 0;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}// Activate Group according to Checkboxif(IsActive)//激活订阅{OPC_Subscribe(IsActive);}// Establish Callback for all Async operations     建立异步回调CComObject<COPCDataCallback>* pCOPCDataCallback;// Pointer to Callback Object// Create Instance of Callback Object using an ATL template 通过ATL模板创建回调对象的实例CComObject<COPCDataCallback>::CreateInstance(&pCOPCDataCallback);// pass pointer of this call Object to callback objectpCOPCDataCallback->InformAbout(this);// query IUnknown interface of callback object, needed for the ATL Advise  查询IUnknown接口LPUNKNOWN pCbUnk;pCbUnk = pCOPCDataCallback->GetUnknown();// Creates a connection between the OPC Server's connection point and// this client's sink (the callback object).建立一个服务器的连接点与客户程序接收器之间的连接HRESULT hRes = AtlAdvise( m_pIOPCGroupStateMgt, pCbUnk,IID_IOPCDataCallback,&m_dwAdvise );if (hRes != S_OK){AfxMessageBox("Advise failed!");CoTaskMemFree(m_pAsyncItemResult);m_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1] = 0;m_GrpSrvHandle = 0;m_pIOPCServer->Release();m_pIOPCServer = NULL;CoUninitialize();return;}}}
/*****************************************************
函数名称:读取数据项(全体读取版本)
参数说明:    in 1、指定读取的同步/异步组
返回值:        无返回值
情况说明:    此函数将读取指定的组中所有数据项的值
******************************************************/
//读取一组中所有寄存器的值
void OPCRes::OPC_ReadItem(DWORD flag)
{    HRESULT        r1;                    //接收ReadItem函数的返回值用于判断OPCHANDLE    *phServer;            //in     Item的的服务句柄DWORD        dwCancelID;            //out     异步读取返回服务器Cancel IDOPCITEMSTATE    *pItemValue;    //out     OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) HRESULT        *pErrors;            //out     返回的错误指针保存每一项的错误信息编号LPWSTR        *ErrorStr;            //用于保存错误编号对应的错误信息内容CString        szOut;                //存放输出信息DWORD         i;                    //控制循环if(flag==SYNC){if( (m_flag&SYNC) != SYNC){AfxMessageBox("同步组不存在!");return;}for(i=0;i<m_SyncItemCount;i++){if (m_pSyncErrors[i] != S_OK)//判断Item的可用性{szOut.Format("OPC Async Item%d not available!",i);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return;}}phServer = new OPCHANDLE[m_SyncItemCount];// Memory allocation really needed, if more than 1 item to be readfor(i=0;i<m_SyncItemCount;i++){phServer[i] = m_pSyncItemResult[i].hServer;// Select item by server handle, received at AddItem}r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,m_SyncItemCount,phServer,&pItemValue,&pErrors);delete[] phServer;ErrorStr=new LPWSTR[m_SyncItemCount];if(r1 == S_OK){for (i = 0; i<m_SyncItemCount; i++){m_ReadVal_S[i]=pItemValue[i].vDataValue.intVal;//GetQualityText(pItemValue[i].wQuality);m_ReadTs_S[i]=COleDateTime(pItemValue[i].ftTimeStamp).Format();}}if (r1 == S_FALSE){for(i=0;i<m_SyncItemCount;i++){m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]);}CString *tempInfo;//存放输出提示信息tempInfo=new CString[m_SyncItemCount];for(i;i<m_SyncItemCount;i++){tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]);AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR);CoTaskMemFree(ErrorStr[i]);}delete[] tempInfo;}if (FAILED(r1)){szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);}else{    // release [out] parameter in case of not failedCoTaskMemFree(pErrors);CoTaskMemFree(pItemValue);}}if( flag==ASYNC ){if( (m_flag&ASYNC) != ASYNC){AfxMessageBox("异步组不存在!");return;}for(i=0;i<m_AsyncItemCount;i++){if (m_pAsyncErrors[i] != S_OK) // Item not available{szOut.Format("OPC Async Item%d not available!",i);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return;}}phServer = new OPCHANDLE[m_AsyncItemCount];// Memory allocation really needed, if more than 1 item to be readfor(i=0;i<m_AsyncItemCount;i++){phServer[i] = m_pAsyncItemResult[i].hServer;// Select item by server handle, received at AddItem}r1 = m_pIOPCAsyncIO2->Read(m_AsyncItemCount,phServer,10,&dwCancelID,&pErrors);delete[] phServer;ErrorStr=new LPWSTR[m_AsyncItemCount];if (r1 == S_FALSE){for(i=0;i<m_AsyncItemCount;i++){m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]);}CString *tempInfo;//存放输出提示信息tempInfo=new CString[m_AsyncItemCount];for(i;i<m_AsyncItemCount;i++){tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]);AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR);CoTaskMemFree(ErrorStr[i]);}delete[] tempInfo;}if (FAILED(r1)){szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);}else{    // release [out] parameter in case of not failedCoTaskMemFree(pErrors);}}
}
/*****************************************************
函数名称:读取数据项(指定读取版本)
参数说明:
in 1、指定读取的同步/异步组
in 2、指定读取的数据项名称
返回值:        若同步读取成功直接返回数据项的值,异步读取成功:0,失败:-1,指定名称未找到:-2
情况说明:    此函数将读取指定的组中数据项的值
******************************************************/
int OPCRes::OPC_ReadItem(DWORD flag,CString Name)
{        HRESULT            r1;                //接收ReadItem函数的返回值用于判断OPCHANDLE        *phServer;        //in     Item的的服务句柄DWORD            dwCancelID;        //out     异步读取返回服务器Cancel IDOPCITEMSTATE    *pItemValue;    //out     OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) HRESULT            *pErrors;        //out     返回的错误指针保存每一项的错误信息编号LPWSTR            ErrorStr;        //用于保存错误编号对应的错误信息内容CString            szOut;            //存放输出信息DWORD             i;                //控制循环if(flag==SYNC){if( (m_flag&SYNC) != SYNC){AfxMessageBox("同步组不存在!");return -1;}for(i=0;i<m_SyncItemCount;i++){if (m_pSyncErrors[i] != S_OK) // Item not available{szOut.Format("OPC SyncItem[%d] not available!",i);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return -1;}}for(i=0;i<m_SyncItemCount;i++)//遍历查找{if( Name==m_SyncItemName[i] ){phServer=new OPCHANDLE[1];phServer[0] = m_pSyncItemResult[i].hServer;//AfxMessageBox("找到指定寄存器");r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,1,phServer,&pItemValue,&pErrors);delete[] phServer;if(r1 == S_OK){return pItemValue[0].vDataValue.intVal;//数值//GetQualityText(pItemValue[0].wQuality);//品质//COleDateTime(pItemValue[0].ftTimeStamp).Format();//时间}if (r1 == S_FALSE){m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr);CString tempInfo;//存放输出提示信息tempInfo.Format("%s:%ls\n",m_SyncItemName[i],ErrorStr);AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR);CoTaskMemFree(ErrorStr);return -1;}if (FAILED(r1)){szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return -1;}else{    // release [out] parameter in case of not failedCoTaskMemFree(pErrors);CoTaskMemFree(pItemValue);return -1;}break;}}return -2;//未找到}/else if( flag==ASYNC ){if( (m_flag&ASYNC) != ASYNC){AfxMessageBox("异步组不存在!");return -1;}for(i=0;i<m_AsyncItemCount;i++){if (m_pAsyncErrors[i] != S_OK) // Item not available{szOut.Format("OPC AsyncItem[%d] not available!",i);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return -1;}}for(i=0;i<m_AsyncItemCount;i++)//遍历查找{if( Name==m_AsyncItemName[i]){phServer=new OPCHANDLE[1];phServer[0] = m_pAsyncItemResult[i].hServer;//AfxMessageBox("找到指定寄存器");r1 = m_pIOPCAsyncIO2->Read(1,phServer,10,&dwCancelID,&pErrors);delete[] phServer;if (r1 == S_FALSE){m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr);CString tempInfo;//存放输出提示信息tempInfo.Format("%s:%ls\n",m_AsyncItemName[i],ErrorStr);AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR);CoTaskMemFree(ErrorStr);return -1;}if (FAILED(r1)){szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1);AfxMessageBox(szOut, MB_OK+MB_ICONERROR);return -1;}else{    // release [out] parameter in case of not failedCoTaskMemFree(pErrors);return 0;}}}return -2;//未找到}else{AfxMessageBox("寄存器标志有误");return -1;}}
/*****************************************************
函数名称:同步写入数据项(指定读取版本)
参数说明:
in 1、指定写入的同步/异步组
in 2、指定写入的数据项序号(数组序)
in 3、指定写入的数据项值
返回值:        若异步读取成功直接返回数据项的值,同步读取成功:0,失败:-1,指定名称未找到:-2
情况说明:    通过指定组的指定序号向寄存器写入一个值
******************************************************/
int OPCRes::OPC_WriteItem(DWORD Flag,int Order,int in_Value)
{OPCHANDLE        *phServer; HRESULT            *pErrors; VARIANT            values[1]; HRESULT            r1; LPWSTR            ErrorStr; CString            szOut; if(Flag==SYNC){if( (m_flag&SYNC) != SYNC){AfxMessageBox("同步组不存在!");return -1;}for(DWORD i=0;i<m_SyncItemCount;i++){if (m_pSyncErrors[i] != S_OK)        //Item not available {     szOut.Format("Sync Item%d not available!",i);AfxMessageBox(szOut,  MB_OK+MB_ICONERROR); return -2; }}//Select item by server handle received at AddItem phServer = new OPCHANDLE[1]; phServer[0] = m_pSyncItemResult[Order].hServer;//Set Variant with datatype and received valuevalues[0].vt = VT_I2; values[0].intVal = in_Value; r1 = m_pIOPCSyncIO_S->Write(1, phServer, values, &pErrors); }else if(Flag==ASYNC){if( (m_flag&ASYNC) != ASYNC){AfxMessageBox("异步组不存在!");return -1;}for(DWORD i=0;i<m_AsyncItemCount;i++){if (m_pAsyncErrors[i] != S_OK)        //Item not available {     szOut.Format("Async Item%d not available!",i);AfxMessageBox(szOut,  MB_OK+MB_ICONERROR); return -2; }}//    Select item by server handle received at AddItem phServer = new OPCHANDLE[1]; phServer[0] = m_pAsyncItemResult[Order].hServer;//    Set Variant with datatype and received value values[0].vt = VT_I2; values[0].intVal = in_Value; r1 = m_pIOPCSyncIO_A->Write(1, phServer, values, &pErrors); }delete[] phServer; if(r1 == S_OK)//写入成功{;}else if (r1 == S_FALSE){m_pIOPCServer->GetErrorString(pErrors[0], LOCALE_ID, &ErrorStr); szOut.Format("提示:%ls",ErrorStr);AfxMessageBox(szOut); AfxMessageBox("请检查PLC连接");CoTaskMemFree(pErrors);    return -1;}if (FAILED(r1)){ szOut.Format("Method call IOPCSyncIO::Write failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1;} else{CoTaskMemFree(pErrors);return 0;}
}//激活订阅模式
void OPCRes::OPC_Subscribe(BOOL IsActiveCheck)
{DWORD dwRevUpdateRate;DWORD dwRequestedUpdateRate=50;FLOAT fPercentDeadband=50;m_ActiveCheck=IsActiveCheck;HRESULT  r1=m_pIOPCGroupStateMgt->SetState(&dwRequestedUpdateRate,&dwRevUpdateRate, &m_ActiveCheck, NULL,&fPercentDeadband,NULL,NULL);if (FAILED(r1)){AfxMessageBox("Set State failed", MB_OK+MB_ICONERROR);return;}
}//释放资源
void OPCRes::UninitRes()
{HRESULT        r1;OPCHANDLE    *phServer;if( (m_flag & SYNC) == SYNC){HRESULT        *pErrors;LPWSTR        ErrorStr;CString        szOut="";phServer = new OPCHANDLE[m_SyncItemCount];for(DWORD i=0;i<m_SyncItemCount;i++){phServer[i] = m_pSyncItemResult[i].hServer;}r1 = m_pIOPCItemMgt[0]->RemoveItems(m_SyncItemCount, phServer, &pErrors);if ( (r1 != S_OK) && (r1 != S_FALSE) ){AfxMessageBox("Remove SyncItems failed!", MB_OK+MB_ICONERROR);}else{    CString tempInfo;for(DWORD i=0;i<m_SyncItemCount;i++){m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr);tempInfo.Format("%ls\n",ErrorStr);szOut+=tempInfo;}//AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);CoTaskMemFree(ErrorStr);}delete[] phServer;CoTaskMemFree(pErrors);CoTaskMemFree(m_pSyncItemResult);m_pSyncItemResult=NULL;CoTaskMemFree(m_pSyncErrors);m_pSyncErrors = NULL;if(m_SyncItemCount>0)//Release interface for sync calls{m_pIOPCSyncIO_S->Release();m_pIOPCSyncIO_S = NULL;}if(m_AsyncItemCount>0)//Release interface for Async calls{m_pIOPCSyncIO_A->Release();m_pIOPCSyncIO_A = NULL;}//Release ItemManagement interfacem_pIOPCItemMgt[0]->Release();m_pIOPCItemMgt[0] = NULL;}if((m_flag & ASYNC) == ASYNC){LPWSTR        ErrorStr;HRESULT        *pErrors;CString        szOut="";phServer = new OPCHANDLE[m_AsyncItemCount];for(DWORD i=0;i<m_AsyncItemCount;i++){phServer[i] = m_pAsyncItemResult[i].hServer;}r1 = m_pIOPCItemMgt[1]->RemoveItems(m_AsyncItemCount, phServer, &pErrors);if ( (r1 != S_OK) && (r1 != S_FALSE) ){AfxMessageBox("Remove AsyncItems failed!", MB_OK+MB_ICONERROR);}else{CString tempInfo;for(DWORD i=0;i<m_AsyncItemCount;i++){    m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr);tempInfo.Format("%ls\n",ErrorStr);szOut+=tempInfo;}//AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);CoTaskMemFree(ErrorStr);}delete[] phServer;CoTaskMemFree(pErrors);CoTaskMemFree(m_pAsyncItemResult);m_pAsyncItemResult=NULL;CoTaskMemFree(m_pAsyncErrors);m_pAsyncErrors = NULL;//Release interface for sync callsm_pIOPCAsyncIO2->Release();m_pIOPCAsyncIO2 = NULL;//Release ItemManagement interfacem_pIOPCItemMgt[1]->Release();m_pIOPCItemMgt[1] = NULL;}//Remove Groupr1=m_pIOPCServer->RemoveGroup(m_GrpSrvHandle, TRUE);if (r1 != S_OK){AfxMessageBox("RemoveGroup failed!", MB_OK+MB_ICONERROR);}m_GrpSrvHandle = NULL;
}DWORD OPCRes::GetAsyncCount()
{return m_AsyncItemCount;
}//初始化COM库,需要在创建类的窗口中通过静态函数调用
//西门子的OPC Server是L"OPC.SimaticNET"
void OPCRes::InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID)//传递一个IOPCServer*类型的引用即实参本身
{HRESULT     r1;CLSID       clsid;CString     szErrorText;// Initialize the COM libraryr1 = CoInitialize(NULL);if (r1 != S_OK){if (r1 == S_FALSE){   //AfxMessageBox("COM Library already initialized",MB_OK+MB_ICONEXCLAMATION);}else{szErrorText.Format("Initialisation of COM Library failed. ErrorCode= %4x", r1);AfxMessageBox(szErrorText, MB_OK+MB_ICONERROR);return;}}// Given a ProgID, this looks up the associated CLSID in the registryr1 = CLSIDFromProgID(CLSID_ID,&clsid);if (r1 != S_OK){          AfxMessageBox("Retrival of CLSID failed", MB_OK+MB_ICONERROR);CoUninitialize();return;}// Create the OPC server object and querry for the IOPCServer interface of the objectr1 = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServer,(void**)&pIOPCServer);if (r1 != S_OK){          AfxMessageBox("Creation of IOPCServer-Object failed", MB_OK+MB_ICONERROR);pIOPCServer = NULL;CoUninitialize();return;}
}//释放COM库
void OPCRes::UninitCOM(IOPCServer* &pIOPCServer)
{//Release OPC-ServerpIOPCServer->Release();pIOPCServer = NULL;//Uninit COMCoUninitialize();
}

转载于:https://my.oschina.net/mlgb/blog/209478

基于OPC协议的上位机PLC通讯 (一)相关推荐

  1. 基于OPC 技术的上位机与S7-200 系列PLC通讯的实现

    摘要:介绍了OPC 技术及其数据访问方式,在此基础上提出了基于OPC 技术开发监控软件的方案,并简单介绍了系统的组成.利用OPC 技术在VB 中实现了上位机与S7-200PLC 的实时通讯,并提供了详 ...

  2. c#上位机plc通讯读位

    1.  var result = McNet2.Read("D6000", 200);                             saveData["Bar ...

  3. 上下位机通讯协议_上位机与下位机的区别通讯

    上位机是指可以直接发出操控命令的计算机,一般是PC/host computer/master computer/upper computer,屏幕上显示各种信号变化(液压,水位,温度等).下位机是直接 ...

  4. 基恩士上位机链路通讯_基恩士PLC通讯源码

    基恩士PLC KV7000,8000还是比较好用的,那如何和上位机通讯,我把源码写出来了.采用上位链路通讯,基恩士官方给我们留了8501端口,这个端口有意思刚好是我生日.基恩士的资料我觉得做的特别好, ...

  5. 雅马哈与上位机TCP通讯

    雅马哈与上位机TCP通讯 1.0 可以先用调试助手测试,先设定电脑IP以及雅马哈控制器IP,系统--通信设置,设置控制器的IP 1.1 在选项--通用以太网端口,设置GP0(通讯对象),模式伺服,通讯 ...

  6. YAMAHA机器人跟上位机TCP通讯

    工控小知识: YAMAHA机器人跟上位机TCP通讯 机器人当断电后重启后是不会自动执行程序的,这时候的机器人相当于是伺服端,在等待外部客户端给命令,需要上位机发一个@RUN+回车空格的指令,机器人返回 ...

  7. 先睹为快:基于OPC协议的远程IO模块

    钡铼技术近日发布的基于OPC协议的远程IO模块让工业物联更简单! OPC基金会发布的OPC UA协议是新一代工业物联网通信协议,逐步被众多设备制造商采用. 那么基于OPC UA协议的IO模块,直接解决 ...

  8. EPSON机械手跟相机搭配走tcp ip协议,及跟plc通讯将手动操作部分映射到触摸屏

    EPSON机械手跟相机搭配走tcp ip协议,及跟plc通讯将手动操作部分映射到触摸屏 YID:2480618151332838

  9. EPSON机械手跟相机搭配走tcp/ip协议,及跟plc通讯将手动操作部分映射到触摸屏

    EPSON机械手跟相机搭配走tcp/ip协议,及跟plc通讯将手动操作部分映射到触摸屏,供同行交流学习! YID:2480618151332838梦幻工业

最新文章

  1. 01Python基础_09异常
  2. linux游戏欢迎界面,制作Linux登录欢迎界面
  3. Windows下Unity5x创建和打开游戏工程
  4. The Intelligent Investor Feedback
  5. python udp编程_Python UDP编程
  6. 502 Bad Gateway - Registered endpoint failed to handle the request
  7. java在文件的后面添加_java 在file的尾部添加数据的两种方法总结
  8. python查询sql_Python处理SQL语句(提供SQL查询平台使用)
  9. 【C语言】复合函数求值
  10. python3设置编码背景颜色_在pythongtk3中设置条目背景颜色并设置回defau的最佳方法...
  11. kafka之生产者---总结自Kafka权威指南
  12. 实体类[notmapped]特殊 “The specified type member ‘‘ is not supported in LINQ to Entities. Only...
  13. java加载字体文件_Java的加载自定义字体文件(.TTF)
  14. 搭建网站教程 小白教程 游戏搭建制作教程
  15. 中国首台自主超级计算机,6亿元能打造出一台怎样的计算机?
  16. 个人安全团队官方网站引导单页html源码
  17. 前端笔记—从入门到坟墓[CSS][滑动门技术与字体图标][11]
  18. matlab2012教程答案,MATLAB教程2012a第6章习题解答-张志涌
  19. 封装类:即8种基本类型对应8种封装类
  20. 官宣!云上的朋友嗨起来,开发者订阅号开通啦![内藏福利]

热门文章

  1. SuperMap GPA 工具箱中字段计算V2升级版
  2. 阿里云的网站负载均衡解决方案
  3. android 城市万花筒,实景导航神器 随便走评测
  4. 查看linux系统redhat版本号,转:五种方法查看Ubuntu/Redhat等Linux系统版本号等系统信息...
  5. 浏览器下载中文乱码问题目
  6. 为“革命”保护视力,每天应做眼保健操!
  7. 晓东的android bluetooth记录的开始
  8. 几种经典概率校准方法(Platt scaling、 histogram binning、 isotonic regression、 temperature scaling)
  9. Excel错误链接的编辑
  10. stm32添加.c和.h文件问题