OPC与三菱Q系列PLC通信

OPC与三菱PLC通信

一、OPC软件配置

安装好KEPServerEX 6 软件,网上资源很多,自己下载。
打开软件:
OPC与三菱Q系列PLC通信
我电脑上已经配置好了两个连接三菱Q03UDVPLC的通道,两个都可以同时连接,只需要设置不同的端口号就可以了。
再新建一个通道:
选择三菱网络通信
OPC与三菱Q系列PLC通信
选择自己电脑的网口作为网络适配器
OPC与三菱Q系列PLC通信
通道创建完成
OPC与三菱Q系列PLC通信

点击添加设备,选择Q系列PLC:
OPC与三菱Q系列PLC通信

ID设置,前面位网址,后面按照这样写就可以了,详细信息可以点击帮助了解。
OPC与三菱Q系列PLC通信
选择TCP/IP,再设置端口号,PLC配置时需要添加此端口
OPC与三菱Q系列PLC通信
设备创建完成

OPC与三菱Q系列PLC通信
添加标记:
OPC与三菱Q系列PLC通信
标记创建完成
OPC与三菱Q系列PLC通信

二、PLC网络配置

设置IP地址
OPC与三菱Q系列PLC通信
选择TCP,MC协议,设置端口号:
OPC与三菱Q系列PLC通信
将参数下载到PLC,重启PLC。
三、通信测试

打开Quick Client
OPC与三菱Q系列PLC通信
通信正常,同时另外两个通道也通信正常。
OPC与三菱Q系列PLC通信
OPC与三菱Q系列PLC通信

四、通过C#程序监控数据

需要一个OPCAutomation.dll文件,引入这个文件后就可以进行OPC通信编程。
OPC与三菱Q系列PLC通信
代码如下:

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 OPCAutomation;//引入OPC命名空间
using System.Net;
using thinger.com.Models;

namespace OPC通信
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        #region   创建对象

        private OPCServer KepServer;//OPC服务器对象
        private OPCBrowser KepBrower;//OPC服务器中的变量集
        private OPCGroups KepGroups;//OPC服务器中的组集合
        private OPCGroup KepGroup;//OPC服务器中组集合内的组
        private Array ServerHandles;//句柄
        private Array ServerErrors;//错误信息
        private int TransactionID = 0;
        private int CancelID = 0;

        #endregion

        #region  刷新节点列表
        /// <summary>
        /// 刷新节点列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            this.cbServerNode.Items.Clear();
            IPHostEntry iphost = Dns.GetHostEntry(Environment.MachineName);//获取计算机名
            if(iphost.AddressList.Length>0)
            {
                for(int i=0;i<iphost.AddressList.Length;i++)
                {
                    string host = Dns.GetHostEntry(iphost.AddressList[i]).HostName;//得到计算机名
                    if(!this.cbServerNode.Items.Contains(host))
                    {
                        this.cbServerNode.Items.Add(host);
                    }
                }
            }
            if(this.cbServerNode.Items.Count>0)
            {
                this.cbServerNode.SelectedIndex = 0;
            }
        }
        #endregion

        #region  获取服务列表
        private void cbServerNode_SelectedIndexChanged(object sender, EventArgs e)
        {
            KepServer = new OPCServer();
            object serverList = KepServer.GetOPCServers(this.cbServerNode.Text);//根据计算机名获取OPC服务器
            foreach (var item in (Array)serverList)
            {
                if (!this.cbServerName.Items.Contains(item))
                {
                    this.cbServerName.Items.Add(item);
                }
            }
            if (this.cbServerName.Items.Count > 0)
            {
                this.cbServerName.SelectedIndex = 0;
            }
        }
        #endregion

        #region   连接与断开
        /// <summary>
        /// 连接与断开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if(this.btnConnect.Text=="Connect")
            {
                if(KepServer==null)
                {
                    KepServer = new OPCServer();
                }
                try
                {
                    KepServer.Connect(this.cbServerName.Text, this.cbServerNode.Text);//连接OPC
                }
                catch(Exception ex)
                {
                    MessageBox.Show("连接失败" + ex.Message);
                    return;
                }

                //获取所有的变量
                KepBrower = this.KepServer.CreateBrowser();
                KepBrower.ShowBranches();
                KepBrower.ShowLeafs(true);
                this.lvName.Items.Clear();

                //往lvName中添加变量名
                foreach(var item in KepBrower)
                {
                    this.lvName.Items.Add(item.ToString());
                }

                //通信组集合初始化
                KepGroups = KepServer.OPCGroups;
                KepGroups.DefaultGroupDeadband = 0;
                KepGroups.DefaultGroupIsActive = true;

                //通信组初始化
                KepGroup = KepGroups.Add("测试组");
                KepGroup.IsActive = true;//激活
                KepGroup.IsSubscribed = true;//订阅
                KepGroup.UpdateRate = 250;
                KepGroup.IsSubscribed = true;

                KepGroup.AsyncReadComplete += KepGroup_AsyncReadComplete;

                this.btnConnect.Text = "Disconnect";

                //开始读取
                this.timer1.Enabled = true;
            }
            else
            {
                KepServer.Disconnect();
                this.btnConnect.Text = "Connect";
                //停止读取
                this.timer1.Enabled = false;
            }
        }

        #endregion

        #region  双击创建变量
        //创建变量集合
        private List<OPCVariable> OPCVarList = new List<OPCVariable>();

        /// <summary>
        /// lvName双击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvName_DoubleClick(object sender, EventArgs e)
        {
            if(this.lvName.SelectedItems!=null)
            {
                //添加一个变量到集合里
                OPCVarList.Add(new OPCVariable()
                {
                    OPCItemID = this.lvName.SelectedItems[0].Text   
                });

                //OPCVarList>>ServerHander

                //OPCVarList>>NumItems ItemIDS ClientHandles

                //Array和集合的区别 前者索引从1开始 后者索引从0开始

                List<string> ItemIDS = new List<string>();
                List<int> ClientHandles = new List<int>();

                //初始化
                ItemIDS.Add("0");
                ClientHandles.Add(0);

                //变量个数
                int Count = OPCVarList.Count;

                //循环添加
                for(int i=0;i<Count;i++)
                {
                    ItemIDS.Add(OPCVarList[i].OPCItemID);
                    ClientHandles.Add(i + 1);
                }

                Array ItemID = ItemIDS.ToArray();
                Array ClientHandle = ClientHandles.ToArray();

                KepGroup.OPCItems.AddItems(Count, ref ItemID, ref ClientHandle, out ServerHandles, out ServerErrors);
            }
        }
        #endregion

        #region 定时读取
        /// <summary>
        /// 定时读取事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            //读取变量  服务器 OPCServer->组集合 OPCGroups->组 OPCGroup

            //OPC读取三种方式:同步 异步 订阅
            //KepGroup.SyncRead(); 同步
            //KepGroup.AsyncRead(); 异步  
            //KepGroup.DataChange(); 订阅

            if (KepServer!=null&& this.OPCVarList.Count > 0)
            {
                //同步读取
                //KepGroup.SyncRead();
                //异步读取
                KepGroup.AsyncRead(this.OPCVarList.Count, ref ServerHandles, out ServerErrors, TransactionID, out CancelID);
            }

        }

        /// <summary>
        /// 异步读取完成事件
        /// </summary>
        /// <param name="TransactionID"></param>
        /// <param name="NumItems"></param>
        /// <param name="ClientHandles"></param>
        /// <param name="ItemValues"></param>
        /// <param name="Qualities"></param>
        /// <param name="TimeStamps"></param>
        /// <param name="Errors"></param>
        private 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);
                int clientHandle = Convert.ToInt32(ClientHandles.GetValue(i));
                for(int j=0;j<this.OPCVarList.Count;j++)
                {
                    if(j+1==clientHandle)
                    {
                        this.OPCVarList[j].OPCValue = value.ToString();
                        this.OPCVarList[j].Quality = Qualities.GetValue(i).ToString();
                        this.OPCVarList[j].UpdateTime = TimeStamps.GetValue(i).ToString();
                    }
                }
            }
            this.dgvData.DataSource = null;
            this.dgvData.DataSource = this.OPCVarList;
            
        }
        #endregion
    }
}

由于DLL文件是32位的,所以只能编译为32位的程序,点击运行:
OPC与三菱Q系列PLC通信
三个通道访问同一个数据都正常。

五、采用UDP通信

设置一个UDP通道,设置好端口号。
OPC与三菱Q系列PLC通信
在PLC参数设置中添加一个UDP通道:
OPC与三菱Q系列PLC通信

运行Quick Client,通信正常
OPC与三菱Q系列PLC通信
C#监控程序正常工作。
OPC与三菱Q系列PLC通信

上一篇:工业4.0的通信规范OPC UA协议的特点


下一篇:OPC Utgard的数据访问方式