# Merkerwörter mit C# und Libnodave aus SPS lesen und schreiben



## Red-Sh4nks (4 März 2010)

Hallo wieder mal.

Ich versuche schon seit geraumer Zeit einen eigenen
OPC-Server zu programmieren, welcher MW, Datenblöcke, Eingänge und Ausgänge lesen und schreiben kann.

Die SPS (S7-300 CPU 315) kann ich mit Hilfe des eingebetteten
S7online codes tadellos in Run und Stop befördern.

Beim lesen der MW und DB bin ich aber auf ein Hinderniss gestoßen!
Laut der beigelegten Doku von Libnodave unter "area" werden MW
wie folgt definiert: z.B. MW4:
daveReadBytes(dc,daveFlags,0,4,2,null)

In meinem Programm ist der Befehl "daveReadBytes" aber nicht vorhanden.
Habe die libnodave.net.dll aber eingebunden.

Es gibt aber eine ähnliche Funktion mit anderen Parametern: 
dc.readBytes(int area, int DBnumber, int Start, int len, byte[]buffer)
(dc = libnodave.daveconnection)

1. Wurde die Funktion daveReadBytes durch Readbytes ersetzt und ist die in der Doku beschriebene Funktion lediglich veraltet? (Version 0.8.1)
2. Oder muss ich die andere Libnodave.dll auch einbinden um an diese funktion zu gelangen? Wenn ja. Wie?

Ich hab mal mit dem dc.readbytes gearbeitet und folgendes programmiert:
Angenommen ich will den MW10 lesen

int MWnr = 10;
dc.readBytes(libnodave.daveFlags, 0, MWnr, 2, null); //gibt 0 zurück
int erg = dc.getU32();   
txt_ausgabe.text = erg.tostring();

Bekomme abnormale Ergebnisse raus:
bei MWnr = 50, erg = 6553610
bei MWnr = 10, erg = 84541450
bei MWnr = 100, erg = 10

werde daraus nicht wirklich schlau...

3. Könnt ihr mir  bitte helfen meinen Fehler zu finden?

Ich hoffe ihr könnt mir helfen! 

lg Marco*


----------



## Thomas_v2.1 (4 März 2010)

Red-Sh4nks schrieb:


> 1. Wurde die Funktion daveReadBytes durch Readbytes ersetzt und ist die in der Doku beschriebene Funktion lediglich veraltet? (Version 0.8.1)


Die Funktion ist die gleiche. Du hast wahrscheinlich in der Dokumentation des C-Codes nachgesehen.
Da es in C keine Klassen und Namespaces gibt, gibt man den Funktionen entsprechende eindeutige Namen. Da in C# alle Methoden zur libnodave-Klasse gehören, kann man sich den "dave"-Prefix schenken.



Red-Sh4nks schrieb:


> 2. Oder muss ich die andere Libnodave.dll auch einbinden um an diese funktion zu gelangen? Wenn ja. Wie?


S.O.
Wirf mal einen Blick in die libnodave.net.cs Datei, denn in der wird die eigentliche C-dll eingebunden. Dort kann man sehen wie die Namen der Methoden umgesetzt werden.



Red-Sh4nks schrieb:


> Ich hab mal mit dem dc.readbytes gearbeitet und folgendes programmiert:
> Angenommen ich will den MW10 lesen
> 
> int MWnr = 10;
> ...


Ein Merkerwort hat 2 Bytes. Du liest auch nur 2 Bytes aus der SPS aus. Mit getU32() liest du aber 4 Bytes aus dem Empfangspuffer. Dort stehen dann undefinierte Werte drin (oder welche aus dem letzten Telegramm). Wenn du dir die Hex-Darstellung deiner abnormalen Ergebnisse ansiehst kannst du an den Bitmustern feststellen, dass sich die 50 und die 10 auch dort finden lässt.
Ergo: Wenn du nur 2 Bytes aus der SPS liest, darfst du auch nur 2 Bytes aus dem Puffer lesen (getS16 oder getU16).


----------



## Red-Sh4nks (6 März 2010)

Herzlichen Dank für die schnelle und vor allem eminent
hilfreiche Antwort Thomas! 

Mit GetU16() bekomme ich die gewünschten Werte.
Ich bin auch in der Lage Eingänge und Ausgänge zu
lesen. Beim E und A setzen bin ich aber wieder auf 
eine Hürde gestoßen.

Angenommen ich will auf Eingang 3 "1" setzen.
Dann wende ich die Funktion dc.writeBytes an.

geforderte Parameter:
dc.writeBytes(int area, int DBnumber, int start, int len, byte[] buffer)

mit eingesetzen Parametern:
dc.writeBytes(libnodave.daveinputs,0, 3,1,null);

Jedoch wird hier kein Wert mitgegeben, was überhaupt
in den Eingang reingeschrieben werden soll (in diesem
Fall eine 1) Wo kann ich diesen Wert mitgeben, oder 
habe ich in der Parameterübergabe einen Fehler?

Mein obriger Befehl wird garnicht ausgeführt:
"Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben."

lg Marco*


----------



## Rainer Hönle (6 März 2010)

Statt null das Array aus einem Byte mitgeben, das "1" ist.


----------



## Red-Sh4nks (6 März 2010)

Der Code sieht wie folgt aus:

int eingangsnr = 0;
int zusetzenderwert = 1;
int test;
int a = 0x01

byte[] b;
b = new byte[1];
b[0] = zusetzenderwert;

test = dc.writeBytes(libnodave.daveInputs, 0, eingangsnr, 1, b)


die Variable test erhält jedesmal den Wert 0. Also wird
alles schonmal korrekt ausgeführt. Bei den Eingängen verändert
sich jedoch nichts. Hab alles mit dem Byte so gemacht wie du gesagt
hast Rainer. 

Außerdem hab ich noch die im Testprogramm angegebene
Zeile ausprobiert und statt dem byte[] b

BitConverter.GetBytes(a)

eingesetzt. Hilft leider auch nichts...

lg Marco*


----------



## Ralle (6 März 2010)

Eingänge beschreiben? Könnte eher sein, das das gar nicht geht, denn die Eingänge werden ja nach dem "beschreiben" durch den PC von der SPS aktualisiert und demzufolge mit den echten Eingangswerten versorgt.


----------



## Rainer Hönle (6 März 2010)

Eingäge beschreiben geht bei der 300er, wenn keine physikalische Hardware vorhanden ist. Ansonsten werden die gerade geschriebenen Werte beim nächsten OB 1 Durchlauf wieder durch die SPS überschrieben.


----------



## Red-Sh4nks (6 März 2010)

physikalische Hardware... Meinst du etwa die
Schalter für die einzelnen Eingänge?


----------



## Rainer Hönle (6 März 2010)

Ich meine eine beliebige Eingangskarte auf dieser Adresse


----------



## Red-Sh4nks (6 März 2010)

Bin leider kein Profi auf dem Gebiet und kann mit
deiner Antwort wenig anfangen. Ich werde mich mal
mit meinem Professor am Dienstag unterhalten und
in Erfahrung bringen was eine Eingangskarte ist und
wie ich eine solche deaktiviere...

lg Marco*


----------



## Rainer Hönle (6 März 2010)

Die kannst Du nicht deaktivieren (außer durch Ausbau ;-)). Du kannst dann nur andere Adressen im Funktionsaufruf verwenden.
Wie sieht denn Deine Hardwarekonfig aus? Welche Karten hast Du denn verbaut?


----------



## Red-Sh4nks (6 März 2010)

Hat etwas gedauert deine Frage zu beantworten ^^
Ich hoffe meine Angaben sind hilfreich:

Meine Schnittstelle ist eine CP5611 und ist 
mit einer CPU 315 2DB verbunden.

Sreenshot zu HW Konfig:
http://www.imagebanana.com/view/knomj0cw/hwconf.bmp.png

Tut mir leid für diese wl nicht richtige Antwort auf
deine Frage, aber ich bin nur Programmierer bei diesem
Projekt. Ich werde aber spätestens am Dienstag eine
genaue Antwort auf deine hier posten ;-)

Falls jemand Interesse an diesem OPC-Server hat, ich
werde ihn, sobald ich ihn fertiggestellt habe hier zum Download
zur Verfügung stellen.

PS:Screenshots kann ich jederzeit auf Anfrage liefern ^^

lg Marco*


----------



## Rainer Hönle (6 März 2010)

Wie Du siehst, ist auf E0..3 eine Eingangsbaugruppe parametriert. Daraus folgt messerscharf, dass diese Eingangsbytes immer von der SPS überschrieben werden. Teste das Ganze doch mal mit EB 4 ;-).


----------



## Red-Sh4nks (8 März 2010)

Mit EB4-EBn funktioniert auch nichts...
habe jeden einzelnen durchgetestet.

Ich hab vermutlich nen kleinen Fehler im
Programm. Daher hier ein Screenshot
welcher die Funktion Eingänge setzen
und das Programm (bis jetzt) zeigt.

Screenshot:
http://www.imagebanana.com/view/57qhcaaw/Eingngesetzen.bmp.png

Die letzte Meldung "Der Vorgang wurde ausgeführt"
ist nicht zu beachten, da das ganze noch etwas schwammig
programmiert ist, denn der Vorgang zeigte kein erkenntliches
Ergebnis...

Beim Lesen der Datenblöcke bin ich auch auf
einen merkwürdigen Fehler gestoßen:

int dc.ReadBytes(libnodave.daveDB, 5,0,4,null)
gibt bei mir immer den Wert 10 zurück. Dabei sollte
sie aber 0 zurückgeben.

Hab schon alles ausprobiert:
anstatt 5: jede beliebige Zahl von 0-50
anstatt 0: jede beliebige Zahl von 0-50
anstatt der Länge 4 auch mal 2
und anstatt null ein Bytearray

Bekomme jedoch immer 10 zurück. 10 deutet
laut der Libnodave Doku auf einen Fehler
der SPS hin...

Wisst ihr wo mein Fehler liegt?

lg Marco*


----------



## Red-Sh4nks (4 Juni 2010)

*Auflösung*

Ärgerlicher Fehler...

Die Rückgabewerte von den Funktionen deuten ja auf bestimmte Fehler oder korrekte Ausführung hin.

0... ausgeführt
10... Datenblock existiert wahrscheinlich nicht...

Ich habe jede DB-Nr ausprobiert und dann feststellen müssen, das
alle Datenblöcke, die sich auf der SPS befanden, gelöscht wurden, bevor
ich diese SPS zum programmieren erhielt, um meine Arbeiten nicht zu behindern *ROFL*

Lösung:
Eine Datenblocknr als Parameter mitgeben, bei der der Datenblock auch wirklich existiert. Die maximale Länge sollte dabei nicht überschritten werden, da sonst alle Ergebnisse 0 sind und der Rückgabewert der Funktion 5 ist --> außerhalb des Lesebereichs ;-)


----------

