kann libnodave - Zeiten / Zähler (Timer / Counter) schreiben ?

powerfacer

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

ich habe libnodave schon seit längerer Zeit mit verschiedenen Sprachen (VB, C#, Delphi) ohne Probleme im Einsatz.
Ich wollte jetzt zum ersten mal einen Zähler in die SPS schreiben, hier gibt es Probleme ich bekomme die Fehlermeldung
"Write data size error".
Ich habe das ganze dann mit Prodave 6 getestet, hier hat es geklappt.

Als Test CPU verwende ich ein 417H System das ich über ISO over TCP anspreche.

Vielleicht kann mir ja jemand Helfen.
 
Habs grad mal getestet. Das Lesen von Timern und Zählern geht, aber das Schreiben funktioniert wirklich nicht, zumindest nicht mit daveWriteBytes().

Wenn man einen Timer oder Zähler lesen will, kommt als Antwort im Datenteil die Transportgröße Octet String, also 0x09 zurück. Das kann libnodave auch verarbeiten.
Beim Schreiben muss aber ebenfalls diese Transportgröße 0x09 angegeben werden (zumindest macht WinCC flex das so, und da funktioniert es), und das macht libnodave momentan (0.8.5) nicht.
Das kannst du selber aber nicht so einfach beheben, das müsste am Besten Zottel in der lib anpassen.

Man müsste in der Funktion daveAddVarToWriteRequest() eine Weiche in Abhängigkeit von "area" einbauen, und dann das Array "da" anders beschreiben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Meiner Meinung nach müssten folgende Änderungen in der nodave.c gemacht werden:
Code:
@@ -588,7 +588,15 @@
     FLUSH;
 #endif
 
-    if ((area==daveTimer) || (area==daveCounter)||(area==daveTimer200) || (area==daveCounter200)) {    
+	if ((area==daveTimer) || (area==daveCounter)) {     /* TWI: Fix for S7 timer/counters */
+	pa[3]=area;
+	pa[4]=byteCount / 0x100;
+	pa[5]=byteCount & 0xff;
+	/* with timer/counters the byteCount parameter gives the number of t/c to write.
+	 * each timer/counter value needs 2 Bytes, adjust byteCount to number of bytes for _daveAddValue() 
+	 */
+	byteCount *= 2;										
+	} else if ((area==daveTimer200) || (area==daveCounter200)) {  
 	pa[3]=area;
 	pa[4]=((byteCount+1)/2) / 0x100;
 	pa[5]=((byteCount+1)/2) & 0xff;
@@ -652,8 +660,13 @@
 	p, daveAreaName(area), DBnum, start, byteCount, buffer);
     FLUSH;	
 #endif	    	
-		
-    daveAddToWriteRequest(p, area, DBnum, 8*start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));
+	/* TWI: Fix for S7 timer/counters */
+	if (area == daveCounter || area == daveTimer) {
+		da[1] = 0x09;	/* Transport-size Octet-String */
+		daveAddToWriteRequest(p, area, DBnum,   start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));
+	} else {
+		daveAddToWriteRequest(p, area, DBnum, 8*start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));
+	}
 }
Ob man das so machen muss sei dahingestellt, an einer S7-300 funktioniert es zumindest.

Bei der Funktion daveWriteBytes wird dann im Parameter "len" die Anzahl der Timer / Counter angegeben die geschrieben werden sollen, und nicht die Anzahl der Bytes in "buffer". Man muss dafür sorgen dass der Buffer pro Timer/Counter einen 2-Byte großen Wert beinhaltet.
So scheint mir das konsistent mit den Lese-Funktionen, denn bei denen wird ebenfalls die Anzahl der Timer/Counter angegeben und nicht die Anzahl an Bytes (im Gegensatz dazu wenn andere Datenbereiche gelesen/geschrieben werden).

Es lassen sich auch mehrere Timer / Counter in einem Rutsch schreiben, z.B. T2, T3 oder C10, C11. Da wusste ich bisher garnicht dass das funktioniert.

Ob das mit den Aufrufen um Timer/Counter einer S7-200 zu lesen zusammenpasst kann ich nicht testen, das sieht mir nochmal speizell anders aus.
 
Hallo,

Danke für die schnelle Hilfe, hab die lib mal mit den vorgeschlagenen Änderungen übersetzt, und es hat funktioniert !
Es hakt allerdings noch mit dem Rückgabewert der Funktion, es kommt immer noch der Fehler "Write data size error",
obwohl der Timer, Counter in die SPS geschrieben wurde.
Hier komme ich nicht weiter, kann mir evtl. auch hierfür noch jemand einen Tipp geben ?

Danke
 
Komisch, welche Funktionen verwendest du denn um einen Zähler zu schreiben?

Mit meiner Änderung kann ich folgendermaßen Zähler Z3 auf 0 setzen:

a = 0;
res = daveWriteBytes(dc, daveCounter, 0, 3 ,1 ,&a);

Die Variable "a" sollte eine Variable mit einem 2-Byte Datentyp sein.

Mich verwundert auch dass angeblich der Zähler trotzdem geschrieben wird, obwohl es von der SPS einen Fehler zurückgibt. Das kenne ich eigentlich so, dass wenn die SPS ein Fehler zurückmeldet auch nichts geschrieben wurde.
Verwendest du libnodave als dll, oder linkst du statisch? Vielleicht ist da irgendwas nicht aktuell.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich verwende libnodave als dll,

Aufruf z.B. so

mPLCError = daveWriteBytes(dc, daveCounter, 0, 3 ,1 ,&PLCData);

ich bekomme im mPLCError den Wert 7 -> "Write Data Size error" zurück, der Zähler wird aber in der Steuerung übernommen, ich
vermute das die Funktion daveExecWriteRequest mir anhand der PLC Rückmeldung das so auswertet.

} else if (q[0]==0xFF) {
c2->error=daveResOK;
} else if (q[0]==0x07) {
c2->error=daveWriteDataSizeMismatch;
 
Ein 0x07 kommt von der SPS zurück wenn bei Timer/Zählern in da[1] kein 0x09 steht, oder andere Werte die nicht zusammenpassen. So verhält sich zumindest die S7-300 die ich hier stehen habe.

Hast du die libnodave.dll denn neu übersetzt?

Pack doch mal hinter die Zeile mit:
da[1] = 0x09;

ein printf um zu prüfen ob die Funktion überhaupt aufgerufen wird, bzw. ob dein Programm überhaupt die richtige (neue) dll verwendet.
 
Hab mal in daveWriteBytes beim Aufruf von

res=_daveTestWriteResult(&p2);

einen Screenshot von _daveDumpPDU gemacht, so wie es aussieht ist da in p->data[0] tatsächlich der wert 0x07.

PDU.gif

Das Programm verwendet meine neu übersetzte dll.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Laut deinem Screenshot versuchst du in der SPS auf zwei Datenbereiche mit einem Auftrag zu schreiben, die aber beide nicht ausgeführt werden konnten.
Bereich 1 kommt mit Fehler 0x07 (Typ inkonsistent), und Bereich 2 mit Fehler 0x0a (Bereich nicht verfügbar) aus der SPS zurück.

Zeig doch mal ein PDU Dump von den Anfragen die du schickst.

Welche libnodave Quellen verwendest du denn als Basis? Ich habe die letzte 0.8.5, und da funktioniert meine Änderung einwandfrei.
 
Hallo,

Asche über mein Haupt, ich hab in daveAddVarToWriteRequest den alten Aufruf von daveAddToWriteRequest bei der Programmänderung für die Timer/Counter nicht
versehentlich noch mit drinnen gehabt, Mann oh Mann, so ein sch... !

Jetzt klappt es perfekt, Danke für deine Spitzenmäßig gute Hilfe !!

Hier noch der Fehler:

daveAddToWriteRequest(p, area, DBnum, 8*start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));


/* TWI: Fix for S7 timer/counters */
if (area == daveCounter || area == daveTimer) {
da[1] = 0x09; /* Transport-size Octet-String */
daveAddToWriteRequest(p, area, DBnum, start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));
} else {
daveAddToWriteRequest(p, area, DBnum, 8*start, byteCount,buffer,da,sizeof(da),pa,sizeof(pa));
}
 
Zurück
Oben