使用visual studio2019在VB.net中用OPC读写数据

自动化项目上用的是PLC控制器,西门子的1200系列,本身支持OPC通讯。如果用上位机与PLC进行OPC通讯,有两种方式,一种是把PLC作为服务器,自己写OPC客户端,直接读取。
另一种是通过中间软件,比如kepware这种,kepware连接plc,上位机读取kepware。
两种方式都可以,不同的是kepware是收费软件,如果不差钱的,建议使用kepware,省事,好用。
如果要节省成本,又愿意自己折腾的,那么可以用上位机自己来写。
本文主要是说一下第二种方式,纯粹是自己的个人经验,如有不足之处,烦请告知

工具:win10系统
visual studio2019(VB.net)
西门子1200系列plc(支持opc功能,固件版本应该是在V4.4及以上才可以)

本文主要用VB.net来做上位机编码,对VB.net没有兴趣的可以不用继续往下看了。

准备工作

准备工作就是把用到的软件都下载好,包括上位机软件visual studio2019(其他版本没用过),西门子编程软件TIA PORTAL V16(可以在西门子官网下载试用版)。

visual studio2019链接:
https://visualstudio.microsoft.com/zh-hans/vs/
博图V16链接:https://support.industry.siemens.com/cs/document/109772803/simatic-step-7-incl-safety-and-wincc-v16-trial-download?dti=0&lc=en-KW
西门子软件比较大,下载和安装都要花一点时间,自己看着来。
(PS:博图最新的版本已经到V17了,但V16还没有用明白呢)

本文主要说上位机的程序,PLC端的简单说一下:
博图V16新建项目,添加一个1200的PLC,如1214C DC/DC/DC,固件V4.4及以上。
然后在的PLC的设备视图里设置一下opc参数,例如激活opc ua 服务器,设置端口、超时时间、采样率等,安全设置里添加证书和许可证,然后在左侧的项目导航器里新添一个opc服务器接口,将想要读取的PLC变量添加进入,可以设置一下变量格式,以便上位机读取。
使用visual studio2019在VB.net中用OPC读写数据_第1张图片
PLC端设置好后,编译下载即可。

上位机这边,电脑上打开visual studio2019,新建一个VB.net窗体项目,这里有个注意的地方,是需要添加一下opc的引用。
使用visual studio2019在VB.net中用OPC读写数据_第2张图片
这个引用需要先在注册表注册,是一个dll文件:OPCDAAuto.dll。
注册的时候如果有问题,参考下面的解决办法:
感谢这位的提供:@tayloramanda
使用visual studio2019在VB.net中用OPC读写数据_第3张图片
引用添加好后,在程序里就可以使用opcautomation这个库了。
使用visual studio2019在VB.net中用OPC读写数据_第4张图片
其实关于VB.net中的opc编程,我也是看了好多网上的文章,还有opc的官方文档:

opc官网链接:
https://www.opcfoundation.cn/

不过opc不是免费的,官网里的一些文档是需要会员才能下载的,而会员必须得氪金。

程序

opc通讯分为几步,即扫描opc服务器、连接、数据读写或者订阅事件、断开服务器。
我们一步步来,首先是连接opc服务器。作为客户端程序,要从服务器获取数据,首先得和服务器建立连接,这是最基本的要求,而要连接服务器,首先要知道,要连接的服务器的信息。
opcAutomation库提供了“GetOPCServers”模块,用于获取当前处于活动状态的opc服务器列表。

Private Sub GetOpcServer(lb As ListBox)       '获取OPC服务器列表
        Dim getserver As OPCAutomation.OPCServer
        Dim infosvr As Object
        Dim i As Integer
        getserver = New OPCAutomation.OPCServer
        infosvr = getserver.GetOPCServers
        lb.Items.Clear()
        For i = LBound(infosvr) To UBound(infosvr)
            lb.Items.Add(infosvr(i))
        Next i
    End Sub

获取opc服务器列表后,选择自己要连接的服务器的名称,开始连接。OPCAutomation库提供“Connect”模块,用于与选定的opc服务器进行连接。

 Private Sub OpcServerConnect(daautosvr As OPCAutomation.OPCServer, lb As ListBox, lbl As Label)
        Try
            daautosvr.Connect(lb.SelectedItem, "")
            If daautosvr.ServerState = OPCAutomation.OPCServerState.OPCRunning Then
                lbl.Text = "已连接到:" + daautosvr.ServerName
            Else
                lbl.Text = "状态" + daautosvr.ServerState.ToString
            End If
        Catch
            MessageBox.Show("")
        End Try
 End Sub

和opc服务器连接成功后,就可以想办法读取服务器的数据了。因为opc的数据是item,即一个item代表一个数据,可以每次单独添加,也可以群体添加。
要读取服务器的item,需要在客户端建立和服务器中名称相同的item,然后使用read读取。

新建item

 Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click  '新建item
        Dim itm1 As ListViewItem

        itemID(newitemcount) = TextBox2.Text
        item(newitemcount) = daitems.AddItem(itemID(newitemcount), newitemcount)
        Label2.Text = newitemcount
        itm1 = ListView1.Items.Add(itemID(newitemcount))
        itm1.SubItems.AddRange({"", "", ""})

        newitemcount = newitemcount + 1
        itemcount = itemcount + 1

    End Sub

read数据

 Private Sub OpcItemRead(item As OPCAutomation.OPCItem, tb As TextBox)
        Dim s, v, q, t As Object
        item.Read(1, v, q, t)
        tb.Text = v
    End Sub

除了使用read、write进行读写item或items之外,opc提供一种基于数据变化的订阅事件,这个事件在groups中。groups是opc数据中的组,即item是包含中组里面的,所以,在客户端建立一个groups,里面包含多个group,而group又包含多个item或items。所以,对于整体的groups,对其数据进行统一监视,只要里面有数据在实时改变,就可以通过订阅事件来通知客户端,客户端就可以知道当前数据的实时值。

Private Sub dagroups_GlobalDataChange(TransactionID As Integer, GroupHandle As Integer, NumItems As Integer, ByRef ClientHandles As Array, ByRef ItemValues As Array, ByRef Qualities As Array, ByRef TimeStamps As Array) Handles dagroups.GlobalDataChange
        For i = 1 To NumItems
            itemvalue(i) = ItemValues(i)
            quality(i) = Qualities(i)
            tt(i) = TimeStamps(i)
        Next i
        For i = 1 To NumItems
            ListView1.Items.Item(i - 1).SubItems(1).Text = itemvalue(NumItems + 1 - i)
            ListView1.Items.Item(i - 1).SubItems(2).Text = quality(NumItems + 1 - i)
        Next i
    End Sub

当然,如果不读写数据的时候,记得关闭opc服务器并释放资源。

 Private Sub OpcServerDisconnect(daautosvr1 As OPCAutomation.OPCServer, dagroups1 As OPCAutomation.OPCGroups,
                                    dagroup1 As OPCAutomation.OPCGroup, daitems1 As OPCAutomation.OPCItems,
                                    daitem1 As OPCAutomation.OPCItem)
        dagroup1.IsActive = False
        dagroups1.Remove(dagroup.ServerHandle)
        daautosvr1.Disconnect()                         '断开opc服务器连接
        daitem1 = Nothing
        daitems1 = Nothing
        dagroup1 = Nothing
        dagroups1 = Nothing
        daautosvr1 = Nothing
    End Sub

下面是完整程序:

Option Explicit On
Imports System.Text
Public Class Form1
    Dim WithEvents daautosvr As OPCAutomation.OPCServer
    Dim WithEvents dagroups As OPCAutomation.OPCGroups
    Dim WithEvents dagroup As OPCAutomation.OPCGroup
    Dim daitems As OPCAutomation.OPCItems
    Dim daitem As OPCAutomation.OPCItem
    Dim item(100) As OPCAutomation.OPCItem
    Dim newitemcount As Integer
    Dim itemcount As Integer
    Public dabrowser As OPCAutomation.OPCBrowser
    Dim itemID(100) As String
    Public Shared itemvalue(100) As String
    Dim quality(100) As String
    Dim timestamps(100) As String
    Dim tt(100) As String
    Dim clihand() As Integer
    Dim svrhand() As Integer
    Dim err() As Integer
    Dim numitems As Integer = 3
    Dim r1, ap As Object
    
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        GetOpcServer(ListBox1)
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        With ListView1
            .Clear()
            .View = View.Details
            .FullRowSelect = False   '表示当单击此行选项时,是否选中整行
            .Columns.Add("itemID", 80)
            .Columns.Add("值", 80)
            .Columns.Add("质量", 80)
            .Columns.Add("时间", 80)
        End With
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        daautosvr = New OPCAutomation.OPCServer
        OpcServerConnect(daautosvr, ListBox1, Label1)
        dabrowser = daautosvr.CreateBrowser
        dagroups = daautosvr.OPCGroups
        dagroup = dagroups.Add("group1")
        dagroup.DeadBand = 0                                    '设置opc服务器参数
        dagroup.UpdateRate = 100
        dagroup.IsActive = True
        dagroup.IsSubscribed = True
        daitems = dagroup.OPCItems
        dabrowser.ShowBranches()
        
        Timer1.Interval = 1000
        Timer1.Start()
    End Sub

    Private Sub GetOpcServer(lb As ListBox)        '获取OPC服务器列表
        Dim getserver As OPCAutomation.OPCServer
        Dim infosvr As Object
        Dim i As Integer

        getserver = New OPCAutomation.OPCServer
        infosvr = getserver.GetOPCServers

        lb.Items.Clear()

        For i = LBound(infosvr) To UBound(infosvr)
            lb.Items.Add(infosvr(i))
        Next i

    End Sub

    Private Sub OpcServerConnect(daautosvr As OPCAutomation.OPCServer, lb As ListBox, lbl As Label)
        Try
            daautosvr.Connect(lb.SelectedItem, "")
            If daautosvr.ServerState = OPCAutomation.OPCServerState.OPCRunning Then
                lbl.Text = "已连接到:" + daautosvr.ServerName
            Else
                lbl.Text = "状态" + daautosvr.ServerState.ToString
            End If
        Catch
            MessageBox.Show("")
        End Try
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim svrname As String
        svrname = daautosvr.ServerName
        OpcServerDisconnect(daautosvr, dagroups, dagroup, daitems, daitem)
        If daautosvr.ServerState = OPCAutomation.OPCServerState.OPCDisconnected Then
            Label1.Text = "已断开连接:" + svrname
        End If
    End Sub

    Private Sub OpcServerDisconnect(daautosvr1 As OPCAutomation.OPCServer, dagroups1 As OPCAutomation.OPCGroups,
                                    dagroup1 As OPCAutomation.OPCGroup, daitems1 As OPCAutomation.OPCItems,
                                    daitem1 As OPCAutomation.OPCItem)
        dagroup1.IsActive = False
        dagroups1.Remove(dagroup.ServerHandle)
        daautosvr1.Disconnect()                         '断开opc服务器连接
        daitem1 = Nothing
        daitems1 = Nothing
        dagroup1 = Nothing
        dagroups1 = Nothing
        daautosvr1 = Nothing
    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        OpcItemRead(item(TextBox3.Text), TextBox1)
    End Sub

    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click  '新建item
        Dim itm1 As ListViewItem
        itemID(newitemcount) = TextBox2.Text
        item(newitemcount) = daitems.AddItem(itemID(newitemcount), newitemcount)
        Label2.Text = newitemcount
        itm1 = ListView1.Items.Add(itemID(newitemcount))
        itm1.SubItems.AddRange({"", "", ""})
        newitemcount = newitemcount + 1
        itemcount = itemcount + 1
    End Sub

    Private Sub OpcItemRead(item As OPCAutomation.OPCItem, tb As TextBox)
        Dim s, v, q, t As Object
        item.Read(1, v, q, t)
        tb.Text = v
    End Sub

    Private Sub dagroups_GlobalDataChange(TransactionID As Integer, GroupHandle As Integer, NumItems As Integer, ByRef ClientHandles As Array, ByRef ItemValues As Array, ByRef Qualities As Array, ByRef TimeStamps As Array) Handles dagroups.GlobalDataChange
    
        For i = 1 To NumItems
            itemvalue(i) = ItemValues(i)
            quality(i) = Qualities(i)
            tt(i) = TimeStamps(i)
        Next i
        
        For i = 1 To NumItems
            ListView1.Items.Item(i - 1).SubItems(1).Text = itemvalue(NumItems + 1 - i)
            ListView1.Items.Item(i - 1).SubItems(2).Text = quality(NumItems + 1 - i)

        Next i
    End Sub

    Private Sub 添加itemToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 添加itemToolStripMenuItem.Click
        Form2.Show()
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim s, v, q, t As Object
        If daautosvr.ServerState = OPCAutomation.OPCServerState.OPCRunning Then
            If itemcount > 0 Then
                For i = 0 To newitemcount - 1
                    item(i).Read(1, v, q, t)
                    If i >= 1 Then
                        ListView1.Items.Item(i).SubItems(1).Text = v
                        ListView1.Items.Item(i).SubItems(2).Text = q
                        ListView1.Items.Item(i).SubItems(3).Text = t
                    End If
                Next i
            End If
        End If
    End Sub
End Class

使用visual studio2019在VB.net中用OPC读写数据_第5张图片
本例中,调试时使用kepware来作为opc服务器的,没有使用西门子plc测试。

你可能感兴趣的:(VB.net实例应用,opc,vb.net)