Beckhoff TwinCat ADS OCX und VB.net

Parallax

Level-1
Beiträge
88
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich möchte in dem bei VS 2005 enthaltenem Visual Basic eine Softwäre für einen Beckhoff Industrie PC entwickeln. Dabei war eine Möglichkeit unter VB6 mit TwinCat eine dauerhafte Verbindung zwischen einer Variable und VB herzustellen das

CALL adsocx1.adsreadintegerconnect(blabla)

dies funktioniert zwar bei VB.net ebenfalls, allerdings wird die Variable nur einmal Aktualisiert und dann bleibt der Wert für alle Ewigkeit bestehen, auch wenn sich der Wert in TwinCat SystemManager ändert.

Hat dafür jemand eine Lösung

die "Connectete" Variable wird mittels eines Timers alle 50ms an zB
me.lblTest.Text = var1 übergeben

Aber wie gesagt die var1, welche Connected wurde wird nur bei Form Load geschrieben und dann nie wieder.

MFG
Parallax
 
Das OCX-Ding ist veraltet. Bei jeder TwinCat-Demo ist auch ein .Net2.0 Interface dabei. Ich poste hier mal ein paar Klassen, die ich so verbrochen habe:

In Arbeit
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke für die Info....

nun allerdings noch eine paar kleine bitten

also....

so etwas ähnliches hab ich mir schon gedacht, allerdings kann ich auf Beckhoff.de keine neue version von dem OCX teil finden geschweige den wie man dass einbindet


könntest du mir bitte einen Link geben, damit ich mir das neuste ziehen kann...

zweites Problem:


also ich hab ein Form...
dieses Form enthält eine Klasse, nämlich
Public Class frmMain

wo genau muss ich da nun was hinschreiben und was genau bedeutet das was ich da schreibe...^^

könntest du mir bitte anhand eines Beispiels erklären wir ich eine Integervariable (ich benutze in der regel die Addresse nach folgendem Schema: 61741,0,2,usw...) connectet und dann diesen wert in einer variable überträgt...


vielen dank für die anstrengung

mfg
Parallax
 
Teil1

Also OCX ist out und .Net-Interface wird von Beckhoff geliefert. Hier ein Bsp.

Ankopplung Klasse Teil 1:

Code:
Public Delegate Sub EventChangedVar(ByVal sender As Object, ByVal e As PLCVariableChangedEventArg)
Public Delegate Sub AsyncChangeEvent(ByRef v As System.Collections.Generic.List(Of PLCVarPoolElement))

Public Class PLCBase

    Private PLCThread As Thread
    Private prioA_thread As Thread
    Private prioB_thread As Thread
    Private prioC_thread As Thread
    Private RunThreads As Boolean

    Private timeA As Integer = 500
    Private timeB As Integer = 2000
    Private timeC As Integer = 4000
    Private timePLC As Integer = 500

    Private tcADS As TcAdsClient
    Private ADSAdress As String
    Private ADSPort As Integer
    Private ADSTimeout As Integer = 100
    Private ADSConnectState As ADSConnectState
    Private ADSState As TwinCAT.Ads.AdsState

    Private State As String

    Private VarDic As System.Collections.Generic.Dictionary(Of String, PLCVarPoolElement)

    Public Event OnPLCVarChange As PLCVarChangeHandler
    Public Event OnPLCConnectMsg As PLCConnectMsgHandler

    Private lock As New Object()



    Public Sub New(ByVal ADSAdress As String, ByVal ADSPort As Integer)
        MyBase.New()
        Me.ADSAdress = ADSAdress
        Me.ADSPort = ADSPort
        VarDic = New System.Collections.Generic.Dictionary(Of String, PLCVarPoolElement)
    End Sub

    Public Sub New(ByVal ADSAdress As String, ByVal ADSPort As Integer, ByVal Timeout As Integer)
        MyBase.New()
        Me.ADSAdress = ADSAdress
        Me.ADSPort = ADSPort
        Me.ADSTimeout = Timeout
        VarDic = New System.Collections.Generic.Dictionary(Of String, PLCVarPoolElement)
    End Sub

    Public Sub AddPLCVar(ByVal name As String, ByVal path As String, ByVal type As PLCType, ByVal timeclass As PLCTimeClass, Optional ByVal size As Integer = 1)
        VarDic.Add(name, New PLCVarPoolElement(name, path, type, timeclass, size))
    End Sub


    Protected Sub GetPLCVars()
        For Each element As PLCVarPoolElement In Me.VarDic.Values
            Dim var As PLCVariable
            Select Case element.PLCType
                Case PLCType.PLCArrayInteger
                    var = New PLCVarArrayInteger(Me, element.PLCPath, element.PLCSize, element.PLCTimeClass)
                Case PLCType.PLCArrayUInteger
                    var = New PLCVarArrayUInteger(Me, element.PLCPath, element.PLCSize, element.PLCTimeClass)
                Case PLCType.PLCBoolean
                    var = New PLCVarBoolean(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCDate
                    var = New PLCVarDate(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCDInteger
                    var = New PLCVarDInteger(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCUDInteger
                    var = New PLCVarUDInteger(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCInteger
                    var = New PLCVarInteger(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCUInteger
                    var = New PLCVarUInteger(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCDouble
                    var = New PLCVarDouble(Me, element.PLCPath, element.PLCTimeClass)
                Case PLCType.PLCString
                    var = New PLCVarString(Me, element.PLCPath, element.PLCSize, element.PLCTimeClass)
                Case Else
                    'var = Nothing
                    Throw New PLCException("PLC type is not implementet!")
            End Select
            element.PLCVariable = var
        Next
    End Sub

    Private Sub DropPLCVars()
        For Each element As PLCVarPoolElement In Me.VarDic.Values
            Try
                If Not (element.PLCVariable Is Nothing) Then
                    element.PLCVariable.Dispose()
                    element.PLCVariable = Nothing
                End If
            Catch ex As Exception
            End Try
        Next
    End Sub


    Protected Sub Connect()
        Me.tcADS = New TcAdsClient()
        Me.tcADS.Synchronize = True
        Me.tcADS.Connect(Me.ADSAdress, Me.ADSPort)
        Me.tcADS.Timeout = ADSTimeout
        AddHandler tcADS.AdsStateChanged, AddressOf AdsStateChangedEventHandler
    End Sub

    Protected Sub Disconnect()
        Try
            If Not (Me.tcADS Is Nothing) Then
                SyncLock Me.tcADS
                    Me.tcADS.Dispose()
                    Me.tcADS = Nothing
                End SyncLock
            End If
        Catch ex As TwinCAT.Ads.AdsException

        End Try
    End Sub

    Private Sub SendConnectMsg(ByVal msg As String)
        RaiseEvent OnPLCConnectMsg(Me, New PLCConnectMessageEventArg(msg))
    End Sub


    Private Sub PLCVarsRead(ByVal type As PLCTimeClass)


        Dim vars As System.Collections.Generic.List(Of PLCVarPoolElement) = New System.Collections.Generic.List(Of PLCVarPoolElement)
        SyncLock lock

            For Each element As PLCVarPoolElement In VarDic.Values
                If element.PLCTimeClass = type Then
                    Try
                        element.PLCVariable.Read()
                        If element.PLCVariable.Changed() Then
                            vars.Add(element)
                        End If
                    Catch ex As Exception
                        MsgBox(ex.Message.ToString)
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCleanUp
                        Return
                    End Try
                End If
            Next
        End SyncLock
        If vars.Count > 0 Then
            RaiseEvent OnPLCVarChange(Me, New PLCVariableChangedEventArg(vars))
        End If
    End Sub

    Private Sub PLCVarsRead2(ByVal type As PLCTimeClass)


        Dim vars As System.Collections.Generic.List(Of PLCVarPoolElement) = New System.Collections.Generic.List(Of PLCVarPoolElement)
        SyncLock lock

            For Each element As PLCVarPoolElement In VarDic.Values
                If element.PLCTimeClass = type Then
                    Try
                        element.PLCVariable.Read()
                        vars.Add(element)
                    Catch ex As Exception
                        MsgBox(ex.Message.ToString)
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCleanUp
                        Return
                    End Try
                End If
            Next
        End SyncLock
        If vars.Count > 0 Then
            RaiseEvent OnPLCVarChange(Me, New PLCVariableChangedEventArg(vars))
        End If
    End Sub


    Private Sub ADSCleanUp()
        DropPLCVars()
        Disconnect()
    End Sub
 
Zuletzt bearbeitet:
Teil2

Ankopplung Teil2

Code:
    Private Sub ConnectStateMachine()
        While True
            Select Case Me.ADSConnectState
                Case BECKADS2.ADSConnectState.ADSInitialize
                    SendConnectMsg("Initialize " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSConnectState = BECKADS2.ADSConnectState.ADSTryConnectToPLC
                    If Not RunThreads Then
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                    End If

                Case BECKADS2.ADSConnectState.ADSTryConnectToPLC
                    SendConnectMsg("Connecting " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Connect()
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSWaitOnRun
                    Catch ex As TwinCAT.Ads.AdsException
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSTryConnectToPLC
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                    End If

                Case BECKADS2.ADSConnectState.ADSWaitOnRun
                    SendConnectMsg("Check for PLC-state RUN at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        If Me.ADSClient.ReadState().AdsState = TwinCAT.Ads.AdsState.Run Then
                            Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCheckPLCProgram
                        End If
                    Catch ex As TwinCAT.Ads.AdsException
                        Disconnect()
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSTryConnectToPLC
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                    End If

                Case BECKADS2.ADSConnectState.ADSCheckPLCProgram
                    SendConnectMsg("Check for PLC-program at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Dim plc_version As New PLCVarString(Me, ".VERSION", 1)
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnectFields
                        plc_version.Dispose()
                    Catch ex As TwinCAT.Ads.AdsException
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCheckPLCProgram
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                    End If

                Case BECKADS2.ADSConnectState.ADSConnectFields
                    SendConnectMsg("Connecting PLC vars at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Me.GetPLCVars()
                        Dim plc_version As New PLCVarString(Me, ".VERSION", 50)
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnectFields
                        plc_version.Dispose()
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnected

                    Catch ex As TwinCAT.Ads.AdsException
                        Me.DropPLCVars()
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCheckPLCProgram
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                    End If

                Case BECKADS2.ADSConnectState.ADSConnected
                    SendConnectMsg("Connected at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    SyncLock Me.lock
                        If Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnected Then
                            Try
                                If Me.ADSClient.ReadState().AdsState <> TwinCAT.Ads.AdsState.Run Then
                                    Me.ADSConnectState = BECKADS2.ADSConnectState.ADSWaitOnRun
                                    Me.DropPLCVars()
                                End If
                            Catch ex As TwinCAT.Ads.AdsException
                                Me.ADSConnectState = BECKADS2.ADSConnectState.ADSCleanUp
                            End Try
                        End If
                        If (Not RunThreads) Then
                            Me.ADSConnectState = BECKADS2.ADSConnectState.ADSExit
                        End If
                    End SyncLock

                Case BECKADS2.ADSConnectState.ADSCleanUp
                    SendConnectMsg("Clean up " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSCleanUp()
                    Me.ADSConnectState = BECKADS2.ADSConnectState.ADSTryConnectToPLC

                Case BECKADS2.ADSConnectState.ADSExit
                    SendConnectMsg("Closed " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSCleanUp()
                    Exit While
            End Select
            Thread.Sleep(timePLC)
        End While
    End Sub
    Private Sub thread_a()
        While RunThreads
            If Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnected Then
                Me.PLCVarsRead(PLCTimeClass.A)
            End If
            Thread.Sleep(timeA)
        End While
    End Sub

    Private Sub thread_b()
        While RunThreads
            If Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnected Then
                Me.PLCVarsRead(PLCTimeClass.B)
            End If
            Thread.Sleep(timeB)
        End While
    End Sub

    Private Sub thread_c()
        While RunThreads
            If Me.ADSConnectState = BECKADS2.ADSConnectState.ADSConnected Then
                Me.PLCVarsRead(PLCTimeClass.C)
            End If
            Thread.Sleep(timeC)
        End While
    End Sub

    Public Sub AdsStateChangedEventHandler(ByVal sender As Object, ByVal e As TwinCAT.Ads.AdsStateChangedEventArgs)
        Me.ADSState = e.State.AdsState
        Select Case Me.ADSState
            Case ADSState.Config
            Case ADSState.Error
            Case ADSState.Init
            Case ADSState.Invalid
            Case ADSState.LoadConfig
            Case ADSState.PowerFailure
            Case ADSState.PowerGood
            Case ADSState.Reconfig
            Case ADSState.Reset
            Case ADSState.Resume
            Case ADSState.Run
            Case ADSState.SaveConfig
            Case ADSState.Shutdown
            Case ADSState.Start
            Case ADSState.Stop
            Case ADSState.Suspend
        End Select
    End Sub

    Public Sub StartThreads()
        RunThreads = True
        Me.PLCThread = New Thread(AddressOf ConnectStateMachine)
        Me.PLCThread.Priority = ThreadPriority.Normal
        Me.PLCThread.IsBackground = True
        Me.PLCThread.Start()

        Me.prioA_thread = New Thread(AddressOf thread_a)
        Me.prioA_thread.Priority = ThreadPriority.BelowNormal
        Me.prioA_thread.IsBackground = True
        Me.prioA_thread.Start()

        Me.prioB_thread = New Thread(AddressOf thread_b)
        Me.prioB_thread.Priority = ThreadPriority.Lowest
        Me.prioB_thread.IsBackground = True
        Me.prioB_thread.Start()

        Me.prioC_thread = New Thread(AddressOf thread_c)
        Me.prioC_thread.Priority = ThreadPriority.Lowest
        Me.prioC_thread.IsBackground = True
        Me.prioC_thread.Start()

    End Sub

    Public Sub StopThreads()
        RunThreads = False
        Me.prioA_thread.Join()
        Me.prioB_thread.Join()
        Me.prioC_thread.Join()
        Me.PLCThread.Join()
    End Sub


    Public Sub SetTimes(ByVal timeA As Integer, ByVal timeB As Integer, ByVal timeC As Integer, ByVal timePLC As Integer)
        Me.timeA = timeA
        Me.timeB = timeB
        Me.timeC = timeC
        Me.timePLC = timePLC
    End Sub

#Region "Properties"
    Public Property Adress() As String
        Get
            Return ADSAdress
        End Get
        Set(ByVal Value As String)
            ADSAdress = Value
        End Set
    End Property

    Public Property Port() As Integer
        Get
            Return ADSPort
        End Get
        Set(ByVal Value As Integer)
            ADSPort = Value
        End Set
    End Property

    Public ReadOnly Property ADSClient() As TcAdsClient
        Get
            Return Me.tcADS
        End Get
    End Property

    Public Property Timeout() As Integer
        Get
            Return ADSTimeout
        End Get
        Set(ByVal Value As Integer)
            ADSTimeout = Value
        End Set
    End Property

    Public ReadOnly Property ConnectState() As ADSConnectState
        Get
            Return Me.ADSConnectState
        End Get
    End Property

    Public ReadOnly Property PLCVar(ByVal name As String) As PLCVariable
        Get
            Return Me.VarDic.Item(name).PLCVariable
        End Get
    End Property

    Private ReadOnly Property PoolElements() As System.Collections.Generic.Dictionary(Of String, PLCVarPoolElement)
        Get
            Return Me.VarDic
        End Get
    End Property

    Public ReadOnly Property IsRunning() As Boolean
        Get
            Return Me.RunThreads
        End Get
    End Property

#End Region

End Class
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Teil3

Basisklasse zu den Variablen

Code:
Public Class PLCVariable
    Implements IDisposable
    Private mConnect As Boolean = False
    Protected VarPath As String
    Protected hVar As Integer = 0
    Protected adsStream As AdsStream
    Protected adsClient As TcAdsClient
    Protected VarSize As Integer
    Protected VarTimeClass As PLCTimeClass


    Public Sub New(ByRef connect As PLCBase, ByVal VarPath As String, ByVal Size As Integer, Optional ByVal timeclass As PLCTimeClass = KitronADS2.PLCTimeClass.X)
        MyBase.New()

        Me.adsClient = connect.ADSClient
        Me.Path = VarPath
        Me.VarSize = Size
        Me.TimeClass = timeclass

        Try
            Me.adsStream = New AdsStream(VarSize)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

        Me.Connect()
    End Sub

    Public Sub Connect()
        Try
            adsClient.ReadState()
            Me.hVar = adsClient.CreateVariableHandle(VarPath)
            Me.mConnect = True
        Catch ex As Exception
            Me.mConnect = False
        End Try
    End Sub

    Public Overridable Sub Read()
        If (Not Me.Connected) Then
            Throw New PLCException("Connection to " + Me.VarPath + " broken")
        End If
    End Sub

    Public Overridable Sub Write()
    End Sub

    Public Overridable Function Changed() As Boolean
        Return True
    End Function

    Public Overloads Sub Dispose() Implements IDisposable.Dispose
        Me.adsStream.Close()
        Me.adsStream.Dispose()
        Me.adsStream = Nothing
        adsClient.DeleteVariableHandle(Me.hVar)
        ' Take yourself off of the finalization queue
        ' to prevent finalization code for this object
        ' from executing a second time.
        GC.SuppressFinalize(Me)
    End Sub


    Public Property Path() As String
        Get
            Return Me.VarPath
        End Get
        Set(ByVal value As String)
            Me.VarPath = value
        End Set
    End Property

    Public ReadOnly Property Handle() As Integer
        Get
            Return hVar
        End Get
    End Property

    Public ReadOnly Property Stream() As AdsStream
        Get
            Return adsStream
        End Get
    End Property

    Public ReadOnly Property Size() As Integer
        Get
            Return VarSize
        End Get
    End Property

    Public ReadOnly Property Connected() As Boolean
        Get
            Dim succ As Boolean = True
            Try
                Me.adsClient.ReadState()
            Catch ex As Exception
                succ = False
            End Try
            Return succ And Me.mConnect
        End Get
    End Property

    Public Property TimeClass()
        Get
            Return Me.VarTimeClass
        End Get
        Set(ByVal value)
            Me.VarTimeClass = value
        End Set
    End Property

End Class

Konkrete Variablenklasse

Code:
Public Class PLCVarInteger
    Inherits PLCVariable
    Private value As Int16
    Private oldvalue As Int16

    Public Sub New(ByRef connect As PLCBase, ByVal Path As String, Optional ByVal timeclass As PLCTimeClass = PLCTimeClass.X)
        MyBase.New(connect, Path, 2, timeclass)
    End Sub


    Public Overrides Sub Read()
        Dim reader As AdsBinaryReader
        MyBase.Read()

        reader = New AdsBinaryReader(Me.Stream)
        Me.adsClient.Read(Me.hVar, Me.adsStream)
        Me.adsStream.Position = 0
        oldvalue = value
        Me.value = reader.ReadInt16()
        reader = Nothing
    End Sub

    Public Overrides Sub Write()
        Dim writer As AdsBinaryWriter
        MyBase.Write()
        writer = New AdsBinaryWriter(Me.adsStream)
        Me.adsStream.Position = 0
        writer.Write(CType(Me.value, Int16))
        Me.adsClient.Write(Me.hVar, Me.adsStream)
        writer = Nothing
    End Sub

    Public Overrides Function Changed() As Boolean
        Return (oldvalue <> value)
    End Function

    Public Property val() As Int16
        Get
            Return Me.value
        End Get
        Set(ByVal Value As Int16)
            Me.value = Value
        End Set
    End Property

End Class


Code:
Public Delegate Sub PLCDelegateStringCallback(ByVal [text] As String)
Public Delegate Sub PLCDelegateIntegerCallback(ByVal [integer] As Integer)
Public Delegate Sub PLCDelegateUIntegerCallback(ByVal [uint] As UInteger)
Public Delegate Sub PLCDelegateBooleanCallback(ByVal [boolean] As Boolean)
 
Teil4

Das ganze ist vor 2 Jahren entstanden und ich bin nicht wirklich zufrieden, weil die Klasse von aufgerufnene Delegates mit .Net2 nicht herausbekomme. Somit muss ich im Programm immer noch folgende Konstruktion haben:


Code:
  Public Sub VariableChanged(ByVal sender As Object, ByVal e As PLCVariableChangedEventArg)
        For Each field As PLCVarPoolElement In e.fields
            Select Case field.PLCVarName
                Case "version"
                    Dim d As New BECKADS2.PLCDelegateStringCallback(AddressOf PLC_DispatchVersion)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarString).val})
                Case "st01_carisin"
                    Dim d As New BECKADS2.PLCDelegateBooleanCallback(AddressOf PLC_DispatchCarIsIn)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarBoolean).val})
                Case "st01_carinit"
                    Dim d As New BECKADS2.PLCDelegateBooleanCallback(AddressOf PLC_DispatchCarInit)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarBoolean).val})
                Case "st01_carstatus"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchCarStatus)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarInteger).val})
                Case "output"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchOutput)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarInteger).val})
                Case "input"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchInput)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarInteger).val})
                Case "st01_yield"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchST01Yield)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarDInteger).val})
                Case "st03_yield"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchST03Yield)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarDInteger).val})
                Case "st05_yield"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchST05Yield)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarDInteger).val})
                Case "st07_yield"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchST07Yield)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarDInteger).val})
                Case "st08_yield"
                    Dim d As New BECKADS2.PLCDelegateIntegerCallback(AddressOf PLC_DispatchST08Yield)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarDInteger).val})
                Case "st01_labelcode"
                    Dim d As New BECKADS2.PLCDelegateStringCallback(AddressOf PLC_DispatchST01LabelCode)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarString).val})
                Case "st02_i_dontsolder"
                    Dim d As New BECKADS2.PLCDelegateBooleanCallback(AddressOf PLC_DispatchSoldering)
                    Me.Invoke(d, New Object() {CType(field.PLCVariable, PLCVarBoolean).val})

                Case Else
                    Me.StatusStrip.Items("errormsg").Text = "unknown PLC variable:" + field.PLCVarName
            End Select
        Next
    End Sub
Dazu habe ich Beckhoff misstraut und selbst Events bei Änderungen implementiert und das ist Müll.


Nun ja, die Initialisierung ist einfach:

Code:
Private Sub PLC_Init()
        Try
            Me.PLC_base = New BECKADS2.PLCBase(My.Settings.ADSNetID, My.Settings.ADSNetPort)
            AddHandler Me.PLC_base.OnPLCVarChange, AddressOf Me.VariableChanged
            AddHandler Me.PLC_base.OnPLCConnectMsg, AddressOf Me.StatusChanged
            AddFields()
            PLC_base.StartThreads()
        Catch ex As Exception
            MsgBox(ex.Message.ToString, MsgBoxStyle.Critical, "Critical failure in PLC_init!")
            PLC_base = Nothing
        End Try
    End Sub


    Private Sub PLC_Destroy()
        If Not (Me.PLC_base Is Nothing) Then
            PLC_base.StopThreads()
            PLC_base = Nothing
        End If
    End Sub

    Private Sub AddFields()
        PLC_base.AddPLCVar("version", ".Version", PLCType.PLCString, PLCTimeClass.C, 50)
        PLC_base.AddPLCVar("Var01", ".ST1.var01", PLCType.PLCBoolean, PLCTimeClass.A)
    End Sub
 
Ach ja, die Bibliothe ist nicht vollständig, so wie ich die gepostet habe. Es ist nur als Implementierungsbeispiel gedacht.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ähm.... ja

danke für die viele mühe nur die sache ist das ich seit ungefähr 2 monaten mit VB 2005 arbeite... daher hab ich von dem ganzen klassenzeugs und so keine ahnung... also das was mein stand ist, ist dass ich ein Steuerelement platziere, meine adresse eingeb und dann unter Form_Load einfach und bescheiden

Call AdsOcx1.AdsReadIntegerConnect(Gruppe,Offset,Länge,Art,Time, "Var")

schreib und dann meinen Wert hab....

so wie deine beispiele aussehen scheint das so als kann ich diese easy und ständig funtionale methode vergessen und darf mich nun durch kiloweise klassen und dämliches VB 2005 kämpfen...

ich frag mich warum man net einfach alles so lassen kann wie es gut war sondern nun son gewirr einführen muss....

aber scheinbar gehts ja wohl net anders

aber danke für die vielen beispiele die ich irgendwann 2010 mal alle verstehen werd...

mfg
Parallax
 
Wenn du das nicht objektorientiert implementierst, dann bekommst du Probleme bei Verbindungsabrüchen und zwar ganz massive. Du musst nach einem Verbindungsabbruch, also einem Fehler in der Kommunikation ALLE Ressourcen wieder freigeben, sonst blockiert der PC sehr schnell und du darfst rebooten. Die Arbeit lohnt sich in jedem Falle.

Meine Idee dahinter war, dass ich eine Verbindung aufbaue und alle Variablen, die ich connecte, in einer Liste sammle, damit ich bei einem Fehler alles elegant und schnell freigeben kann. So ein Fehler kann überall auftreten. Ohne Exceptions wird das zum Alptraum eines Programmierers.
 
hallo

ich muss mich normal bei dir melden weil ich mit dem Zeug überhaupt net zurecht komm. Evt. sollte ich erwähnen das ich kein Programmierer bin sondern nur ein paar einfache Oberflächen mit ein paar simplen Bedingungen und Berechnungen in VB6 gecodet hab. Dazu zählen zum Beispiel ein Programm zum Auswerten eines Tischtennis oder Schafkopfturniers (^^) und ein paar Oberflächen für Maschinen wie zum Beispiel eine Statusanzeige für Schwerlastzylinder und ähnliches. Dabei hab ich halt immer meine Variablen dimensioniert und dann halt a weng was zam rechnen lassen, teilen, wurzeln, differenzieren und so weiter und dann halt irgedwo anzeigen lassen.

So meine Oberfläche und meine Maschinensteuerung funktionieren mittlerweile auch unter VB.Net oder 2005 und wie das jetzt heißt.

Das einzige was ich noch brauche ist die Kommunikation mit TwinCat.

Ich kann dir ja mal erklären was ich bisher gemacht hab.

Also ich habe mit des neue OCX dings geholt und dann mit Verweis hinzufügen in mein Projekt eingebunden.

Als nächstes hab ich im Code (ganz oben, also im allgemeinen Bereich)

Imports TwinCAT.Ads

reingeschrieben. Das scheint dafür da zu sein um dieses OCX dings irgendwie zu implementieren

Als nächstes habe ich unter der Class des Forms

Private tcClient As TcAdsClient

eingefügt.

Bis jetzt hab ich immer noch keine ahnung was diese Anweisung bedeuet aber scheint irgend eine Dimensionierung zu sein. Ich hab die nur reingeschrieben weil mir jemand gesagt hat ich solls reinschreiben....

So nun müsste ich ja irgendwie den Port und die NetId angeben damit das ding kommunizieren kann.

Unter Form Load steht bis jetzt

tcClient = New TcAdsClient()

was das nun wieder genau bedeutet..: keine Ahnung

so aber nun müsste ich ja eine Var mit irgend etwas beschreiben

Also mit Dim varTest as Integer mal ne Testvar erstellt und dann hab ich gelesen brauch ich

varTest = tcClient.AddDeviceNotification(Gruppe,Offset,dataStream??,Länge,AdsTransMode.OnChange,Cycle,Delay,userData as Object???)

so das meiste is mir klar aber was ist ein dataStream oder was erwartet der da von mir und was is Userdata as Object. In VB6 kommt ja da der Name für die var rein die mit dem Wert beschrieben werden soll....


Nun ja etz weißt du auf was für einen Stand ich bin und was mir fehlt. Ich hab mir schon mehrere Codes angeschaut werd aber aus dem Objekt zeug net schlau... Also mir war die Art von VB6 wesentlich lieber... das hat man noch verstanden ohne Informatik gelernt zu haben.

MfG
Andre Wagner
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Streams sind die Datenströme in .Net. Dabei ist es nicht wichtig, ob etwas aus einer Datei, dem Speicher oder einer SPS kommt oder geschrieben wird, so die Theorie. Die verschiedenen Streams sind verschieden mächtig.

Du eröffnest einen Stream weil du Daten aus der SPS holen willst. Genauso gut kannst du einen Stream eröffnen, um eine Datei zu lesen.
 
aja und wie eröffne ich einen solchen stream und welche "mächtigkeit" brauch ich dafür...

gibt es irgendwo deutschsprachige erklärungen zu den entsprechenden methoden und ähnliches....

wie gesagt ich benutzt vb.net erst seid 2 monaten und war die meiste zeit damit beschäftigt die oberfläche zu erstellen und mich da etwas reinzudenken...

und warum ich am anfang das

Private tcClient As TcAdsClient

schreibe weiß ich immer noch net^^....

ich hab mir auch ein paar bücher angeschaut aber da steht nur sowas drin wie eine klasse ist ein blablabla das nix davon wie ich das hinschreib und was das alles zu bedeuten hat..

für vb6 war wenigstens in der beckhoff doku explizit gestanden was man tun muss und was was in der anweisung heißt und so konnte ich das auch nachvollziehen aber hier stehen nur tausend fachbegriffe und ich hab keine ahnung mehr

mfg
andre wagner
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich danke für die umfassenden antworten und Unterlagen die ich von dir bekommen hab. Allerdings habe ich dadurch aus festgestellt das ich ein schweres Problem habe.

Ich habe bis ende der Woche eine Frist für diese Anlage und das ist ein sehr großes Problem.

Kurzer Überblick zur erklärung:

Ich programmiere seit einigen Jahren SPS in einem kleineren Betrieb, was ich mir in größtenteils selbst oder über Bücher beigebracht habe.
Dazu gehört die Logo von Siemens, alle arten von Möller und ein paar wenige andere. Meist wurden damit nur kleine Maschinen mit maximal 40 Ein- und Ausgängen angesteuert.

Seid einiger Zeit mache ich das auch mit Beckhoff da ich dort VB6 über Busskoppler verwenden kann. VB6 habe ich mir auch über die Jahre selbst beigebracht und konnte damit einiges bewerkstelligen.
Nun habe ich eine neue Maschine und eine neue Steuerung, nämlich eine CX1010-xxxx und die Aus und Eingänge sind etwas mehr geworden. Die komplexität ist nicht das Problem das das Hauptprogramm mehr oder weniger komplett vorliegt und die Aufgaben erfüllt.

Das Problem ist wie geschrieben die Kommunikation.
Ich ging beim erwerb dieser Steuerung von der einfachheit von VB6 aus und lies mich dazu überreden VS2005 zu verwenden da dies (so wurde mir gesagt) sich von den Anweisungen nicht stark von VB6 unterscheidet.

Nachdem sich Windows CE als ungenügend herausstellte habe ich auf einen Win XP rechner gewechselt, die Programmierung unter VS2005 is zwar wesentlich einfacher geworden und meine Oberfläche und Programmablauf sind größtenteils fertig aber das Problem an Kunden ist das sie diesen Aufwand nicht sehen sondern immer drehende Teile zu ihrer zufriedenheit verlangen.
Wie ich ja nun auf grund deiner Unterlagen nachlesen konnte is das mehr als komplex und ich werde das bis Freitag nicht komplett schaffen.

Nun 2 Fragen die mehr oder weniger über leben und tot entscheiden^^:

gibt es von Beckhoff oder irgendwem anders eine dll oder sonst irgendetwas die einem den ganzen Müll von Klassen und sonst allem abnimmt so das man wieder auf seine ausreichend Primitive Call adsocx1.AdsReadIntegerConnect ( ... und so weiter kommt...??


2. Wenn es sowas nicht gibt, gibt es irgendwo eine stelle oder Hotline oder am besten aussendienst oder kurs oder was weiß ich auch immer der in ungeahnter geschwindigkeit (das heißt bis Freitag) das einem zeigt und erklärt.

Das Problem is nicht das ich etwas nicht verstehe wenn man mir sagt wozu diese anweisung da ist was sie tut was sie verlangt und so weiter...

Nur wenn ich ein Buch vor mir habe der mich mit Begriffen überschüttet und ich immern noch net so viel mehr von Streams weiß dann is das bis Freitag unmachbar....

Mfg
Parallax

PS: Ich kann in diesem Projekt leider nicht mehr auf VB6 wechseln da die anschaffungskosten für VS2005 mit in das Projekt mit einfließen und der kunde dann natürlich auch in dieser Version ein Programm haben willl
 
Uppss, da bist du wirklich in einer schwierigen Situtation. Nein, es gibt ausser der ADS-Bibliothek keine weiteren Hilfen und das ist wirklich Mist.

Ich empfehle:

1) Werfe alles über Bord, was ich über das Freigeben von Ressourcen schrieb und mache es Straightforward. Das führt später zu kleineren Problemen, die aber als Bug verkauft werden können.

2) Dann brauchts du sowieso eine Bibliothek, die eine Architektur gemäss meinen Angaben verlangt und schreibst das Programm mit Hilfe der Bibliothek neu. (dauert max 1Tag)
 
hm ich hab ja über wochenende schon verschiedene bücher durchgelesen aber so schnell lernt man das leider nicht...

jetzt hab ich beckhoff am sonntag ne email geschrieben in der hoffnung das mir einer ihrer entwickler erklärt an einem auskommentierten beispielprogramm wie ich von anfang an nachdem ich das adsocx.dll eingebunden habe die verbindung aufbau und dann einen wert auslesen...

bekommt heute nachmittag antwort.. ich hoffe das dass was wird....

ich habe mir gestern noch gedacht naja kann ja net so schwer sein einfach ne ne verbindung herzustellen und dann einen wert zu lesen... nur wenns schon mal an dem stream scheitert weiß ich auch net...

mein chef hat schon angeboten er zahlt was wenn mir das jemand erklärt aber du wirst auch net aus der nähe von Hersbruck/Nürnberg kommen^^??

mfg
parallax
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nee, ich komm nicht aus der Nähe :) Ich bräuchte so mit dem Flugzeug (inkl. aller Wartezeiten grrr) so 1 Tag Anreisezeit und 1000Eu für einen Flug. Wenn ich nicht demnächst meinen Job wechseln sollte, können wir die Lib auf Sourceforge zusammen designen. Ich brauche sowieso eine verbesserte Version. Einen grossen Teil der Tipperei habe ich ja schon.
 
Zuletzt bearbeitet:
naja ich hab mich für den nächsten kurs eingetragen allerdings hilft der mir für das projekt auch nix mehr....

hm... aber mal im ernst...

in vb6 brauchte ich zum connecten auf eine variable ca 3 minuten und dann gings...

des kann doch net denen ihr aller ernst sein das man nun mehr als ne stunde und n diplom in vb.net braucht um mich mit einer variable zu verbinden...

also entweder bin ich in dem fall schwer von begriff oder ich übersehe einfach irgendwas....

wenn ich schon mal ne auflistung von den befehlen methoden und sonst was hab was mit des ADS teil bringt wäre ich ja schon mal sehr glücklich nur leider finde ich in dem Infosys von beckhoff nur zeug für vb.net... irgendwas will mich bei dem projekt tierisch verarschen...

mfg
parallax
 
Nein, du hast recht, es ist einfach. Aber, die praktischen Probleme gibt es hinterher, denn wenn z.B. der HMI-PC heruntergefahren wird, ohne dass das Programm alle seine Variablen zur SPS freigegeben hat. Die wird dann irgendwann immer mehr CPU verbrauchen. Das kann man hervorragend sichtbar machen, wenn den FB aus der Systembibliothek nutzt und sich die CPU-Belastung anzeigen lässt. Die steigt dann nämlich. Ausserdem hatten wir Probleme mit dem Netzwerk und dann passiert ähnliches. Meine einzigste Abwehr war, alles sehr geordnet hoch und herunterzufahren.

Damit ich dass einfach machen konnte, habe ich alle Variablenverbindungen in eine Liste eines Objektes gelegt, und beim Beenden des Programmes brauche ich nur noch zu schreiben: PLS.close, weil ich einfach mit einer Schleife alle Verbindungen durchgehen kann, anstatt 80 oder mehr Variablen freizugeben. So viel hatte ich nämlich in einem Programm und mir wurde das alles zu unübersichtlich.

Hier bietet die Objektorientierung einfach das bessere Mittel, auch wenn es mehr Tippserei ist.


Die Organisation ist so:

Hauptklasse ist

"PLC"

- Legt die Verbindung zur SPS an und überwacht diese st¨ndig. Bei einem Timeout, werden alle Variablen freigeben und die Verbindung neu aufgebaut.
- Verwaltet alle Variablen

Dann kommt
"PLCVariable"

- Diese Klasse ist Wurzelklasse für alle Variablentypen wie z.B. PLCInteger
- Weil alle Valriablenklassen von "PLCVariable" abstammen, kann ich die in die Liste packen, ohne dass es Typkonflikte gibt.


Um in eine Var vom Typ Int zu schreiben mache ich das einfach so:

dim t as PLCInteger = new PLCInteger('.X_Value')
t.val = 2
t.write
t.dispose

Das wars. Das ist auch der Sinn dieser Lib. EInmal geschrieben, nimmt die einem viel Arbeit ab und verhindert mögliche Fehler.
 
Zurück
Oben