# VB Warte Zeit



## knoddelpusch (17 März 2016)

Hallo,
ich stehe gerade vor einem Problem.

Ich bekomme über einen OPC-Server 3-Boolean Wert. Das Programm soll warten bis die 3-Werte auf True gesetzt werden.
Ich habe das jetzt über eine Do While schleife gemacht. Die Werte werden im OPC-Server auf True gesetzt. Aber jedoch nicht in VB.
Wenn ich eine Msgbox mit rein mache werden die Werte auch aktualisiert. Wenn ich eine sleep einsetzt werden ja die Werte auch nicht aktualisiert.
Welche Möglichkeit gibt es denn noch. Timer? Aber wie mach ich das dann genau.


----------



## Larry Laffer (17 März 2016)

VB ... und was ?
VB.Net, VB-Script ? In welchem Entwicklungsumfeld ?
Falls zum Beispiel Visual Studio und VB.Net so wäre der Einsatz eines Timers eine Möglichkeit, da du dadurch dein Programm (und das Drum-herum) responsiv hältst.

Vielleicht schreibst du erstmal etwas mehr ...

Gruß
Larry


----------



## knoddelpusch (18 März 2016)

VB.Net

Mit einer USB-Kamera mache ich mir ein Foto von einem weißen Spielfeld, da liegen ein paar schwarze Spielsteine.
Mit einem VB.Net Programm kann ich mir schon die Positionen der Spielsteine auswerten und kann diese auch per OPC-Server auf die Soft-SPS übertragen.
Da das Programm ja schnell durchlaufen wird kommt der Roboter nicht nach.
Deswegen lasse ich mir von den 3 POSMO-Motoren die Werte übertragen wann die Soll-Positionen erreicht sind.
Dies wollte ich in einer Do While Schleife machen, aber es werden die Werte von dem OPC-Server nicht mehr aktualisierte.
Wenn in den OPC-Scout reinschau werden dort die Werte aktualisierte, auch wenn ich in der Do While Schleife mir die Werte anzeigen lasse stehen die auch mit True, also Ziel Position erreicht, nur wenn ich die Msgbox wieder rauchs mache hängt er in der Schleife fest.
Wenn ich jetzt ein Sleep einbau werden die Werte auch nicht aktualisierte.

```
'Hier ist noch eine Sub wo ich die Soll-Positionen an die Motoren übertrage.

Privat Sub Soll_Position Erreicht()
  Do While (Pos_5 = False or Pos_6 = False or Pos_7 = False) ' Mache weil ein Fahrauftrag noch nicht Quitiert wurde
       Werte_Abfragen()
  Loop
End Sub

Privat Sub Werte_Abfragen()
' Hier eine Msgbox funktioniert alles wunderbar
    Pos_5 = chkFahrauftragerledigtM5.Checked 'Werte vom OPC-Server abfragen
    Pos_6 = chkFahrauftragerledigtM6.Checked 'Werte vom OPC-Server abfragen
    Pos_7 = chkFahrauftragerledigtM7.Checked 'Werte vom OPC-Server abfragen
End Sub
```

Wie funktioniert das mit dem Timer genau, bin noch in der Techniker-Schule und da haben wir das nie so genau gemacht mit den Timer.


----------



## RobiHerb (18 März 2016)

Ich vermute mal, dass da mehrere Threads aktiv sind. Der OPC Teil wird nur geupdatet, wenn sonst nichts zu tun ist, sprich die MSG Box gibt während man auf den Tastendruck wartet, die Resourcen frei. Deshalb geht es damit.

Ohne Box dreht sich die While Schleife ohne Unterbrechung in sich selbst. (Früher nannte Microsoft das so schön "Kooperatives Multitasking", das hier wäre dann nicht kooperativ programmiert)


----------



## oliver.tonn (18 März 2016)

Ich bin zwar etwas aus der Übung, aber ich meine mich zu erinnern, das bei einer MsgBox vor der Anzeige der Box diverse Queues abgearbeitet werden. Vermutlich musst Du die Aktualisierung der OPC-Daten in dem Sub noch anstossen.

Von irgendwas mit Internetzugang gesendet.


----------



## Larry Laffer (18 März 2016)

Hallo,
die Do-While-Schleife läßt dem Rest von Windows keine Zeit  mehr noch irgend etwas zu machen. VB.Net arbeitet vorwiegend  Event-basiert und um die auszuführen darf das Programm sich nicht selbst  blockieren. In dienem Fall werden zwar die Zwischen-Variablen im  .Net-Programm gesetzt - sie können aber gar nicht mehr weiter geleitet  werden.

Einen Timer instanzierst du ein Mal für dein Programm  oder deine Form und sagst ihm sein Intervall (in Millisekunden). Nun  löst der Timer in dem Intervall seinen .Tick aus, den du an eine Methode  hängen kannst (ähnlich wie zum Beispiel Button.MouseClick). In dieser  Methode kannst du nun z.B. deine Abfragen und Zuweisungen machen - sie  wird zyklisch in dem Intervall aufgerufen und anschließend wieder  beendet (um anderen Funktionen "eine Chance zu geben").

Hier ein Beispiel, wie das aussehen könnte :

```
' in deiner Form :
    [COLOR=blue]Public[/COLOR] [COLOR=blue]WithEvents[/COLOR] myTimer [COLOR=blue]As[/COLOR] [COLOR=blue]New[/COLOR] System.Windows.Forms.[COLOR=#2b91af]Timer[/COLOR] [COLOR=blue]With[/COLOR] {.Interval = 100, .Enabled = [COLOR=blue]True[/COLOR]} 

' als Timer-Methode :
   [COLOR=blue]Private[/COLOR] [COLOR=blue]Sub[/COLOR] myTimer_Tick(sender [COLOR=blue]As[/COLOR] [COLOR=blue]Object[/COLOR], e [COLOR=blue]As[/COLOR] System.[COLOR=#2b91af]EventArgs[/COLOR]) [COLOR=blue]Handles[/COLOR] myTimer.Tick
        [COLOR=green]' hier deine Aktionen ausführen[/COLOR]
    [COLOR=blue]End[/COLOR] [COLOR=blue]Sub[/COLOR]
```
Gruß
Larry


----------



## oliver.tonn (19 März 2016)

Oder so, stimmt das gibt es ja auch noch. Ansonsten müsste er die Abarbeitung aller anstehenden Dinge in der While-Schleife selber anstossen. Wie gesagt, bin schon zu lange raus und weiß nur noch das es da was gibt, aber nicht mehr wie es heißt. 

Von irgendwas mit Internetzugang gesendet.


----------



## knoddelpusch (21 März 2016)

Das heißt ich muss in der Timer Sub meine OPC Daten aktualisieren?

```
Privat Sub Soll_Position Erreicht()
  Do While (Pos_5 = False or Pos_6 = False or Pos_7 = False) ' Mache weil ein Fahrauftrag noch nicht Quitiert wurde
       Werte_Abfragen()
  Loop
End Sub

Private Sub Timer_Tick(sender As Object, e As System.EventArgs) Handles myTimer.Tick
    Pos_5 = chkFahrauftragerledigtM5.Checked 'Werte vom OPC-Server abfragen
    Pos_6 = chkFahrauftragerledigtM6.Checked 'Werte vom OPC-Server abfragen
    Pos_7 = chkFahrauftragerledigtM7.Checked 'Werte vom OPC-Server abfragen
End Sub
```
Oder Verstehe ich da was falsch?
Oder auch schon gleich die Do While Schleife?


----------



## holgermaik (21 März 2016)

Eher so:

```
Private Sub Soll_Position Erreicht()
        myTimer.Interval = 200               'Intervall festlegen
        myTimer.Enabled = True             'Timer anschalten
    End Sub

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles myTimer.Tick
        Werte_Abfragen()
        If Pos_5 = True And Pos_6 = True And Pos_7 = True Then ' alle Positionen gefunden
            myTimer.Enabled = False                                            ' Timer ausschalten
            Exit Sub                                                                    ' zurück zur Hauptroutine
oder hier weiter im Programm
        End If
    End Sub
```
Die Schleife ist dabei überflüssig.
Anmerkung: Du arbeitest nur mit globalen Variablen, besser wäre Funktionen zu schreiben mit Rückgabewerten. Bei längeren Programmen hast du sonst hunderte von globalen Variablen, wo die Übersichtlichkeit stark leidet.
Holger


----------



## Larry Laffer (21 März 2016)

... wobei ich den Timer (oder besser einen Backgroundworker) nicht abschalten würde sondern immer weiter abfragen lassen würde.
Du kannst es im Grunde mit dem OB1 der SPS vergleichen - der läuft ja auch dauernd - nur was er macht ändert sich ggf. 

Gruß
Larry


----------



## holgermaik (22 März 2016)

..dann wäre er hier aber an der falschen Stelle. Dazu müsste die Struktur des gesamten Programms anders aufgebaut sein. 
Für Beginner ist es oftmals einfacher für jedes Ereignis einen neuen Timer zu benutzen.
Holger


----------



## twincatter (22 März 2016)

Hallo,

so sollte es funktionieren:

Do While (Pos_5 = False or Pos_6 = False or Pos_7 = False) ' Mache weil ein Fahrauftrag noch nicht Quitiert wurde
*Application.DoEvents()
       System.Threading.Thread.Sleep(10)*
       Werte_Abfragen()
  Loop
Grüße, Michael


----------



## knoddelpusch (22 März 2016)

Hallo,
irgendwie bin ich zu blöd.
Wenn ich die OPC-Scout Software öffne sehe ich das sich die Variablen änderen, nur in VB.Net nicht.

Hab ihr mal den Code:

```
Imports SimaticNET.OPC.DAConnector
 
Public Class Form1
 
    Dim Pos_5, Pos_6, Pos_7 As Boolean
 
    'Ablagepunkte der Spielsteine Rand
    Dim P1, P2, P3, P4, P5, P6, P7, P8, Mitte As Punkt
 
    Public Declare Function Inp Lib "inpout32.dll" Alias "Inp32" (ByVal PortAddress As Integer) 'Eingänge
    Public Declare Sub Out Lib "inpout32.dll" Alias "Out32" (ByVal PortAddress As Integer, ByVal Value As Integer) 'Ausgänge
 
    Private Structure Punkt
        Dim X As Integer
        Dim Y As Integer
    End Structure
 
    Private Sub AblagePunkte …
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        SerialPort1.Open() 
    End Sub
 
    Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        SerialPort1.Close()
    End Sub
 
    Private Sub chkSauger_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkSauger.CheckedChanged
        If chkSauger.Checked = True Then
            SerialPort1.DtrEnable = True
        Else
            SerialPort1.DtrEnable = False
        End If
    End Sub
 
    Private Sub Turm()
        'Über Spielstein 1
        txtKordinateX.Text = P1.X
        txtKordinateY.Text = P1.Y
        chkHoch.Checked = True
 
        berechnen()
        chkStart.Checked = True
        Soll_Position_Erreicht()
  'Erst wenn die Soll-Position soll es hier weiter gehen
        'Auf Spielstein 1
        chkHoch.Checked = False
        berechnen()
        chkStart.Checked = True
    End Sub
 
  Private Sub Soll_Position Erreicht()
        myTimer.Interval = 200               'Intervall festlegen
        myTimer.Enabled = True              'Timer anschalten
    End Sub

    Private Sub Werte_Abfragen()
        Pos_5 = chkFahrauftragQuittierenM5.Checked 'Hier werden die CheckBoxen aktualisiert
        Pos_6 = chkFahrauftragQuittierenM6.Checked 'Sind also nicht direkt von dem OPC-Server
        Pos_7 = chkFahrauftragQuittierenM7.Checked 'Habe einen OPCDAConnector
    End Sub
 

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles myTimer.Tick
        Werte_Abfragen()
        If Pos_5 = True And Pos_6 = True And Pos_7 = True Then ' alle Positionen gefunden
            myTimer.Enabled = False                                            ' Timer ausschalten
            Exit Sub                                                                    ' zurück zur Hauptroutine
oder hier weiter im Programm
        End If
    End Sub
 
  End Class
```

Gibt es eine Möglichkeit direkt auf die OPC-Variablen zuzugreifen?
Habe im Internet noch nichts gefunden.


----------



## knoddelpusch (22 März 2016)

Hallo,
habe da noch im Internt ein möglichkeit gefunden auf die OPC-Variable zuzugreifen.

```
Variable = ("S7:[OPC-IPC]Fahrauftrag_Quittieren")
```
Es kommt jetzt aber die Meldung das eine Ungültige Konvertierung von der Zeichenfolge vorkommt.:-(
Es sind jedoch die zwei gleiche Variabletypen.
Mit der anderen Möglichkeit bin ich auch noch nicht weiter gekommen.:-(


----------



## Larry Laffer (23 März 2016)

Hallo,


knoddelpusch schrieb:


> Wenn ich die OPC-Scout Software öffne sehe ich das sich die Variablen änderen, nur in VB.Net nicht.


Bisher hatte ich angenommen, dass du die fraglichen Variablen-Inhalte in dein VB-Programm eingelesen bekommst - nur mit der sinnvollen Abfrage so deine Probleme hast.
Jetzt sieht es so aus, als wenn das absolut nicht der Fall wäre ...



knoddelpusch schrieb:


> Gibt es eine Möglichkeit direkt auf die OPC-Variablen zuzugreifen?
> Habe im Internet noch nichts gefunden.


Normalerweise läuft das in etwa so :
Du fragst bei deinem OPC-Server  die gewünschte Variable mit deren Namen (also der Namens-String der  ihrer Zuordnung im OPC-Server entspricht) an und erhältst von ihm ein  Object zurück, dass du dem passenden VB-Variablentyp zuordnen mußt.

Wie das genau vonstatten geht hängt von deinem OPC-Server ab zu dem du eine Doku dafür haben solltest - ansonsten vielleicht mal den Hersteller desselben antriggern.
Garantiert wirst du dafür eine Bibliothek (wharscheinlich eine DLL) in dein Projekt mit einbinden müssen.

Generell gilt aber :
Keine deiner Variablen bekommt von selber ihren neuen Wert zugeordnet ... du wirst das immer irgendwie abfragen müssen ...

Gruß
Larry


----------



## Larry Laffer (23 März 2016)

knoddelpusch schrieb:


> Hallo,
> habe da noch im Internt ein möglichkeit gefunden auf die OPC-Variable zuzugreifen.
> 
> ```
> ...



So etwas habe ich mal bei Excel gesehen - hier wird ein Feld mit dem OPC-Zugriffspfad verlinkt.
Das kannst du m.W. unter VB.Net so nicht nachstellen ...


----------



## holgermaik (23 März 2016)

Suche mal bei Siemens nach der Beitrags-ID: 21043779.
Holger


----------



## knoddelpusch (24 März 2016)

Morgen,
ne die Variablen habe ich schon in VB. Mein Programm läuft ja auch wenn ich mit Msgboxen arbeite das ich sehe wo es hängen bleibt, aber da geht es ja, weil ja das Programm eine „Pause“ einlegt.
Also ich habe in VB einen OPCDAConnector mit diesem kann ich meinen Variablen einen Wert von dem OPC zuweisen. Dies ändern sich auch wenn ich gerade in keiner Schleife fest hänge.
Aber da kann ich die Werte von dem OPC Server auf keine Variablen legen sondern nur auf Windows CheckBox oder Label usw. also nicht dirket auf eine Variable.


```
Private Sub Werte_Abfragen()
        Pos_5 = chkFahrauftragQuittierenM5.Checked 'Hier werden die CheckBoxen aktualisiert
        Pos_6 = chkFahrauftragQuittierenM6.Checked 'Sind also nicht direkt von dem OPC-Server
        Pos_7 = chkFahrauftragQuittierenM7.Checked 'Habe einen OPCDAConnector
    End Sub
```

Hier frage ich ja nur die CheckBox ab, diese ändert sich auch wenn ich in keiner Schleife fest hänge. 
Und mit der

```
Variable = ("S7:[OPC-IPC]Fahrauftrag_Quittieren")
```
Habe ich gedacht, dass ich direkt  auf die OPC-Variable zugreifen kann ohne CheckBox oder Label  wo ich vorher den Wert drauf lege.


----------



## Larry Laffer (24 März 2016)

... das heißt, du hast die OPC-Variable mit dem Control verlinkt ...?
In dem Fall funktioniert das Ganze dann so lange, wie das Control responsiv ist - dies ist aber nicht der Fall, wenn du irgendwo eine Schleife am Laufen hast. Allerdings würde dir dein Control ein CheckedStateChanged-Event schmeissen wenn sich sein Wert ändert. An so ein Event solltest du dann deinen Methoden-Aufruf festmachen (wobei ... ich würde das komplett so nicht machen 8)).
Mit etwas Glück würde ein gelegentliches Application.DoEvents deine Schleife in die Lage versetzen, dass deine Controls responsiv bleiben - das ist aber kein guter Stil.
Besser ist : IMMER Events nutzen wenn es welche gibt.

Gruß
Larry


----------

