Verwendung DotNetSiemensPLCToolBoxLibrary von Jochen Kühner

Zuviel Werbung?
-> Hier kostenlos registrieren
1. Danke für den Test meines Testprogrammes

Ich werde es am Montag nochmals ausprobieren.
Jo schreib mir dann obs ging!

2. BCD-Zahlen

Ich habe nur quer Beet alle Varianten deiner DLL erprobt.
Selber hab ich sie noch nicht benötigt - also lass es so wie es ist.
Zu spät, nun hab Ichs schon geändert! Und wenns drinn ist solls ja auch richtig sein!

3. Und nun doch noch eine Frage

Wie due in meinem Testprogramm vieleicht bemerkt hast, habe ich den Aufruf und das Einlesen einer Symboldatei mittels deiner DLL bereits integriert.
Funktioniert wunderbar.
Nun meine Frage:
Die Rückgabe eines BlockTags ist mir auch gelungen.
Ist es möglich die Auflistung der in einem Datenbaustein (Block) enthaltenen Tags heranzukommen?
Bis jetzt ist es mir immer nur gelungen einen TAG des Blocks zu lesen.

Ja das geht! Nutze Ich z.B. in ToolBoxForSiemensPLCs um Datenbausteinwerte Online anzuschauen.

Beispielcode:

Code:
S7DataBlock myBlock = woher auch immer...
List<S7DataRow> tmpLst = S7DataRow.GetChildrowsAsList(myBlock.Structure);
List<PLCTag> valueList = S7DataRow.GetLibnoDaveValues(askLst);
Hier wandelst du erstmal die Hirachische Struktur des DBs in eine flache Liste um (tmpLst) und dann Wird davon eine Liste von PLCTags erstellt (valueList )
 
Noch ne Frage

Hallo Jochen

Dein Beispielcode ist sehr interessant:

Wie kann ich den S7DataBlock myBlock aus einem Offlineprojekt versorgen (laden) ?

Die zweite und dritte Zeile deines Codes ist eindeutig - in VB lauten sie wohl:

Dim myBlock As New S7DataBlock()
Dim tmpList As New List(Of S7DataRow)
Dim valueList As New List(Of PLCTag)


tmpList = S7DataRow.GetChildrowsAsList(myBlock.Structure)
valueList = S7DataRow.GetLibnoDaveValues(tmpList

Wie aber kann die "myBlock" Variable versorgen ?

z.B. myBlock=Projectfiles.SelectProjectPart. - wie?


Dankbar für eine Antwort - hanjo
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In deinem Code kannst du dir das New sparen:
Code:
Dim myBlock As New S7DataBlock()
Dim tmpList As New List(Of S7DataRow)
Dim valueList As New List(Of PLCTag)


tmpList = S7DataRow.GetChildrowsAsList(myBlock.Structure)
valueList = S7DataRow.GetLibnoDaveValues(tmpList)

Da du später den variablen ja eine neue Instanz zuweist, sonst wird unötigerweise eine Instanz erzeugt!

Die Funktion Projectfiles.SelectProjectPart gibt es für einen datablock noch nicht (könnte Ich aber einbauen.). Du kannst aber mit Projectfiles.SelectProjectPart.SelectBlocksOfflineFolder eine Instanz von BlocksOfflineFolder bekommen aus der kannst du mit readPlcBlocksList() die enthaltet Bausteine auflisten, und mit GetBlock bekommst du dann auch den Block (wenn es ein S7-DB ist als S7DataBlock Instanz!)
 
Lesen und Schreiben probiert

Hallo Jochen

Ich habe das Lesen und Schreiben mit der Version 74916 probiert und deiner neuen umbenannten libnodave_jfkmod.dll.
Es funktioniert alles wie es soll - verstehe nicht warums beim ersten mal nicht geklappt hat.

Werde es demnächst auch immer wieder mit deiner neusten Version prüfen-
Z.B der Verrsion 74916.

Anmerkung :
Auch so, eines ist mir aufgefallen, bei allen Versionen muss ich die
Höhe der Forms
- PLCTagEditor
- SelectProjectPartForm
- ConnectionEditor
vergrössern, damit sie ganz (in voller Höhe ) angezeigt werden.
Beispiel für die Orginal und die vergrösserte Darstellung (nur Höhe). siehe Anhang.

Ich arbeite mit Windows 7 32 Bit und Visual Studio 2010.

Bin begeistert von den Möglichkeiten der Verwendung orginaler Step7-Projekte - z.B. öffnen eines Projektes , auslesen der Symboldateien und ...

Grosses Lob für deine Arbeit - sehr gut.

hanjo
 

Anhänge

  • ConnectionEditorOrginal.jpg
    ConnectionEditorOrginal.jpg
    54 KB · Aufrufe: 55
  • ConnectionEditor_Vergrössert.jpg
    ConnectionEditor_Vergrössert.jpg
    51 KB · Aufrufe: 50
Zuviel Werbung?
-> Hier kostenlos registrieren
Anmerkung :
Auch so, eines ist mir aufgefallen, bei allen Versionen muss ich die
Höhe der Forms
- PLCTagEditor
- SelectProjectPartForm
- ConnectionEditor
vergrössern, damit sie ganz (in voller Höhe ) angezeigt werden.

Kann Ich mir im Moment nicht erkläre, auf meinem PC und denen meiner Kollegen passt das Fenster! Hast du irgendwas an den Darstellungsoptionen von Windows umgestellt?

Vielleicht hat sonst noch jemand das gleiche Problem?
 
Hallo Jochen

Lesetest - verschiedene Varianten

Ich habe heute verschiedene Lesetests durchgeführt.
Unter „Lesetest“ verstehe ich dabei das Lesen von Variablen aus der SPS.
Die Lesetestergebnisse sind in der Exceldatei im Anhang dargestellt.
Lesetest Variante 1
Lesen eines ByteArrays (zusammenhängender Bereich)

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - aVar ist eine Liste von PLCTags – „TagList As List(Of PLCTag)”
Lesetest Variante 2
Lesen einer zuvor zusammengestellten Variablenliste

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - Var ist ein ByteArray – Einzelvariable

Lesetest Variante 3
Lesen eines Bytearrays mit bis zu 220 Bytes

Basis : LibNoDave
res = dc.readBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

Lesetest Variante 4
Lesen eines Bytearrays mit mehr als 220 Bytes

Basis : LibNoDave
res = dc.readManyBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

Zusammenfassung und Frage
Die Variante 1 sollte, meiner Meinung nach, in etwa die gleiche Funktion sein wie die in Variante 4.
Beide Varianten lesen ein zusammenhängendes ByteArray mit gleichem Leseergebnis :

Variante 1 : Verwendet „DotNetSiemensPLCToolBoxLibrary„
Variante 4 : Verwendet „LibNoDave“ in der „DotNetSiemensPLCToolBoxLibrary“

Die Lesezeit für 700-Bytes dauert
für Variante 1 min. 499ms360µs686ns und
für Variante 4 min. 18ms761µs135ns

Das ist ein erheblicher Unterschied.
Ich habe daraufhin mal in deiner „DotNetSiemensPLCToolBoxLibrary“


Ø unter „PLCConnection.cs“
Ø in der Funktion „public void ReadValue(PLCTag value)“
Ø die Zeile in der gelesen wird - auskommentiert
int res = _dc.readManyBytes(Convert.ToInt32(value.LibNoDaveDataSource), value.DatablockNumber, value.ByteAddress, readSize, ref myBuff);

Dann wird zwar nicht mehr gelesen, - die Aufrufdauer liegt dann bei 2ms, d.h. der große Lesezeitunterschied liegt in dieser Funktion begründet.

Meine Frage :
Warum dauert das Lesen gegenüber dem Originalaufruf der LibNoDave so viel länger?
Ich würde die Variante 1 lieber verwenden, weil ich in diesem Fall deine Funktionen zur Konfiguration und zum Aufbau der Verbindung verwenden kann.
Ich habe übrigens auch erprobt das Bytearray „ref myBuff“ in einer extra Funktion direkt auszugeben – aber auch dieser Aufruf verkürzt die Lesedauer nicht.

Viele Grüsse hanjo
 
Hallo Jochen

Hab beim ersten mal vergessen den Anhang beizulegen


Lesetest - verschiedene Varianten

Ich habe heute verschiedene Lesetests durchgeführt.
Unter „Lesetest“ verstehe ich dabei das Lesen von Variablen aus der SPS.
Die Lesetestergebnisse sind in der Exceldatei im Anhang dargestellt.
Lesetest Variante 1
Lesen eines ByteArrays (zusammenhängender Bereich)

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - aVar ist eine Liste von PLCTags – „TagList As List(Of PLCTag)”
Lesetest Variante 2
Lesen einer zuvor zusammengestellten Variablenliste

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - Var ist ein ByteArray – Einzelvariable

Lesetest Variante 3
Lesen eines Bytearrays mit bis zu 220 Bytes

Basis : LibNoDave
res = dc.readBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

Lesetest Variante 4
Lesen eines Bytearrays mit mehr als 220 Bytes

Basis : LibNoDave
res = dc.readManyBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

Zusammenfassung und Frage
Die Variante 1 sollte, meiner Meinung nach, in etwa die gleiche Funktion sein wie die in Variante 4.
Beide Varianten lesen ein zusammenhängendes ByteArray mit gleichem Leseergebnis :

Variante 1 : Verwendet „DotNetSiemensPLCToolBoxLibrary„
Variante 4 : Verwendet „LibNoDave“ in der „DotNetSiemensPLCToolBoxLibrary“

Die Lesezeit für 700-Bytes dauert
für Variante 1 min. 499ms360µs686ns und
für Variante 4 min. 18ms761µs135ns

Das ist ein erheblicher Unterschied.
Ich habe daraufhin mal in deiner „DotNetSiemensPLCToolBoxLibrary“


Ø unter „PLCConnection.cs“
Ø in der Funktion „public void ReadValue(PLCTag value)“
Ø die Zeile in der gelesen wird - auskommentiert
int res = _dc.readManyBytes(Convert.ToInt32(value.LibNoDaveDataSource), value.DatablockNumber, value.ByteAddress, readSize, ref myBuff);

Dann wird zwar nicht mehr gelesen, - die Aufrufdauer liegt dann bei 2ms, d.h. der große Lesezeitunterschied liegt in dieser Funktion begründet.

Meine Frage :
Warum dauert das Lesen gegenüber dem Originalaufruf der LibNoDave so viel länger?
Ich würde die Variante 1 lieber verwenden, weil ich in diesem Fall deine Funktionen zur Konfiguration und zum Aufbau der Verbindung verwenden kann.
Ich habe übrigens auch erprobt das Bytearray „ref myBuff“ in einer extra Funktion direkt auszugeben – aber auch dieser Aufruf verkürzt die Lesedauer nicht.

Viele Grüsse hanjo
 

Anhänge

  • Lesetest.jpg
    Lesetest.jpg
    239,4 KB · Aufrufe: 45
  • TestLesezeiten.zip
    6,7 KB · Aufrufe: 11
Zuviel Werbung?
-> Hier kostenlos registrieren
Mal sehn...

Ich schau mirs morgen mal an. Als info vorab schon mal: der leseaufruf von mehreren zusammenhängenden plctags wird noch nicht optimiert! Dies ist aber in Arbeit, wird aber noch etwas dauern...
 
Na klar geht es - anbei der Code

Hallo Jochen


Das Testprojekt habe ich im Anhang beigelegt.
Die entscheidenden Aufrufe befinden sich unter Tab-Reiter „Variablenliste“.

Variante 1 - Lesen eines zusammenhängenden Bytearrays mit deiner DLL

Variante 4 - Lesen eines zusammenhängenden Bytearrays mit LibNoDave
Meiner Meinung wird in deiner DLL das Bytearray in gleicher Weise gelesen wie laut LibNoDave, eben mit ReadManyBytes.
Ich glaube nicht, dass es mit der fehlenden Optimierung zu tun hat.
Viele Grüsse hanjo
 

Anhänge

  • Test.rar
    1,5 MB · Aufrufe: 53
Zuviel Werbung?
-> Hier kostenlos registrieren
Noch was als Ergänzung

Hallo Jochen

im Anhang habe ich ergänzend die AWL-Quelle für den Test-DB3500 und eine VAT (Excel) zum schnelleren testen beigelegt.
Du kannst ja die DB-Nummer auch in eine andere umbenennen.
Bitte beachte, dass die DB-Nummer in meinem Code fix hinterlegt ist - die müsste dann auch geändert werden.
Die VAT kannst du aus der Exceldatei über die Zwischenablage in dein SPS-Projekt importieren.

Viele Grüsse hanjo
 

Anhänge

  • VAT und DB3500.rar
    5,3 KB · Aufrufe: 15
Ein paar Infos....

Das ist schon mal falsch:
Code:
 'Konfigurationsmenü Verbindung 1
Configuration.ShowConfiguration("SPS1", True)
PLCCon1.Configuration.ConnectionName = "SPS1"

der Code sollte so ausehen:
Code:
'Konfigurationsmenü Verbindung 1
        Configuration.ShowConfiguration("SPS1", True)
        PLCCon1 = New PLCConnection("SPS1")

Und bei mir dauert das lesen von 700 Bytes entweder über ReadTag oder über ReadManyBytes um die 110ms... also bei beiden gleich lang...
Sicher das dein readManyBytes auch funktioniert hat? den res value wertest du nämlich nicht aus!
 
PS:

Habs auch noch so probiert:

Code:
Dim aa As New List(Of PLCTag)
            aa.Add(aVar)

            xTime2.Reset()
            xTime2.UhrStart()
            
            PLCCon1.ReadValues(aa) 'Neue Funktion Bytearray direkte Rückgabe 

            
            xTime2.UhrStop()
            txtDauer.Text = xTime2.DauerNanoSec

Dauert auch fast genau 110ms...

Hab dabei auch noch ein Bug bei ReadManyValues gefunden, wenn ein Tag nicht in die PDU gepasst hat! Fix dazu kommt...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Jochen

die Instanz der Verbindung "SPS1" habe ich im Modul "mdl_Globals" bereits als Public PLCCon1 as New PLCConnection("SPS1") angelegt.

Ich dachte, dass ich dieser Instantz dann im
'Konfigurationsmenü Verbindung 1
einfach nur zuordnen muss.

Das readManyBytes über die LibNoDave hat funkkktioniert-es ist aber korrekt, das Res habe ich nicht ausgewertet.

Mein Hardwareaufbau war:
S7-400
CPU417-4
CP443-1

Ich probier es am Montag noch mal.

Vielen Dank für deine Bemühungen.

Gruss hanjo
 
Hallo Jochen

die Instanz der Verbindung "SPS1" habe ich im Modul "mdl_Globals" bereits als Public PLCCon1 as New PLCConnection("SPS1") angelegt.

Das Problem ist, das New PLCConnection("SPS1") im Konstruktor aus der Registry liest. Ich könnte auch reinmachen das die Config vor dem Verbindungsaufbau nochmals gelesen wird, dann wird diese Zeile überflüssig:
Code:
PLCCon1 = New PLCConnection("SPS1")
aber den ConnectioNamen nochmals zuweisen wie hier:
Code:
PLCCon1.Configuration.ConnectionName = "SPS1"
ist auf jeden Fall nicht nötig!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So...

Hab jetzt auch mal noch ne optimier Funktion bei ReadValues eingebaut, diese kombiniert verschiedene Tags wenn das Ende eines Tags nicht weiter als 4 Byte entfernt liegt! Oder auch überlappende Bytes werden kombiniert!
 
Hab jetzt auch mal noch ne optimier Funktion bei ReadValues eingebaut, diese kombiniert verschiedene Tags wenn das Ende eines Tags nicht weiter als 4 Byte entfernt liegt! Oder auch überlappende Bytes werden kombiniert!

Ja, so eine Optimierung hab ich auch schon mal realisiert. Aber das theoretische Optimum ist bei einer Lücke mit 16 Bytes.

Jede Antwort hat einen Protokoll-Overhead von 4 Bytes. Aber auch der Request hat einen Overhead von 12 Bytes!. Mit jedem Paket das angefordert wird, gibt das einen Overhead von 4+12 = 16 Bytes. Es ist also effizienter, eine Lücke von 16Bytes mitzulesen, als das in zwei Aufrufen zu machen.

Aus der praktischen Erfahrung ergab sich sogar, daß für die effektive Bandbreite das Optimum bei einer Lücke von 20(!) Bytes liegt. Das ergibt zwar wieder mehr Busverkehr, aber im Datendurchsatz (kB/sec) ist hier das Maximum zu messen. (Kann aber abhängig vom SPS-Typ sein). Vermutlich tut sich die SPS intern auch leichter, einen längeren Block am Stück zu kopieren, als zwei kleine.
 
Ja, so eine Optimierung hab ich auch schon mal realisiert. Aber das theoretische Optimum ist bei einer Lücke mit 16 Bytes.

Jede Antwort hat einen Protokoll-Overhead von 4 Bytes. Aber auch der Request hat einen Overhead von 12 Bytes!. Mit jedem Paket das angefordert wird, gibt das einen Overhead von 4+12 = 16 Bytes. Es ist also effizienter, eine Lücke von 16Bytes mitzulesen, als das in zwei Aufrufen zu machen.

Aus der praktischen Erfahrung ergab sich sogar, daß für die effektive Bandbreite das Optimum bei einer Lücke von 20(!) Bytes liegt. Das ergibt zwar wieder mehr Busverkehr, aber im Datendurchsatz (kB/sec) ist hier das Maximum zu messen. (Kann aber abhängig vom SPS-Typ sein). Vermutlich tut sich die SPS intern auch leichter, einen längeren Block am Stück zu kopieren, als zwei kleine.

Also das das mit den 16 Bytes stimmt bin kann Ich nicht glauben, da Ich in eine Anfrage bei einer PDU größe von 240 Bytes 17 Tags bekomme, wenn diese jedoch alle 16 Bytes auseinander liegen würden, und Ich alle zusammenfassen würde, müsste meine Antwort 16*17 als mindestens 272 Bytes groß sein, was nicht mehr in eine PDU passt....
 
Zurück
Oben