基于OPC协议的上位机PLC通讯 (一)

    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    0x10

class 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]);
       
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值