【源代码】西门子Simatic.NET与Visual C#异步通讯的代码

 

/*********************************************************************
 * 模块名称:OPC服务器类
 * 版    本:Version 0.97a
 * 作    者:龙少爷
 * 时    间:2010-11-16 11:43
 * 备    注: 
 *      OPC服务器的常用操作:连接,断开,读,写,设置状态
 * 附    注:
 *            
 * *******************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;

using OpcRcw.Da;
using OpcRcw.Comn;

namespace Utility.PLC
{
    /// <summary>
    /// OPC服务器类 By 龙少爷 2010
    /// </summary>
    public class OPCServer
    {
        #region OPCServer Common Fields
        private OpcRcw.Da.IOPCServer ServerObj;//OPCServer  

        private OpcRcw.Da.IOPCAsyncIO2 IOPCAsyncIO2Obj = null;//异步读写对象  
        private OpcRcw.Da.IOPCGroupStateMgt IOPCGroupStateMgtObj = null;//组管理对象  

        private IConnectionPointContainer pIConnectionPointContainer = null;
        private IConnectionPoint pIConnectionPoint = null;

        public const int LOCALE_ID = 0x407;

        private Object MyobjGroup1 = null;
        private int[] ItemServerHandle;
        private int pSvrGroupHandle = 0;
        private Int32 dwCookie = 0;

        #endregion

        #region OPCServer User-Defined Variables
        #endregion

        #region OPCServer Constructors
        public OPCServer()
        {

        }
        #endregion

        #region Methods

        /// <summary>
        /// 建立PC到PLC的连接,返回OPC服务器对象
        /// </summary>
        /// <param name="programID">将要连接的进程ID</param>
        /// <param name="server">服务器IP地址</param>
        /// <returns>OPC服务器对象</returns>
        public bool CreateServer(string programID, string server)
        {
            Type svrComponenttyp;
            try
            {
                svrComponenttyp = Type.GetTypeFromProgID(programID, server);//OPCServer  
                ServerObj = (IOPCServer)Activator.CreateInstance(svrComponenttyp);//注册  
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 添加一个组对象,并返回该组对象的引用
        /// </summary>
        /// <param name="form">回调对象</param>
        /// <returns>是否执行成功</returns>
        public bool AddGroup(object form)
        {
            Int32 dwRequestedUpdateRate = 1000;
            Int32 hClientGroup = 1;
            Int32 pRevUpdateRate;

            float deadband = 0;

            int TimeBias = 0;
            GCHandle hTimeBias, hDeadband;
            hTimeBias = GCHandle.Alloc(TimeBias, GCHandleType.Pinned);
            hDeadband = GCHandle.Alloc(deadband, GCHandleType.Pinned);
            Guid iidRequiredInterface = typeof(IOPCItemMgt).GUID;

            try
            {
                ServerObj.AddGroup("MyOPCGroup1",//组对象  
                    0,
                    dwRequestedUpdateRate,
                    hClientGroup,
                    hTimeBias.AddrOfPinnedObject(),
                    hDeadband.AddrOfPinnedObject(),
                    LOCALE_ID,
                    out pSvrGroupHandle,
                    out pRevUpdateRate,
                    ref iidRequiredInterface,
                    out MyobjGroup1);

                IOPCAsyncIO2Obj = (IOPCAsyncIO2)MyobjGroup1;
                //Query interface for Async calls on group object  

                IOPCGroupStateMgtObj = (IOPCGroupStateMgt)MyobjGroup1;

                pIConnectionPointContainer = (IConnectionPointContainer)MyobjGroup1;
                //定义特定组的异步调用连接  

                Guid iid = typeof(IOPCDataCallback).GUID;
                // Establish Callback for all async operations  
                pIConnectionPointContainer.FindConnectionPoint(ref iid, out pIConnectionPoint);

                // Creates a connection between the OPC servers's connection point and this client's sink (the callback object)  
                pIConnectionPoint.Advise(form, out dwCookie);

                return true;
            }
            catch (Exception ex)// catch for group adding  
            {
                return false;
            }
            finally
            {
                if (hDeadband.IsAllocated)
                    hDeadband.Free();
                if (hTimeBias.IsAllocated)
                    hTimeBias.Free();
            }
        }
        /// <summary>
        /// 添加一个读写的Items数组对象
        /// Ex:
        ///     OpcRcw.Da.OPCITEMDEF[] ItemArray = new OPCITEMDEF[3];//  
        ///     ItemArray[0].szAccessPath = "";
        ///     ItemArray[0].szItemID = "S7:[S7 connection_1]DB13,DWORD0";
        ///     //地址,不同数据类型表示方法不同  
        ///     ItemArray[0].bActive = 1;//是否激活  
        ///     ItemArray[0].hClient = 1;//表示ID  
        ///     ItemArray[0].dwBlobSize = 0;
        ///     ItemArray[0].pBlob = IntPtr.Zero;
        ///     ItemArray[0].vtRequestedDataType = 2;
        /// </summary>
        /// <param name="items">Items读写对象数组</param>
        /// <returns>Items是否执行成功</returns>
        public bool AddItems(OPCITEMDEF[] items)
        {
            IntPtr pResults = IntPtr.Zero;
            IntPtr pErrors = IntPtr.Zero;

            try
            {
                ((IOPCItemMgt)MyobjGroup1).AddItems(items.Length, items, out  pResults, out pErrors);

                int[] errors = new int[items.Length];
                Marshal.Copy(pErrors, errors, 0, items.Length);

                ItemServerHandle = new int[items.Length];

                IntPtr pos = pResults;

                OPCITEMRESULT result;

                if (errors[0] == 0)
                {
                    result = (OPCITEMRESULT)Marshal.PtrToStructure(pos, typeof(OPCITEMRESULT));
                    ItemServerHandle[0] = result.hServer;
                }
                for (int i = 1; i < errors.Length; i++)
                {
                    if (errors[i] == 0)
                    {
                        pos = new IntPtr(pos.ToInt32() + Marshal.SizeOf(typeof(OPCITEMRESULT)));
                        result = (OPCITEMRESULT)Marshal.PtrToStructure(pos, typeof(OPCITEMRESULT));
                        ItemServerHandle[i] = result.hServer;
                    }
                }
                return true;
            }
            catch (Exception ex) // catch for add item  
            {
                return false;
            }
            finally
            {
                // Free the memory  
                if (pResults != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pResults);
                    pResults = IntPtr.Zero;
                }
                if (pErrors != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pErrors);
                    pErrors = IntPtr.Zero;
                }
            }
        }
        /// <summary>
        /// 发送异步读命令,结果的读取要通过实现IOPCDataCallback接口的OnReadComplete函数实现
        /// </summary>
        /// <param name="itemServerHandles">Item读写对象句柄数组</param>
        /// <returns>是否执行成功</returns>
        public bool Read()
        {
            int nCancelid;
            IntPtr pErrors = IntPtr.Zero;
            if (IOPCAsyncIO2Obj != null)
            {
                try
                {
                    IOPCAsyncIO2Obj.Read(ItemServerHandle.Length, ItemServerHandle, ItemServerHandle.Length, out nCancelid, out pErrors);
                    int[] errors = new int[ItemServerHandle.Length];
                    Marshal.Copy(pErrors, errors, 0, ItemServerHandle.Length);
                    return false;
                }
                catch (Exception ex)
                {
                    return false;
                }
            }
            else
                return false;
        }
        /// <summary>
        /// 发送异步写命令,结果的状态,要通过实现IOPCDataCallback接口的OnWriteComplete函数实现
        /// </summary>
        /// <param name="itemIndex">要写的Item项</param>
        /// <param name="values">要写入到PLC中的值数组</param>
        /// <returns>是否执行成功</returns>
        public bool Write(int itemIndex, object[] values)
        {
            int nCancelid;
            IntPtr pErrors = IntPtr.Zero;

            int[] phServer = new int[1];
            phServer[0] = itemIndex;

            if (IOPCAsyncIO2Obj != null)
            {
                try
                {
                    IOPCAsyncIO2Obj.Write(1, phServer, values, itemIndex, out nCancelid, out pErrors);

                    int[] errors = new int[1];
                    Marshal.Copy(pErrors, errors, 0, 1);

                    if (errors[0] != 0)//Error in reading item
                    {
                        Marshal.FreeCoTaskMem(pErrors);
                        pErrors = IntPtr.Zero;
                        return false;
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    return false;
                }
            }
            else
                return false;
        }
        /// <summary>
        /// 发送异步写命令,结果的状态,要通过实现IOPCDataCallback接口的OnWriteComplete函数实现
        /// </summary>
        /// <param name="values">要写入到PLC中的值数组</param>
        /// <returns>是否执行成功</returns>
        public bool Write(object[] values)
        {
            int nCancelid;
            IntPtr pErrors = IntPtr.Zero;

            if (IOPCAsyncIO2Obj != null)
            {
                try
                {
                    IOPCAsyncIO2Obj.Write(ItemServerHandle.Length, ItemServerHandle, values, ItemServerHandle.Length, out nCancelid, out pErrors);

                    int[] errors = new int[ItemServerHandle.Length];
                    Marshal.Copy(pErrors, errors, 0, ItemServerHandle.Length);

                    bool bError = false;
                    foreach (int err in errors)//Error in reading item
                    {
                        if (err != 0)
                        {
                            bError = true;
                            break;
                        }
                    }
                    if (bError)
                    {
                        Marshal.FreeCoTaskMem(pErrors);
                        pErrors = IntPtr.Zero;
                        return false;
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    return false;
                }
            }
            else
                return false;
        }
        /// <summary>
        /// 设置PLC状态,使之处罚OnDataChange事件函数
        /// </summary>
        /// <param name="group"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool SetState(bool value)
        {
            IntPtr pRequestedUpdateRate = IntPtr.Zero;
            int nRevUpdateRate = 0;
            IntPtr hClientGroup = IntPtr.Zero;
            IntPtr pTimeBias = IntPtr.Zero;
            IntPtr pDeadband = IntPtr.Zero;
            IntPtr pLCID = IntPtr.Zero;
            int nActive = 0;

            // activates or deactivates group according to checkbox status  
            GCHandle hActive = GCHandle.Alloc(nActive, GCHandleType.Pinned);
            if (value != true)
                hActive.Target = 0;
            else
                hActive.Target = 1;
            try
            {
                IOPCGroupStateMgtObj.SetState(pRequestedUpdateRate, out nRevUpdateRate, hActive.AddrOfPinnedObject(), pTimeBias, pDeadband, pLCID, hClientGroup);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
            finally
            {
                hActive.Free();
            }
        }
        /// <summary>
        /// 断开PC到PLC的连接
        /// </summary>
        /// <returns>是否成功执行</returns>
        public bool DisConnect()
        {
            try
            {
                if (dwCookie != 0)
                {
                    pIConnectionPoint.Unadvise(dwCookie);
                    dwCookie = 0;
                }
                // Free unmanaged code  
                Marshal.ReleaseComObject(pIConnectionPoint);
                pIConnectionPoint = null;

                Marshal.ReleaseComObject(pIConnectionPointContainer);
                pIConnectionPointContainer = null;

                if (IOPCAsyncIO2Obj != null)
                {
                    Marshal.ReleaseComObject(IOPCAsyncIO2Obj);
                    IOPCAsyncIO2Obj = null;
                }

                ServerObj.RemoveGroup(pSvrGroupHandle, 0);
                if (IOPCGroupStateMgtObj != null)
                {
                    Marshal.ReleaseComObject(IOPCGroupStateMgtObj);
                    IOPCGroupStateMgtObj = null;
                }
                if (MyobjGroup1 != null)
                {
                    Marshal.ReleaseComObject(MyobjGroup1);
                    MyobjGroup1 = null;
                }
                if (ServerObj != null)
                {
                    Marshal.ReleaseComObject(ServerObj);
                    ServerObj = null;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }
        #endregion

        #region  Public Properity
        public OpcRcw.Da.IOPCServer Server
        {
            get
            {
                return this.ServerObj;
            }
        }
        #endregion
    }

}

 

如何使用的范例:

由于上面的代码只是简单的封装了OPC的基本操作,然而却在项目中使用并不简洁方便,为此又写了一个接口。

 

/*********************************************************************
 * 模块名称:定义在操作PLC的常用操作和属性
 * 作    者:龙少爷
 * 时    间:2010-11-24 11:44
 * 备    注:
 * 
 * 历史修改记录
 * 作    者:
 * 修改时间:
 * 备    注:
 * 
 * *******************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Picking
{
    /// <summary>
    /// 定义在操作PLC的常用操作和属性
    /// </summary>
    public interface IPLCOperator
    {
        /// <summary>
        /// 数据库是否已经连接上
        /// </summary>
        bool IsConnected { get; set; }
        /// <summary>
        /// 建立PC到PLC的连接,由指定的adviser参数对象来处理事件的结果
        /// </summary>
        /// <param name="adviser">接受处理结果的对象</param>
        /// <returns>true/false</returns>
        bool ConnectToPLC(string programID, string server, object adviser);

        bool ReadFromPLCDB();

        bool WriteIntoPLCDB(object[] values);

        bool SetPLCState(bool state);

        bool DisConnectFromPLC();


    }
}

 

 

与PLC交互的代码,之所以这样写一个单独的类,是为了在同时读写多个ITEM项时,能把每个操作独立出来处理:

 

/*********************************************************************
 * 模块名称:
 * 作    者:龙少爷
 * 时    间:2010-11-24 13:44
 * 备    注:
 * 
 * 历史修改记录
 * 作    者:
 * 修改时间:
 * 备    注:
 * 
 * *******************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Utility.PLC;

using OpcRcw.Da;

namespace Picking
{
    /// <summary>
    /// 
    /// </summary>
    public class DLStopLine : IOPCDataCallback, IPLCOperator
    {
        #region  私有变量
        private OPCServer opcServer = null;
        #endregion

        #region Public Constructor
        public DLStopLine()
        {
            opcServer = new OPCServer();
        }
        #endregion

        #region IPLCOperator 成员

        public bool IsConnected
        {
            get;
            set;
        }

        public bool ConnectToPLC(string programID, string server, object adviser)
        {
            if (!opcServer.CreateServer(programID, server))
            {
                IsConnected = false;
                return false;
            }
            if (!opcServer.AddGroup(adviser))
            {
                IsConnected = false;
                return false;
            }
            OpcRcw.Da.OPCITEMDEF[] items = new OPCITEMDEF[1];//定义读写的item,共个变量   
            items[0].szAccessPath = "";
            items[0].szItemID = "S7:[S7 connection_1]DB20,B1";    //地址,不同数据类型表示方法不同   
            items[0].bActive = 1;//是否激活   
            items[0].hClient = 1;//表示ID   
            items[0].dwBlobSize = 0;
            items[0].pBlob = IntPtr.Zero;
            items[0].vtRequestedDataType = 17;

            if (!opcServer.AddItems(items))
            {
                IsConnected = false;
                return false;
            }
            IsConnected = true;
            return true;
        }

        public bool ConnectToPLC(string programID, string server)
        {
            return ConnectToPLC(programID, server, this);
        }

        public bool ConnectToPLC(object adviser)
        {
            return ConnectToPLC("OPC.SimaticNet", "localhost", adviser);
        }

        public bool ConnectToPLC()
        {
            return ConnectToPLC("OPC.SimaticNet", "localhost", this);
        }

        public bool ReadFromPLCDB()
        {
            return opcServer.Read();
        }

        public bool WriteIntoPLCDB(object[] values)
        {
            return opcServer.Write(values);
        }

        public bool SetPLCState(bool state)
        {
            return opcServer.SetState(state);
        }

        public bool DisConnectFromPLC()
        {
            return opcServer.DisConnect();
        }

        #endregion

        #region IOPCDataCallback 成员

        public void OnCancelComplete(int dwTransid, int hGroup)
        {

        }

        public void OnDataChange(int dwTransid, int hGroup, int hrMasterquality, int hrMastererror, int dwCount, int[] phClientItems, object[] pvValues, short[] pwQualities, FILETIME[] pftTimeStamps, int[] pErrors)
        {

        }

        public void OnReadComplete(int dwTransid, int hGroup, int hrMasterquality, int hrMastererror, int dwCount, int[] phClientItems, object[] pvValues, short[] pwQualities, FILETIME[] pftTimeStamps, int[] pErrors)
        {

        }

        public void OnWriteComplete(int dwTransid, int hGroup, int hrMastererr, int dwCount, int[] pClienthandles, int[] pErrors)
        {

        }

        #endregion

        #region  Destructor
        ~DLStopLine()
        {
            if (IsConnected)
                opcServer.DisConnect();
        }
        #endregion

    }
}

 

 在项目中,编写相应的调用代码即可。

 

            DLStopLine stopLine = new DLStopLine();
            stopLine.ConnectToPLC();

            values = new object[1];
            values[0] = 1;
            stopLine.WriteIntoPLCDB(values);

 

posted @ 2010-11-28 20:26  龙少爷1123  阅读(3666)  评论(4编辑  收藏  举报