# daveReadBytes schreibt nicht in den Buffer (Excel VBA)



## Martin Glarner (26 November 2005)

Hallo
Ich mache gerade meine ersten Gehversuche mit Libnodave.

Mein Ziel:
Ich möchte alle Werte eines Datenbausteins aus der Steurung lesen und in ein Arrray abspeichern.

Was funktioniert:
Ich kann über IBH-Link und ISn_TCP einzelne Werte aus der Steuerung lesen.

Was geht nicht:
daveReadByte schreibt die gelesenen Werte nicht direkt in mein Array. (Buffer)


```
Function DB_lesen_aus_SPS() As Variant

Dim Buffer(19) As Byte
Dim ph, di, dc As Long
Dim res As Integer
Dim v1 As Long

    ' Verbindungsaufbau funktioniert
    res = SPS_Verb_aufbauen(ph, di, dc)

    If res = 0 Then
    
        ' Bei dieser Variante werden die Werte nicht in den Buffer geschrieben.
        res = daveReadBytes(dc, daveDB, 120, 0, 20, Buffer(0))

        ' Bei dieser Variante wird ein Laufzeitfehler im Excel ausgelöst
        rem res = daveReadBytes(dc, daveDB, 120, 0, 20, Buffer)

        ' Hier wird der Wert richtig in v1 geschrieben
        v1 = daveGetS32At(dc, 6)
    
    End If

    ' Verbindung wird wieder richtig abgebaut
    Call SPS_Verb_abbauen(ph, di, dc)

End Function
```

Wer kann mir einen Hinweis geben?

Ist es sinnvoller, wenn ich mit "daveGetU8" Byte für Byte in einer Schleife aus dem internen Buffer lese und in mein Array kopiere?

Besten Dank für euer Hilfe


----------



## seeba (26 November 2005)

```
res = daveReadBytes(dc, daveDB, 120, 0, 20, Buffer)
```

So müsste es gehen!


----------



## Martin Glarner (26 November 2005)

Hallo seeba



			
				seeba schrieb:
			
		

> ```
> res = daveReadBytes(dc, daveDB, 120, 0, 20, Buffer)
> ```
> So müsste es gehen!



Diese Variante habe ich schon getestet.
Wie oben im Code beschrieben, wird ein Laufzeitfehler im Excel ausgelöst (Programm stürzt ab, kein VBA Fehler)

Besten Dank


----------



## seeba (26 November 2005)

Martin Glarner schrieb:
			
		

> Hallo seeba
> 
> 
> 
> ...



Du hast es mit irgendeiner "rem" Deklaration getestet!


----------



## Martin Glarner (26 November 2005)

Ich habe beim testen der oberen Variante, den Text "rem" entfernt und bei der unteren Variante  davor geschrieben, damit jeweils nur eine dieser Zeilen ausgeführt wird.

Müsste es mit Buffer(0) oder aber auch bei einem nächsten Aufruf mit Buffer(20) nicht auch funktionieren?


----------



## seeba (26 November 2005)

Martin Glarner schrieb:
			
		

> Ich habe beim testen der oberen Variante, den Text "rem" entfernt und bei der unteren Variante  davor geschrieben, damit jeweils nur eine dieser Zeilen ausgeführt wird.
> 
> Müsste es mit Buffer(0) oder aber auch bei einem nächsten Aufruf mit Buffer(20) nicht auch funktionieren?



Nein so wird es nicht funktionieren! Du hast den Buffer als Byte-Array deklariert?

*Alles klar, hab's gesehen!*

Du liest da also aus DB120 ab DBB0 20 Bytes? Hmm versteh nicht, warum es nicht gehen soll! Was zeigt er denn genau an?


----------



## Martin Glarner (26 November 2005)

Ich definiere mit "Dim Buffer(19) As Byte" ein Array mit 20 Byte (0..19). 
Ich habe es schon mit "Dim Buffer(200) As Byte" probiert. Müsste eigentlich auch geht.
Ich habe es schon mit "Dim Buffer(19) As Variant" probiert. 

Im Buffer stehen nach der Ausführung lauter 0 drin.
In res steht 0 drin
In v1 steht der richtige Wert aus DB120.DBD6


----------



## seeba (26 November 2005)

Martin Glarner schrieb:
			
		

> Ich definiere mit "Dim Buffer(19) As Byte" ein Array mit 20 Byte (0..19).
> Ich habe es schon mit "Dim Buffer(200) As Byte" probiert. Müsste eigentlich auch geht.
> Ich habe es schon mit "Dim Buffer(19) As Variant" probiert.
> 
> ...



Wenn's über den internen Buffer geht, könntest du das einfach weglassen. Ansonsten weiß wohl nur noch Zottel Rat.


----------



## Martin Glarner (26 November 2005)

Hallo,

Über den internen Buffer geht es ohne Probleme. Habe gerade folgendes getestet:


```
For i = 0 To 19
            Buffer(i) = daveGetU8(dc)
        Next i
```

Ich werde nun erst einmal mit dieser Variante weiter arbeiten.
Besten Dank für deine schnelle Hilfe


----------



## Zottel (28 November 2005)

Ändere bitte in der Definition von daveReadBytes das letzte Argument in:
ByRef buffer As Byte
Anschließend kannst du einen Puffer, den du mit 
dim buffer(1024) As Byte  ' oder wie lang du ihn brauchst
definiert hast, als buffer(0) als letztes Argument angeben.


----------



## Martin Glarner (28 November 2005)

Hallo Zottel
Besten Dank, nun geht es.

' Read a value or a block of values from PLC.
Private Declare Function daveReadBytes Lib "libnodave.dll" (ByVal dc As Long, ByVal area As Long, ByVal areaNumber As Long, ByVal start As Long, ByVal numBytes As Long, *ByRef buffer As Byte*) As Long


----------



## Zottel (29 November 2005)

Das Problem an der Sache ist nur:
Mit dieser Deklaration mußt du zwangsläufig einen eigenen Puffer übergeben. Die C-Funktion prüft, ob der Zeiger auf den Puffer den Wert "NULL" hat. Das entspricht einem longint mit dem Wert 0. Falls es 0 ist, versucht sie nicht, Ergebnisse in den Puffer zu kopieren. Und ich habe bis jetzt keinen Weg gefunden, in VB einen "NULL"-Wert zu übergeben, so daß er auch von der aufgerufenen C-Funktion richtig erkannt wird.
Falls mir kein VB-Freak einen Tip geben kann, werde ich es in der nächsten Version wahrscheinlich so machen:
Bei daveReadBytes werde ich den Parameter für den Puffer entfernen, so daß immer mit dem internen Puffer gearbeitet werden muß.
Wer mit einem eigenen Puffer arbeiten will, soll daveReadManyBytes benutzen. daveReadManyBytes kann einen Block lesen, der größer ist, als das, was in einem Zugriff aus die SPS übertragen werden kann und verteilt das Lesen wenn nötig auf mehrere Zugriffe. Da der interne Puffer dafür sowieso nicht ausreicht, bruacht es immer einen Puffer, der von der Anwendung zur Verfügung gestellt wird.
In dem Fall, daß die Anzahl Bytes in einem einzigen Leseaufruf gelesen werden kann, unterscheidet sich daveReadManyBytes nur von daveReadBytes durch einen zusätzlichen call/return beim internen Aufruf von daveReadBytes.
Leider ist in der gegenwärtigen Version daveReadManyBytes fälschlicherweise als daveManyReadBytes deklariert (Tippfehler). 
Wenn du keine bessere Idee hinsichtlich der Übergabe eines "NULL"-Zeigers auf den Puffer hast und dein Programm "zukunftssicher" schreiben willst, kopiere einfach die funktionierende Deklaration von daveReadBytes für daveReadManyBytes und benutze daveReadManyBytes statt daveReadBytes.


----------



## Martin Glarner (30 November 2005)

*Libnodave: daveReadManyBytes in Excel VBA*

Hallo Zottel
Besten Dank für den Hinweis.
Ich habe "daveReadManyBytes" getestet. Leider funktioniert es nicht ganz ohne Problem.
Wenn die Daten über S7Online gelesen werden, kann ich nur einmal Daten von der SPS auslesen. Beim zweiten Versuch wird der Laufzeitfehler '6' Überlauf ausgegeben. Ich nehme an, dass dies mit dem Problem Verbindungsabbau zusammenhängt. siehe unten.

Hier noch meine Deklaration:
Private Declare Function daveReadManyBytes Lib "libnodave.dll" (ByVal dc As Long, ByVal area As Long, ByVal areaNumber As Long, ByVal start As Long, ByVal numBytes As Long, *ByRef buffer As Byte) *As Long

Zusatzfrage:
Ich habe leider keine 400er CPU zum testen. Hast du schon einmal 65536 Byte von einer S7-400 gelesen?


Frage zum Verbindungsabbau mit "/S7ONLINE"

- Der Verbindungsaufbau mit "ph = openS7online(acspnt)" funktioniert.
- Beim ersten Verbindungsaufbau wird der gültige Wert 0 zurückgegeben.
     Ab nun kann im Step7 unter PG/PC-Schnittstelle nichts mehr angepasst  werden,  was auch richtig ist.
     Meldung "Die benutzte Schnittstelle kommuniziert gerade. Sie können den Zugriffsweg im Moment nicht ändern"

- Nach dem lesen sollte mit "res = daveDisconnectAdapter(di)" die Verbindung wieder abgebaut werden.
  Ich habe gelesen, das "res = closePort(ph)" bei S7Online nichts macht.

- Beim nächsten Verbindungsaufbau bekomme ich ph=1, 2, 3, 4, 5, 6, 7, Acht)
  Beim 10.Verbindungsversuch wird -1 zurückgegeben.
  Sollte hier nicht jedesmal der Wert 0 zurückgegeben werden, wenn die Verbindung korrekt abgebaut wurde?

- Wenn das Excel geschlossen und wieder geöffnet wird, funktioniert ein erneuter Verbindungsaufbau. 
- In Step7 kann die Schnittstelle wieder geändert werden, wenn das Excel geschlossen wurde.

Als Lösung könnte ich die Verbindung nicht meht schliessen, doch in Step7 kann dann die Schnittstelle nicht mehr angepasst werden.

Besten Dank für dein Hilfe


----------



## Zottel (30 November 2005)

*Re: Libnodave: daveReadManyBytes in Excel VBA*



			
				Martin Glarner schrieb:
			
		

> Hallo Zottel
> Besten Dank für den Hinweis.
> Ich habe "daveReadManyBytes" getestet. Leider funktioniert es nicht ganz ohne Problem.
> Wenn die Daten über S7Online gelesen werden, kann ich nur einmal Daten von der SPS auslesen. Beim zweiten Versuch wird der Laufzeitfehler '6' Überlauf ausgegeben. Ich nehme an, dass dies mit dem Problem Verbindungsabbau zusammenhängt. siehe unten.


Hallo Martin,
auch wenn meine Makros das anders machen: Wenn du fortlaufend Werte von der SPS lesen willst, solltest du nur einmal openSocket, setPort oder openS7online sowie initAdapter und connectPLC aufrufen (oder sub initialize), schon weil diese Funktionen recht viel Zeit benötigen. Anschließend rufst du halt daveReadBytes oder daveReadManyBytes sooft auf, wie du neue oder andere Werte holen willst.
Meine Makros schließen die Verbindung sofort wieder, weil ich sonst "verwalten" müßte, ob eine Verbindung schon besteht und die einzelnen Makros nicht mehr unabhängig und weniger übersichtlich wären. Zudem müßte der user nach dem letzten Aufruf irgendeines Makros die Verbindung schließen.


> Hier noch meine Deklaration:
> Private Declare Function daveReadManyBytes Lib "libnodave.dll" (ByVal dc As Long, ByVal area As Long, ByVal areaNumber As Long, ByVal start As Long, ByVal numBytes As Long, *ByRef buffer As Byte) *As Long


Sieht absolut richtig aus.


> Zusatzfrage:
> Ich habe leider keine 400er CPU zum testen. Hast du schon einmal 65536 Byte von einer S7-400 gelesen?


Nein, ich habe keine solche CPU. Sollte aber gehen, entweder mit daveReadManyBytes oder mit antprechend vielen Aufrufen von daveReadBytes in "Häppchen".


> Frage zum Verbindungsabbau mit "/S7ONLINE"
> - Der Verbindungsaufbau mit "ph = openS7online(acspnt)" funktioniert.
> - Beim ersten Verbindungsaufbau wird der gültige Wert 0 zurückgegeben.
> Ab nun kann im Step7 unter PG/PC-Schnittstelle nichts mehr angepasst  werden,  was auch richtig ist.


Zunächst mal kannst du unter "PC/PG-Schnittstelle einstellen" in der Systemsteuerung (nicht im Simatic-Manager) eigene Namen für einen "Zugriffsweg" definieren und diese dann statt s7online als Argument für openS7online benutzen.
Step7 und Libnodave-Anwendungen können dann unabhängig voneinander arbeiten und auch verschiedene Zugriffswege und Geräte benutzen. Protool und ähnliche Programme machen das auch so.


> Meldung "Die benutzte Schnittstelle kommuniziert gerade. Sie können den Zugriffsweg im Moment nicht ändern"


Sollte dann entweder nicht mehr auftreten oder nur wenn du versuchst, Parameter eines Gerätes (CPs, MPI-Adapters) zu ändern, daß im anderen Zugriffsweg benutzt wird.


> - Nach dem lesen sollte mit "res = daveDisconnectAdapter(di)" die Verbindung wieder abgebaut werden.
> Ich habe gelesen, das "res = closePort(ph)" bei S7Online nichts macht.
> 
> - Beim nächsten Verbindungsaufbau bekomme ich ph=1, 2, 3, 4, 5, 6, 7, Acht)
> ...


Ja, das sollte es.
Seit Version 0.8.1 sollte zum Schließen einer S7online-Verbindung die Funktion
closeS7online verwendet werden. Die VB-Deklaration fehlt, glaube ich, noch. Du kannst sie ergänzen, indem du die Deklaration von closePort kopierst und den Funktionsnamen anpaßt.


> - Wenn das Excel geschlossen und wieder geöffnet wird, funktioniert ein erneuter Verbindungsaufbau.
> - In Step7 kann die Schnittstelle wieder geändert werden, wenn das Excel geschlossen wurde.
> Als Lösung könnte ich die Verbindung nicht meht schliessen, doch in Step7 kann dann die Schnittstelle nicht mehr angepasst werden.


Mit den obigen Ratschlägen sollte ein Teil dieser Schwierigkeiten behoben sein, jedoch bin ich nicht sicher, welche genau. Ich hatte den diffusen Eindruck, daß Excel gewisse Resourcen "weiterbeansprucht", bis man es schließt, weiß jedoch nichts genaues und verstehe auch nicht, wie die S7onlinx.dll davon "wissen" könnte.
Generell sind alle anderen Protokolle besser getestet. Wenn du also S7online nicht entweder für einen CP oder für gleichzeitiges Arbeiten mit Step7 benötigst, würde ich es nicht verwenden.


----------



## Martin Glarner (30 November 2005)

Hallo Zottel
Besten Dank für die detailierte Antwort.

Habe heute noch kurz Zeit gehabt "closeS7online" zu testen. Hat super funktioniert. 

Schönen Abend


----------



## Martin Glarner (1 Dezember 2005)

Hallo,
Habe heute diverses getestet



> Frage von Martin:
> Ich habe "daveReadManyBytes" getestet. Leider funktioniert es nicht ganz ohne Problem.
> Wenn die Daten über S7Online gelesen werden, kann ich nur einmal Daten von der SPS auslesen. Beim zweiten Versuch wird der Laufzeitfehler '6' Überlauf ausgegeben. Ich nehme an, dass dies mit dem Problem Verbindungsabbau zusammenhängt. siehe unten.
> 
> ...


Ich lese die Daten eines DBs nur einmal aus der SPS, darum schliesse ich die Verbindung anschliessend wieder. Mit "closeS7online" funktioniert das schliessen nun einwandfrei, so dass in Step7 in PG/PC-Schnittstelle auch wieder geändert werden kann.



> Zusatzfrage von Martin:
> Ich habe leider keine 400er CPU zum testen. Hast du schon einmal 65536 Byte von einer S7-400 gelesen?
> 
> Antwort von Zottel:
> Nein, ich habe keine solche CPU. Sollte aber gehen, entweder mit daveReadManyBytes oder mit antprechend vielen Aufrufen von daveReadBytes in "Häppchen".


Habe aus einer S7-400 mit "daveReadManyBytes" einen DB mit der maximalen Länge von 65534 lesen können. Aus unerklärlichen Gründen lässt Step7 die Definition von 64kB (65536Byte) nicht zu.



> Frage zum Verbindungsabbau mit "/S7ONLINE"
> - Der Verbindungsaufbau mit "ph = openS7online(acspnt)" funktioniert.
> - Beim ersten Verbindungsaufbau wird der gültige Wert 0 zurückgegeben.
> Ab nun kann im Step7 unter PG/PC-Schnittstelle nichts mehr angepasst werden, was auch richtig ist.
> ...


Habe einen eigenen Zugriffweg "Excel" statt "S7Online" eingerichtet und hat funktioniert. Bei deinem Beispiel steht "/S7Online" geht aber auch ohne den "/". Was hat der "/" für eine Bedeutung?



Diese Parameter habe ich je nach Kommunikationsweg vorgegeben.
S7Online: Timeout, Zuganspunkt, MPI-Nr.
ISO over IP: Timeout, IP-Adresse, Rack-Nr., Slot-Nr.
IBH NetLink: Timeout, IP-Adresse, MPI-Nr.
MPI-Seriell: Timeout, Schnittstelle (z.B. COM1), Baudrate (z.B. 38400), Parität (z.B. O)

Die ersten drei Varianten funktionieren mitlerweile sehr gut. 



Bei MPI-Seriell, habe ich noch folgende Probleme:

Diese Deklation funktionierte nicht

```
Private Declare Function setPort Lib "libnodave.dll" (ByVal portName As String, ByVal baudrate As String, ByVal parity As Byte) As Long
```
Habe sie geändert auf

```
Private Declare Function setPort Lib "libnodave.dll" (ByRef portName As String, ByRef baudrate As String, ByRef parity As Byte) As Long
```
Ist dies korrekt?


```
port = "COM1"
    baud = "38400"
    parity = "O"
    ph = setPort(port, baud, Asc(parity))
```
Beim diesem Verbindungsaufbau erhalte ich den Fehler -1

Wozu muss die Parität angegeben werden?
Ist diese immer "O"?

Die Verbindung möche ich mit einem ACCON-MPI-Adapter von Deltalogic testen. Der Adapter funktioniert ohne Probleme mit Libnodave über "S7Online". Hat jemand diesen schon erfolgreich über "MPI-Seriell" getestet?

Besten Dank


----------



## Ralle (1 Dezember 2005)

@Martin
Hast du mal versucht mit S7Online 2 SPS-en gleichzeitig anzusprechen und Daten auszulesen. Das funktioniert bei mir leider nicht, die Verbindungen werden korrekt geöffnet, aber die Daten stammen immer aus der ersten geöffneten Verbindung, egal was in der jeweils anderen SPS drinsteht.


----------



## Martin Glarner (1 Dezember 2005)

@Ralle
Nein, ich habe bis jetzt immer nur auf eine Steuerung zugegriffen.

Ich erweitere unsere Exceldatei, mit der wir Datenbausteine deklarieren und anschliessend als Quellen nach Step7 exportieren. 
Mit Prodave lese ich die Aktualwerte aus der Steurung, damit die Anfangswerte aktualisiert werden können. 
Das gleichzeitige lesen ist daher bei mir nicht nötig.


----------



## Zottel (1 Dezember 2005)

Martin Glarner schrieb:
			
		

> Hallo,
> Ich lese die Daten eines DBs nur einmal aus der SPS, darum schliesse ich die Verbindung anschliessend wieder. Mit "closeS7online" funktioniert das schliessen nun einwandfrei, so dass in Step7 in PG/PC-Schnittstelle auch wieder geändert werden kann.


Ok. Es sind halt viele denkbare Anwendungen, bei denen man die Daten fortwährend aktualisieren möchte.


> Habe aus einer S7-400 mit "daveReadManyBytes" einen DB mit der maximalen Länge von 65534 lesen können. Aus unerklärlichen Gründen lässt Step7 die Definition von 64kB (65536Byte) nicht zu.


Wie groß ist denn die maximale Länge eines DB?


> Habe einen eigenen Zugriffweg "Excel" statt "S7Online" eingerichtet und hat funktioniert. Bei deinem Beispiel steht "/S7Online" geht aber auch ohne den "/". Was hat der "/" für eine Bedeutung?


Keine Ahnung.


> Bei MPI-Seriell, habe ich noch folgende Probleme:
> 
> Diese Deklation funktionierte nicht
> 
> ...


Die Deklaration für setport ist getestet und hat funktioniert. Obe deine geänderte Deklaration auch funktioniert, kann ich im Moment nicht testen. Der Wert -1 bei setport besagt, daß die serielle Schnittstelle nicht geöffnet werden konnte. Entweder existiert sie nicht oder eine anderes Programm beansprucht sie oder ein erstes Öffnen hat funktioniert, aber sie ist nicht geschlossen worden. In diesem Fall müßtest du zunächst Excel beenden. Möglicherweise wird auch der parity-Wert nicht richtig übergeben?
Versuche mal:
    ph = setPort(port, baud, 79)
79 ist der Wert des großen O.


> Wozu muss die Parität angegeben werden?
> Ist diese immer "O"?


Nein. Bei MPI und Teleservice-Adapter im lokalen Betrieb ist sie O, bei Teleserviceadpter über Modem und PPI-Adapter ist sie E.


> Die Verbindung möche ich mit einem ACCON-MPI-Adapter von Deltalogic testen. Der Adapter funktioniert ohne Probleme mit Libnodave über "S7Online". Hat jemand diesen schon erfolgreich über "MPI-Seriell" getestet?


Darüber habe ich keine Informationen. Du solltest auf jeden Fall Version 0.8 oder 0.8.1 verwenden, da diese toleranter mit den Antworten der Adapter umgehen.
Lies bitte auch das FAQ.
Wenn du Probleme mit dem Adapter vermutest, ist es viel einfacher, testMPI von der Kommandozeile aus zu versuchen. Ohne Optionen sowie mit den Optionen -2, -3 -4 stehen dir vier Varianten des seriellen Protokolls zwischen PC und Adapter zur Verfügung.
Der Adapter MUSS auf 38400 Baud eingestellt sein.
Nach einem Fehlversuch solltest du den Adapter kurz spannungsfrei machen.
Geht testMPI mit keiner Option, so erhälst du mit der Option -d ein ausführliches Protokoll.
Mit:
testMPI -d >ausgabe.txt
landet dieses in der Datei ausgabe.txt.
Du soltest mir dann die Ausgaben folgender Tests schicken:
testMPI -d >ausgabe.txt
testMPI -2 -d >ausgabe2.txt
testMPI -3 -d >ausgabe3.txt
testMPI -4 -d >ausgabe4.txt
Das steht alles auch im FAQ.


----------



## Martin Glarner (1 Dezember 2005)

*Max.Datenbausteingrössen*

Hallo Zottel

Besten Dank, ich werde Morgen nochmals Tests mit dem Adapter machen.



> Wie groß ist denn die maximale Länge eines DB?


S7-300 ohne MMC -> max 8kB
S7-300 mit MMC -> max.16kB
S7-300 CPU318 -> max.64kB
S7-400 -> max.64kB (minus 2Byte ev. für STRUCT und END_STRUCT am Anfang und Ende?)


----------



## Martin Glarner (2 Dezember 2005)

*Erfolgreiche Adaptertest mit*

Hallo

Konnte folgende Adapter erfolgreich testen.
- Deltalogic: Accon-MPI-Adapter USB (daveProtoMPI. Wert 0)
- Deltalogic: Acoon-MPI-Adapter RS232 (daveProtoMPI2, Wert 1)

Nochmals vielen Dank an Zottel und seeba für eure Hilfe


----------

