OPC取数OPCAutomation.dll的使用以及注意事项

声明:如果这篇文章又被变成了仅对VIP开放,请去我的公众号查看。

项目使用的是Winform+C#,从美卓maxDNA OPCServer取数,接口机系统是Win7,工控机是Win Server2003

之前在OPC取数的时候遇到一个难题,上千个点取数时间太长,大概10秒左右,当时对OPC了解不够,在一个技术群里面问关于OPC取数的问题,很多大牛都说需要给钱才肯提供解决方法,当然我也不小气,但是写一个OPC取数接口开口要一万,未免也太狠了吧;靠人不如靠自己,自己认真捉摸OPC,在遇到问题的第二天下午解决,取数时间控制在秒级;同时也分享一些经验,技术共享,同时有关于OPC或者实时数据库相关的外包项目也可以找我,微信xiaoyiyz   靠谱

废话不多说,下面贴出代码,首先是异步读 

异步读是OPCGroup的DataChange事件
当值或组中项目的值的质量触发DataChange事件已经改变。 请注意,事件不会比组的更新速率快。 所以,项目值将由服务器保持并缓冲,直到当前时间+更新速率大于上次更新的时间(事件触发)。这也受组和项的活动状态的影响。 只有活动的项目,和其组是活动的将被发送到事件中的客户端。

class OPCHelper:IDisposable
    {
        private string strHostIP;
        private string strHostName;
        private OPCServer opcServer;
        private OPCGroups opcGroups;
        private OPCGroup opcGroup;
        private List<int> itemHandleClient = new List<int>();
        private List<int> itemHandleServer = new List<int>();
        private List<string> itemNames = new List<string>();
        private OPCItems opcItems;
        private OPCItem opcItem;
        private Dictionary<string, string> itemValues = new Dictionary<string, string>();
        public bool Connected = false;

        public OPCHelper(string strHostIP, string strHostName, int UpdateRate) 
        {
            this.strHostIP = strHostIP;
            this.strHostName = strHostName;
            if (!CreateServer())
                return;
            if (!ConnectServer(strHostIP, strHostName))
                return;
            Connected = true;
            opcGroups = opcServer.OPCGroups;
            opcGroup = opcGroups.Add("ZZHOPCGROUP");
            SetGroupProperty(opcGroup, UpdateRate);
            opcGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(opcGroup_DataChange);
            opcGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(opcGroup_AsyncWriteComplete);
            opcItems = opcGroup.OPCItems;
        }

        
        /// <summary>
        /// 创建服务
        /// </summary>
        /// <returns></returns>
        private bool CreateServer() 
        {
            try
            {
                opcServer = new OPCServer();
            }
            catch 
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="strHostIP"></param>
        /// <param name="strHostName"></param>
        /// <returns></returns>
        private bool ConnectServer(string strHostIP, string strHostName) 
        {
            try
            {
                opcServer.Connect(strHostName, strHostIP);
            }
            catch 
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 设置组的属性 
        /// </summary>
        /// <param name="opcGroup"></param>
        /// <param name="updateRate"></param>
        private void SetGroupProperty(OPCGroup opcGroup, int updateRate) 
        {
            opcGroup.IsActive = true;
            opcGroup.DeadBand = 0;
            opcGroup.UpdateRate = updateRate;
            opcGroup.IsSubscribed = true;
        }

        public bool Contains(string itemNameContains)
        {
            foreach (string key in itemValues.Keys)
            {
                if (key == itemNameContains)
                    return true;
            }
            return false;
        }

        public void AddItems(string[] itemNamesAdded) 
        {
            for (int i = 0; i < itemNamesAdded.Length; i++)
            {
                this.itemNames.Add(itemNamesAdded[i]);
                itemValues.Add(itemNamesAdded[i], "");
            }
            for (int i = 0; i < itemNamesAdded.Length; i++)
            {
                itemHandleClient.Add(itemHandleClient.Count != 0 ? itemHandleClient[itemHandleClient.Count - 1] + 1 : 1);
                opcItem = opcItems.AddItem(itemNamesAdded[i], itemHandleClient[itemHandleClient.Count - 1]);
                itemHandleServer.Add(opcItem.ServerHandle);
            }
        }


        public string[] GetItemValues(string[] getValuesItemNames) 
        {
            string[] getedValues = new string[getValuesItemNames.Length];
            for (int i = 0; i < getValuesItemNames.Length; i++)
            {
                if (Contains(getValuesItemNames[i]))
                    itemValues.TryGetValue(getValuesItemNames[i], out getedValues[i]);
            }
            return getedValues;
        }


        /// <summary>
        /// 异步写 
        /// </summary>
        /// <param name="writeItemNames"></param>
        /// <param name="writeItemValues"></param>
        public void AsyncWrite(string[] writeItemNames, string[] writeItemValues) 
        {
            OPCItem[] bItem = new OPCItem[writeItemNames.Length];
            for (int i = 0; i < writeItemNames.Length; i++)
            {
                for (int j = 0; j < itemNames.Count; j++)
                {
                    if (itemNames[j] == writeItemNames[i]) 
                    {
                        bItem[i] = opcItems.GetOPCItem(itemHandleServer[j]);
                        break;
                    }
                }
            }
            int[] temp = new int[writeItemNames.Length + 1];
            temp[0] = 0;
            for (int i = 1; i < writeItemNames.Length + 1; i++)
            {
                temp[i] = bItem[i - 1].ServerHandle;
            }
            Array serverHandles = (Array)temp;
            object[] valueTemp = new object[writeItemNames.Length + 1];
            valueTemp[0] = "";
            for (int i = 1; i < writeItemNames.Length + 1; i++)
            {
                valueTemp[i] = writeItemValues[i - 1];
            }
            Array values = (Array)valueTemp;
            Array Errors;
            int cancelID;
            opcGroup.AsyncWrite(writeItemNames.Length, ref serverHandles, ref values, out Errors, 2009, out cancelID);
            GC.Collect(); 
        }

        public void SyncWrite(string[] writeItemNames, string[] writeItemValues) 
        {
            OPCItem[] bItem = new OPCItem[writeItemNames.Length];
            for (int i = 0; i < writeItemNames.Length; i++)
            {
                for (int j = 0; j < itemNames.Count; j++)
                {
                    if (itemNames[j] == writeItemNames[i]) 
                    {
                        bItem[i] = opcItems.GetOPCItem(itemHandleServer[j]);
                    }
                }
            }
            int[] temp = new int[writeItemNames.Length + 1];
            temp[0] = 0;
            for (int i = 1; i < writeItemNames.Length; i++)
            {
                temp[i] = bItem[i - 1].ServerHandle;
            }
            Array serverHandles = (Array)temp;
            object[] valueTemp = new object[writeItemNames.Length + 1];
            valueTemp[0] = "";
            for (int i = 1; i < writeItemNames.Length + 1; i++)
            {
                valueTemp[i] = writeItemValues[i - 1];
            }
            Array values = (Array)valueTemp;
            Array Errors;
            opcGroup.SyncWrite(writeItemNames.Length, ref serverHandles, ref values, out Errors);
            
            GC.Collect();
        }





        void opcGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps) 
        {
            for (int i = 1; i <= NumItems; i++)
            {
                itemValues[itemNames[Convert.ToInt32(ClientHandles.GetValue(i)) - 1]] = ItemValues.GetValue(i).ToString();
            }
        }

        void opcGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
        {
            throw new NotImplementedException();
        }


        public void Dispose() 
        {
            if (opcGroup != null) 
            {
                opcGroup.DataChange -= new DIOPCGroupEvent_DataChangeEventHandler(opcGroup_DataChange);
                opcGroup.AsyncWriteComplete -= new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(opcGroup_AsyncWriteComplete);
            }
            if (opcServer != null) 
            {
                opcServer.Disconnect();
                opcServer = null;
            }
            Connected = false;
        }


    }

声明一下,这段代码并非我自己写的,是参考网上的资源

下面贴出同步读方法

 public class OPCReadAuto:IDisposable
    {
        object syncLock = new object();

        OPCServer OpcServer;
        OPCGroup OpcGroup, OpcWriteGroup;
        OPCGroups OpcGroups;
        OPCItems OpcItems;
        OPCItem OpcItem;
        /// <summary>
        /// OPC连接状态
        /// </summary>
        bool IsConnected = false;
        /// <summary>
        /// 客户端句柄
        /// </summary>
        int ItmHandleClient = 0;
        /// <summary>
        /// 服务端句柄
        /// </summary>
        int ItmHandleServer = 0;
        string IpAddr;
        //public string[] OpcValues = null; 
        int index;

        public void Dispose() 
        {
            DisConnected();
        }

        public OPCReadAuto(string opcAddr)
        {
            this.IpAddr = opcAddr;
            bool b = ConnectToServer();
            if (b == false)
                return;
            bool b2 = CreateGroups();
            if (b2 == false)
                return; 
        }
 
        string ServerName = "";
        /// <summary>
        /// 连接OPC Server
        /// </summary>
        /// <returns></returns>
        public bool ConnectToServer()
        {
            try
            { 
                if (OpcServer != null)
                {
                    try
                    {
                        if (OpcServer.ServerState == (int)OPCServerState.OPCRunning)
                        {
                            //WriteLog.WriteLogs(OpcServer.ServerName + "-----" + OpcServer.ServerNode + "-----" + OpcServer.ServerState);
                            GlobalVariables.OPCState = true;
                            return true;
                        }
                    }
                    catch
                    {
                        GlobalVariables.OPCState = false;
                    }
                }


                bool isConn = false;
                OpcServer = new OPCServer();
                //获取IP地址上最后一个 OPC Server 的名字

                object serverList = OpcServer.GetOPCServers(IpAddr);
                if (serverList == null)
                {
                    GlobalVariables.OPCState = false;
                    return false;
                }

                foreach (string turn in (Array)serverList)
                {
                    ServerName = turn;
                }

                OpcServer.Connect(ServerName, IpAddr); //连接OPC Server
                if (OpcServer.ServerState == (int)OPCServerState.OPCRunning)
                {
                    isConn = true;
                    IsConnected = true;
                    GlobalVariables.OPCState = true;
                }
                return isConn;
            }
            catch (Exception ex)
            {
                WriteLog.WriteLogs(ex.ToString());
                GlobalVariables.OPCState = false;
                return false;
            }
        }

        /// <summary>
        /// 创建组
        /// </summary>
        /// <returns></returns>
        private bool CreateGroups()
        {
            if (OpcGroup != null)
                return true;

            bool isCreate = false;
            try
            {
                OpcGroups = OpcServer.OPCGroups;
                OpcGroup = OpcGroups.Add("ZZHGROUP" + DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                //设置组属性
                OpcServer.OPCGroups.DefaultGroupIsActive = true;
                OpcServer.OPCGroups.DefaultGroupDeadband = 0; 
 
                OpcItems = OpcGroup.OPCItems;

                isCreate = true;
            }
            catch (Exception ex)
            {
                WriteLog.WriteLogs(ex.ToString());
                isCreate = false;
            }
            return isCreate;
        }
  
        /// <summary>
        /// OPC取数
        /// </summary>
        /// <param name="opcTags"></param>
        /// <returns></returns>
        public string[] GetOpcValues(List<string> opcTags)
        { 
            bool b = ConnectToServer();
            if (b == false)
                return null;
            CreateGroups(); 
            index = 0;
            int badValue = 0;
            string[] OpcValue = new string[opcTags.Count];

            string strTemp = ""; //临时使用
            foreach (string str in opcTags)
            {  
                string strs = GetOpcValueOne(str);
                //如果测点加不进去,数量超过10个,说明接口机又取不到数了 ZZH 
                if (strs.Equals("BAD"))
                {
                    badValue += 1;
                    if (badValue > 10)
                    { 
                        GlobalVariables.OPCState = false;
                        return null;
                    }
                }
                OpcValue[index] = strs;
                strTemp += str + ",值:" + strs + "\r\n";
                index++;
            } 
            WriteLog.WriteLogs(strTemp);
            return OpcValue;
        }

        Hashtable ReadHS = new Hashtable();
        int iItemIndex = 1;
        /// <summary>
        /// 同步取数/一个一个读取
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private string GetOpcValueOne(string str)
        {
            OPCItem item;

            int IndexItem = 0;
            try
            {  
                try
                {
                    if (ReadHS.ContainsKey(str))
                        item = OpcGroup.OPCItems.GetOPCItem(Convert.ToInt32(ReadHS[str]));
                    //item = OpcGroup.OPCItems.Item(str);
                    else
                    {
                        iItemIndex += 1;
                        item = OpcGroup.OPCItems.AddItem(str, iItemIndex);
                        ReadHS.Add(str, item.ServerHandle);
                    }
                }
                catch
                {
                    iItemIndex += 1;
                    try
                    { item = OpcGroup.OPCItems.AddItem(str, iItemIndex); }
                    catch
                    {
                        return "BAD";
                    }
                } 
  
                Object value;
                Object quality;
                Object timestamp;
                //直接从设备上取数
                item.Read((short)OPCDataSource.OPCDevice, out value, out quality, out timestamp); 

                return value.ToString();
            }
            catch (Exception es)
            {
                WriteLog.WriteLogs(es.ToString());
                return "";
            }
        }


        /// <summary>
        /// 断开OPC连接
        /// </summary>
        public void DisConnected()
        {
            if (!IsConnected)
            {
                return;
            }

            //加锁 
            lock (syncLock)
            {
                if (OpcServer != null)
                {
                    try
                    {
                        //删组 
                        if(OpcGroup != null)
                            OpcServer.OPCGroups.Remove(OpcGroup.Name);
                        if(OpcWriteGroup != null)
                            OpcServer.OPCGroups.Remove(OpcWriteGroup.Name);
                    }
                    catch
                    { GC.Collect(); }

                    try
                    {
                        OpcServer.Disconnect();
                    }
                    catch
                    {
                        try
                        {
                            GC.Collect();
                            OpcServer.Disconnect();
                        }
                        catch
                        { 
                            GC.Collect(); 
                        }
                    }
                }
            }


            IsConnected = false;
        }
        


    }


注意!

用完一定要Disconnect,如果不断开,以后再连接的时候肯定会出错;另外,opcgroup的名字一定不能重复 

Disconnect()
这允许您断开与服务器的连接,然后连接到另一个服务器,或删除物体。 它是良好的编程实践,为客户端应用程序明确删除它创建的对象(包括所有OPCGroup和OPCItem)自动化方法。 调用此函数将删除所有组并释放所有引用底层的OPC自定义服务器。

有什么疑问或者建议可以给我留言,也可以微信,有错误的地方欢迎指正 

关注公众号,回复OPC,即可获取OPC相关资料

  • 16
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 30
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值