OPC协议

1, 解析主机
2. 向 cmbServerNode 中添加所有节点(电脑)
3. 选择一个OPC服务器, 连接它, 并将它名下的OPC 节点写入 ListItems
4. 使用委托解析OPC中的信息(异步读取), 提取出Value和Time, 存入OPClist中, OPClist 事先建好了一个类, 里面有Tag, value, Time, 并为dvg准备数据源
5. 设置同步修改 异步修改操作器

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using OPCAutomation;

namespace OPCClientDemon
{
    public partial class FrmOPCClient : Form
    {
        public FrmOPCClient()
        {
            InitializeComponent();
            this.Load += FrmOPCClient_Load;
        }
        private void FrmOPCClient_Load(object sender, EventArgs e)
        {
            this.btnRefreshList_Click(null, null);
            this.timer1.Interval = 1000; //时间从1秒开始
            this.timer1.Enabled = true;
            this.dtgData.AutoGenerateColumns = false; //自动生成列
            Control.CheckForIllegalCrossThreadCalls = false;
        }




        //定义OPC服务器;
        OPCServer kepServer;
        //定义OPC服务器Groups;
        OPCGroups kepGroups;
        OPCGroup kepGroup;
        OPCItems kepItems;
        OPCBrowser kepBrowser;
        //定义OPC变量集合
        List<OPCItem> opcList = new List<OPCItem>();
        List<int> serverHandles = new List<int>();
        List<int> clientHandles = new List<int>();
        List<string> tempIDList = new List<string>();

        //定义返回的OPC标签错误码
        Array iErrors;
        //定义要添加的OPC标签的标识符
        Array strTempIDs;
        Array strClientHandles;
        Array strServerHandles;
        Array readServerHandles;
        Array writeServerHandles;
        Array writeArrayHandles;
        Array readError;
        Array writeError;
        int readTransID;
        int writeTransID;
        int readCancelID;
        int writeCancelID;


        private void btnRefreshList_Click(object sender, EventArgs e)
        {
            this.cmbServerNode.Items.Clear();
            //GetHostEntry是DNS类里面的一个方法,可以将主机名(域名)和IP地址相互解析的一个类
            IPHostEntry IPhost = Dns.GetHostEntry(Environment.MachineName); //获取主机名称 DESKTOP-IH9OA15 并解析地址
            if (IPhost.AddressList.Length > 0)
            {
                int count = IPhost.AddressList.Length;
                for (int i = 0; i < count; i++)
                {
                    //解析主机名称
                    string HostName = Dns.GetHostEntry(IPhost.AddressList[i].ToString()).HostName;
                    //绑定下拉菜单
                    if (!this.cmbServerName.Items.Contains(HostName))//读取所有主机名称,记录其节点
                    {
                        this.cmbServerNode.Items.Add(HostName);
                    }
                }
            }
            else
            {
                return;
            }

            //Thread th = new Thread(LL);
            //th.IsBackground = true;
            //th.Start(IPhost);
        }

        //void LL(object o)
        //{
        //    IPHostEntry IPhost = o as IPHostEntry;
        //    if (IPhost.AddressList.Length > 0)
        //    {
        //        int count = IPhost.AddressList.Length;
        //        for (int i = 0; i < count; i++)
        //        {
        //            //解析主机名称
        //            string HostName = Dns.GetHostEntry(IPhost.AddressList[i].ToString()).HostName;
        //            //绑定下拉菜单
        //            if (!this.cmbServerName.Items.Contains(HostName))//读取所有主机名称,记录其节点
        //            {
        //                this.cmbServerNode.Items.Add(HostName);
        //            }
        //        }
        //    }
        //    else
        //    {
        //        return;
        //    }
        //}


        private void cmbServerNode_SelectedIndexChanged(object sender, EventArgs e)
        {
            //清空菜单
            this.cmbServerName.Items.Clear();
            //通过OPCAutomation 建立OPCserver
            kepServer = new OPCServer();
            object serverList = kepServer.GetOPCServers(this.cmbServerNode.Text.Trim());//通过主机IP获得所有OPC服务器
            Thread th1 = new Thread(ThreadCmbName);
            th1.IsBackground = true;
            th1.Start(serverList);
        }

        void ThreadCmbName(object o)
        {
            Array arr1 = o as Array;
            foreach (string item in arr1)
            {
                if (!this.cmbServerName.Items.Contains(item))
                {
                    this.cmbServerName.Items.Add(item);
                }
            }
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            //连接选择的OPC服务器
            if (this.btnConnect.Text=="Connect")
            {
                try
                {
                    kepServer.Connect(this.cmbServerName.Text.Trim(), this.cmbServerNode.Text.Trim());
                }
                catch (Exception err1)
                {
                    MessageBox.Show(err1.Message, "连接失败");
                    //throw err1;
                }
                this.btnConnect.Text = "Disconnect";
                //对kepGroups对象赋值
                kepGroups = kepServer.OPCGroups;
                //对kepGroups属性设置
                kepGroups.DefaultGroupDeadband = 0;//Group的默认死区,变化量超过死区后将会触发DataChange事件
                kepGroups.DefaultGroupIsActive = true; //以后添加的Group是否默认激活
                kepGroup = kepGroups.Add("Group1");
                kepGroup.IsActive = true;
                kepGroup.IsSubscribed = true; //订阅模式
                kepGroup.UpdateRate = 250; //刷新率

                kepGroup.AsyncReadComplete += KepGroup_AsyncReadComplete; //建立委托 异步读取完成

                kepBrowser = kepServer.CreateBrowser();
                kepBrowser.ShowBranches(); //OPCBrowser遍历构建树枝
                kepBrowser.ShowLeafs(true); //叶节点.

                foreach (object item in kepBrowser)
                {
                    this.ListItems.Items.Add(item.ToString());
                }
            }
            else
            {
                if (kepServer != null)
                {
                    kepServer.Disconnect();
                    kepServer = null;
                    this.btnConnect.Text = "Connect";
                }
            }
        }
        //使用委托解析
        void KepGroup_AsyncReadComplete(
            int TransactionID, int NumItems, ref Array ClientHandles, 
            ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array Errors)
        {
            for (int i = 1; i <=NumItems; i++)
            {
                object Value = ItemValues.GetValue(i);
                if (Value != null)
                {
                    this.opcList[i - 1].Value = Value.ToString();//注意减1
                    //this.opcList[i-1].Time = ((DateTime)TimeStamps.GetValue(i)).AddHours(8).ToLongTimeString();
                    this.opcList[i - 1].Time = Convert.ToDateTime(((DateTime)TimeStamps.GetValue(i)).AddHours(8));
                }
            }
            this.dtgData.DataSource = null;
            
            this.dtgData.DataSource = this.opcList; //为dvg指定数据源

            //throw new NotImplementedException(); 解析
        }

        private void ListItems_DoubleClick(object sender, EventArgs e)
        {

            if (this.ListItems.SelectedItem != null)
            {
                opcList.Add(new OPCItem()
                {
                    Tag = this.ListItems.SelectedItem.ToString()
                });
            }

            tempIDList.Clear();
            clientHandles.Clear();
            tempIDList.Add("0");
            clientHandles.Add(0);
            int count = this.opcList.Count;
            for (int i = 0; i < count; i++)
            {
                tempIDList.Add(this.opcList[i].Tag);
                clientHandles.Add(i + 1);
            }
            strTempIDs = (Array)tempIDList.ToArray();
            strClientHandles = (Array)clientHandles.ToArray();
            kepItems = kepGroup.OPCItems;
            //KepItems添加标签
            kepItems.AddItems(this.opcList.Count, ref strTempIDs, ref strClientHandles, out strServerHandles, out iErrors);
            serverHandles.Clear();
            serverHandles.Add(0);
            for (int i = 0; i < count; i++)
            {
                serverHandles.Add(Convert.ToInt32(strServerHandles.GetValue(i + 1)));
            }
            readServerHandles = (Array)serverHandles.ToArray();


        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.lbl_CurrentTime.Text = "当前时间:" + DateTime.Now.ToLongTimeString();

            if (kepServer!= null)
            {
                if (kepServer.ServerState == 1)
                {
                    this.lbl_Status.Text = "Connected";
                }
                else
                {
                    this.lbl_Status.Text = "Disonnected";
                }
            }


            if (this.opcList.Count>0)
            {
                if (kepServer!=null)
                {
                    kepGroup.AsyncRead(this.opcList.Count, ref readServerHandles, out readError, readTransID, out readCancelID);
                }
                
            }
        }

        private void dtgData_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (this.dtgData.SelectedRows !=null)
            {
                int index = this.dtgData.CurrentRow.Index;
                OPCItem objItem = this.opcList[index];
                Frm_Modify objFrm = new Frm_Modify(objItem.Value);//跨屏操作
                DialogResult res = objFrm.ShowDialog();
                int[] serverHandle = new int[] { 0,Convert.ToInt32(strServerHandles.GetValue(index+1))};
                object[] values = new object[2];
                string[] modifyResult;
                writeServerHandles = (Array)serverHandle;
                if (res==DialogResult.OK)
                {
                    modifyResult = objFrm.Tag.ToString().Split('|');//使用哪个屏幕的Tag
                    values[1] = modifyResult[0];
                    writeArrayHandles = (Array)values;
                    if (modifyResult[1]=="1")
                    {
                        kepGroup.AsyncWrite(
                            1, writeServerHandles,writeArrayHandles,
                            out writeError, writeTransID, out writeCancelID);//异步
                    }
                    else //同步
                    {
                        kepGroup.SyncWrite(1, ref writeServerHandles, ref writeArrayHandles, out writeError);
                    }

                }
            }
        }

        private void dtgData_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            new DataGridViewStyle().DgvRowPostPaint(this.dtgData, e);
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OPCClientDemon
{
    public partial class Frm_Modify : Form
    {
        public Frm_Modify(string Value)
        {
            InitializeComponent();
            this.txtInitial.Text = Value;
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            string Res = string.Empty;
            if (this.chk_Async.Checked)
            {
                Res = this.txtModify.Text.Trim() + "|" + "1";
            }
            else
            {
                Res = this.txtModify.Text.Trim() + "|" + "0";
            }
            this.Tag = Res;
            this.DialogResult = DialogResult.OK;
            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

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

namespace OPCClientDemon
{
    public class OPCItem
    {
        //OPCItem变量名
        public string Tag { get; set; }

        //OPCItem值
        public string Value { get; set; }

        public DateTime Time { get; set; }
    }
}

上一篇:05_Tutorial 5: Relationships & Hyperlinked APIs


下一篇:OPC学习