zoukankan      html  css  js  c++  java
  • C#.Net平台与OPC服务器通讯

    最近,我们Ndolls工作室承接了山大某个自动化控制项目,主要做了一套工控信息化系统,其中有一个功能模块是将系统管理的一部分数据参数发送至OPC服务器,由OPC服务器接收数据后执行相应工控操作。第一次接触OPC的项目,有点头大,与大家分享一点经验,希望对大家有所帮助。

    一、开发调试环境

    1、系统环境:win7 64位

    2、开发工具:Microsoft Visual Studio 2010(.Net4.0)

    3、OPC组件:Interop.OPCAutomation.dll

    下载地址:http://www.ndolls.net/doc/OPCAutomation.zip

    4、OPC Server仿真软件:ICONICS Simulator OPC Server 3.12

    下载地址(需要登陆后下载):http://www.ndolls.net/doc/ICONICSSimulatorOPCServer3.12.zip

    二、注意事项

    1、Interop.OPCAutomation.dll需要在系统进行注册,可以直接运行如下命令:

    regsvr32 Interop.OPCAutomation.dll存放路径

    如因为win7系统权限问题无法注册成功,请使用如下命令:

    runas /user:administrator regsvr32 Interop.OPCAutomation.dll存放路径

    2、请将项目设置成X86模式,不然Interop.OPCAutomation.dll会调用失败。

    3、使用仿真软件ICONICS Simulator OPC Server需要开启Distributed Transaction Coordinator服务。

    4、在调用Interop.OPCAutomation.dll过程中,如遇到返回错误码,可参考以下地址进行分析解决:

    https://www.cnblogs.com/heroius/p/7401026.html

    5、Interop.OPCAutomation.dll中文文档可从以下地址下载:

    http://www.ndolls.net/doc/OPC_API.pdf

    三、Demo界面以及代码分析(下载地址:http://www.ndolls.net/doc/OPCManage.zip)

    Demo主要实现了向OPC服务器指定的分组和标签定向发送数据。

    下图为demo的winform界面

    下图为仿真软件界面

    下面贴上代码,请注意首先需要添加引用using OPCAutomation

            #region 变量
    
            //OPCServer的IP
            private String strHostIP;
            //OPCServer的主机名
            private String strHostName;
            //是否和OPCServer建立连接
            private Boolean opc_connected;
            //建立的OPCServer对象
            private OPCServer myServer;
            //OPCServer节点浏览器
            private OPCBrowser myOPCBrowser;
            //分组集合
            private OPCGroups myGroups;
            //分组实例
            private OPCGroup myGroup;
            //分组的TAG节点
            private OPCItems myItems;
            //服务端句柄
            int itmHandleServer = 0;
            //要写入的叶子节点
            private OPCItem[] myItemArray;
    
            #endregion
    
            #region 触发事件
    
            /// <summary>
            /// 每当项数据有变化时执行的事件
            /// </summary>
            /// <param name="TransactionID">处理ID</param>
            /// <param name="NumItems">项个数</param>
            /// <param name="ClientHandles">项客户端句柄</param>
            /// <param name="ItemValues">TAG值</param>
            /// <param name="Qualities">品质</param>
            /// <param name="TimeStamps">时间戳</param>
            void myGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
            {
                for (int i = 1; i <= NumItems; i++)
                {
                    txtValue.Text = ItemValues.GetValue(i).ToString();
                }
    
                //为方便测试,显示到状态栏输出
                lblState.Text = "TransactionID:" + TransactionID.ToString() + "--" + "NumItems:" + NumItems.ToString();
            }
    
            /// <summary>
            /// 写入TAG值时执行的事件
            /// </summary>
            /// <param name="TransactionID">处理ID</param>
            /// <param name="NumItems">项个数</param>
            /// <param name="ClientHandles">项客户端句柄</param>
            /// <param name="Errors">服务器返回的错误信息</param>
            void myGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
            {
                //为方便测试,显示到状态栏输出
                for (int i = 1; i <= NumItems; i++)
                {
                    lblState.Text = "TransactionID:" + TransactionID.ToString() + "--" + "ClientHandle:" + ClientHandles.GetValue(i).ToString() + "--" + "ErrorValue: " + Errors.GetValue(i).ToString();
                }
            }
    
            #endregion
    
            #region 按钮事件
    
    
            /// <summary>
            /// 连接服务器
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnConIP_Click(object sender, EventArgs e)
            {
                //根据输入获取OPC服务器IP地址
                strHostIP = txtIP.Text;
    
                //通过IP来获取OPC服务器主机名
                IPHostEntry ipHostEntry = Dns.GetHostEntry(strHostIP);
                strHostName = ipHostEntry.HostName.ToString();
    
                try
                {
                    //实例化OPC服务
                    myServer = new OPCServer();
    
                    //获取OPCServer列表
                    object serverList = myServer.GetOPCServers(strHostName);
    
                    //将OPCServer展示到ComboBox
                    foreach (string turn in (Array)serverList)
                    {
                        cmbServer.Items.Add(turn);
                    }
                    cmbServer.SelectedIndex = 0;
    
                    //开启OPC连接按钮
                    btnOPC.Enabled = true;
                }
                catch (Exception err)
                {
                    MessageBox.Show("枚举OPC服务出错:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
    
            /// <summary>
            /// 连接OPC服务器
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnOPC_Click(object sender, EventArgs e)
            {
                try
                {
                    //根据选择的OPCServer进行连接
                    myServer.Connect(cmbServer.Text, strHostIP);
    
                    //根据连接成功与否输出状态信息
                    if (myServer.ServerState == (int)OPCServerState.OPCRunning)
                    {
                        lblState.Text = "已连接到:" + myServer.ServerName;
                        //显示服务器信息
                        lblState.Text += "----开始时间:" + myServer.StartTime.ToString();
                        lblState.Text += "----版本:" + myServer.MajorVersion.ToString() + "." + myServer.MinorVersion.ToString() + "." + myServer.BuildNumber.ToString();
                    }
                    else
                    {
                        lblState.Text = "状态:" + myServer.ServerState.ToString();
                    }
    
                    //已连接标记
                    opc_connected = true;
    
                    //开启获取标签按钮
                    btnGetGrps.Enabled = true;
    
                    MessageBox.Show("链接OPC成功");
                }
                catch (Exception err)
                {
                    MessageBox.Show("初始化出错:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
    
            /// <summary>
            /// 获取OPC服务器所有分组和标签
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnGetGrps_Click(object sender, EventArgs e)
            {
                //实例化Tag浏览器
                myOPCBrowser = myServer.CreateBrowser();
    
                //展开分组
                myOPCBrowser.ShowBranches();
    
                //展开标签
                myOPCBrowser.ShowLeafs(true);
    
                //将所有分支和叶子节点显示到ListBox
                lstItems.Items.Clear();
                foreach (object turn in myOPCBrowser)
                {
                    lstItems.Items.Add(turn.ToString());
                }
    
                //开启定位标签按钮
                btnSetItem.Enabled = true;
            }
    
    
            /// <summary>
            /// 根据列表中选中的当前标签,定位到需要发送数据的标签
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnSetItem_Click(object sender, EventArgs e)
            {
                try
                {
                    /**
                     * 需要注意,不同的OPC服务器的标签格式也是不同的
                     * 测试时,使用的是ICONICS Simulator OPC Server,标签格式如:Textual.Memory
                     * 生产环境时,使用的是SimaticNet_V13Sp1,标签格式如:S7:[S7_Connection_1]MReal120
                     * **/
    
                    //根据ListBox选中的标签,处理得到分组名称
                    string groupName = lstItems.Text;
    
                    //实例化组
                    myGroups = myServer.OPCGroups;
                    myGroup = myGroups.Add(groupName);
    
                    //设置缺省的组属性
                    myServer.OPCGroups.DefaultGroupIsActive = true;
                    myServer.OPCGroups.DefaultGroupDeadband = 0;
                    myGroup.UpdateRate = 250;
                    myGroup.IsActive = true;
                    myGroup.IsSubscribed = true;
    
                    //定位需要发送数据的目标项
                    myItems = myGroup.OPCItems;
    
                    //实例化组内标签
                    myItemArray = new OPCItem[1];
    
                    //填充项目组
                    myItemArray[0] = myItems.AddItem(lstItems.Text, 1);
    
                    //获取服务端句柄
                    itmHandleServer = myItemArray[0].ServerHandle;
    
                    //监听组内数据变化
                    myGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(myGroup_DataChange);
                    myGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(myGroup_AsyncWriteComplete);
    
                    //开启发送参数按钮
                    btnWrite.Enabled = true;
                }
                catch (Exception err)
                {
                    MessageBox.Show("创建组出现错误:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
    
            /// <summary>
            /// 写入值
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnWrite_Click(object sender, EventArgs e)
            {
                //获取之前定位的标签
                OPCItem bItem = myItems.GetOPCItem(itmHandleServer);
    
                //根据用户界面输入生成数据对象
                int[] temp = new int[2] { 0, bItem.ServerHandle };
                Array serverHandles = (Array)temp;
                object[] valueTemp = new object[2] { "", txtMyValue.Text };
                Array values = (Array)valueTemp;
                Array Errors;
                int cancelID;
    
                //异步写入到OPC服务器
                myGroup.AsyncWrite(1, ref serverHandles, ref values, out Errors, 2009, out cancelID);
    
                //回收资源
                GC.Collect();
            }
    
    
            /// <summary>
            /// 关闭窗体时,关闭链接
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OPCManage_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (!opc_connected)
                {
                    return;
                }
    
                if (myGroup != null)
                {
                    myGroup.DataChange -= new DIOPCGroupEvent_DataChangeEventHandler(myGroup_DataChange);
                }
    
                if (myServer != null)
                {
                    myServer.Disconnect();
                }
    
                opc_connected = false;
            }
    
            #endregion
    

    四、生产环境

    真实的生产环境中,工控终端采用西门子数控系统(SINUMERIK 808),OPC服务器采用SimaticNet_V13Sp1。由工控人员预先在OPC服务的S7:[S7_Connection_1]M分组下,创建MReal120—MReal140共6个寄存节点,用于接收软件写入的工艺参数。本系统用户根据需要从我们的软件中检索工艺参数,并定向写入到OPC服务器的S7:[S7_Connection_1]M节点下,由数控人员控制数控系统从OPC服务器获取到最新参数进行生产。

  • 相关阅读:
    css实现并列效果
    去除inline-block之间的间距
    鼠标点击<input>输入域后出现有颜色的边框
    消除a标签点击后产生的虚线框
    超过既定行数时,用省略号代替的方法
    常用按钮样式
    常用颜色
    通过Gulp流方式处理流程
    IntelliJ IDEA 10 配置 Tomcat7
    chrome浏览器调试线上文件映射本地文件
  • 原文地址:https://www.cnblogs.com/ndolls/p/9801701.html
Copyright © 2011-2022 走看看