TIA Variabelgröße SizeOf/Variant

Zuviel Werbung?
-> Hier kostenlos registrieren
Ok, lassen wir mal den blöden Baustein doch mal weg. !!!

Nochmal, ich arbeite nur symbolisch. Ich brauche auch keine Adressen, so arbeite ich nicht.

Aus dem #Post13 das versuche ich gerade, das möchte aber nicht so ganz wie ich das möchte.
Ich versuche zu Serialisieren

Code:
"tempDB".dwDebugWord := Serialize(SRC_VARIABLE := #varIn_Variant, DEST_ARRAY => "tempDB".tempArDEbug, POS := #tempCount2);
#tempCount := CountOfElements("tempDB".tempArDEbug);

Der Compiler sagt das es eine ungültige Zuweisung wäre. Warum?

Gruß
 
Ich vermute CountOfElemtents möchte einen Variant als Parameter bekommen.
Aber eigentlich brauchst du das nicht - in POS vom Serialize sollte schon deine gesuchte Größe stehen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Als Variant kann man jede Variabel anhängen, Variant wird indirekt als Referenz intern verwendet und Ausgänge müssen beschalten sein, heißt es wird ein Ausdruck erwartet.
Daher weiß ich gerade nicht was das Problem ist.
 
Ich würde gerne zu dem Ziel kommen sowas wie das SizeOf umsetzen zu wollen.
Beispiel:
Du hast einen PLC-Datentyp oder einen Struct, der aus 1 INT + 1 BOOL + 1 WORD + 15 BOOL besteht.
In Speicher mit Standard-Zugriff belegt dieser Datentyp/Struct 8 Bytes. In der S7-1500 in Speicher mit optimiertem Zugriff belegt dieser Datentyp (vermutlich) 20 Byte, die müssen nicht zusammenhängend und auch nicht in der deklarierten Reihenfolge liegen (deshalb geht da kein "AT"), und wenn da ein Array ist, dann müssen die Array-Elemente auch nicht lückenlos hintereinanderweg liegen. Welchen Wert sollte eine SizeOf-Funktion da liefern?

Nun könnte man mit IF/CASE/... und TypeOf und festen Zahlen eine SizeOf-Funktion für bekannte Datentypen realisieren - doch wofür? Man kann damit in "optimiertem" Speicher eh' nichts anfangen. SizeOf braucht man doch nur für Adressarithmetik, die aber in optimiertem Speicher nicht funktioniert. In optimiertem Speicher kann nur symbolisch adressiert werden und indirekte Zugriffe sind nur in Form indizierter Zugriffe in Arrays möglich. SizeOf wird nicht benötigt.
Schnittstellen "nach außen" gehen nur mit elementaren Datentypen oder über Speicher mit Standard-Zugriff. Bei Speicher mit Standard-Zugriff kann man SizeOf durch zerlegen von ANY-Pointern berechnen.

Harald
 
Hi,

also wofür man das braucht möchte ich nicht diskutieren. Dafür kenne ich genügend Ansätze wo man sowas grundlegend und der einfach halber benötigt.

Wenn der Compiler nicht weiß wo seine Variabel im Speicher liegen dann muss ich mir ganz arge Sorgen machen.
Und die Daten liegen auch hintereinander ansonsten würde ein Wahnsinns Chaos im Speichermanagament System vorhanden sein, was eh schon bei Siemens für den Anwender
völlig krank ist. Ich sage nur String Verarbeitung !!! Aber gut anderes Thema ...

Und was die Größe von einem UDT angeht ist folgendes zu sagen, das hier nicht nur 20 Byte sind sondern eher man darauf noch achten muss was auf einem Bool
für eine Variabel folgt. Ich weiß nicht ab welcher CPU Reihe das ist aber grundlegend wird versucht immer Word orientiert den Speicher zu belegen.
Heißt man sollte grundlegend immer mit den höher wertigen Datentypen in einem UDT anlegen.

Die Funktion Serialisieren macht aber genau das was fast zu meinem Ziel führt. Aber meine nächste Frage kommt später wenn wir mal hier durch sind ... :)

Nimm einfach einen UDT und über gib ihn als Quelle und das Ziel soll ein Array sein, fast egal wo es liegt, nimm einfach einen globalen DB.
Lass dein Programm zyklisch mit dem Serialisieren einfach laufen und beschreibe deinen UDT und du wirst sehen das in deinem DB wo das Array liegt
genau an die richtig Stelle die Daten geschrieben werden.

Ich könnte noch ein paar Schlagworte in den Raum werfen aber dann weichen wir wieder vom Thema ab.

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der Compiler sagt das es eine ungültige Zuweisung wäre. Warum?
Das könnte man sagen wenn du auch die Variablendeklaration zeigst.

Explizites Beispiel:
Code:
FUNCTION_BLOCK "SerializeTest"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR 
      dataStruct { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Struct
         Var1_Int { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int := 123;
         Var2_Real { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real := 45.6;
         Var3_Bool { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool := True;
         Var4_Byte { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Byte := 16#AA;
         Var5_Bool { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool := True;
         Var6_Bool { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool := False;
         Var7_DWord { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DWord := 16#deadbeef;
         Var8_DInt { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt := 2147483647;
      END_STRUCT;
      dataArray { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Array[0..127] of Byte;
      ser_RetVal { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      ser_Pos { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt;
      Pos_bevor : DInt;
      Pos_nach : DInt;
      Anzahl_Bytes : DInt;
   END_VAR


BEGIN
	// Index ab der die Strukturdaten in das Array geschrieben werden
	#Pos_bevor := 0;
	
	#ser_Pos := #Pos_bevor;
	#ser_RetVal := Serialize(SRC_VARIABLE := #dataStruct,
	                         DEST_ARRAY => #dataArray,
	                         POS := #ser_Pos);
	#Pos_nach := #ser_Pos;
	
	IF #ser_RetVal = 0 THEN
	    #Anzahl_Bytes := #Pos_nach - #Pos_bevor;
	ELSE
	    #Anzahl_Bytes := 0;
	END_IF;
	    
	    
END_FUNCTION_BLOCK

Bei "optimierten" Daten musst du beachten, dass 1 Bool hier 1 Byte groß ist. Die Struktur aus dem Beispiel oben besitzt somit insgesamt 18 Bytes.

Ich könnte mich auch jedes mal über diesen "optimierten" Unfug aufregen, im Jahr 2018 ist Speicherplatz ja so extrem teuer, dass man sich diesen alles verkomplizierenden Unfug antun musste.
 
Code:
#tempCount := CountOfElements("tempDB".tempArDEbug);

Der Compiler sagt das es eine ungültige Zuweisung wäre. Warum?
Zumindest bis TIA V13 darf der Operand von CountOfElements nicht in einem DB liegen. Kann man einfach nachlesen, indem man den Cursor in die Anweisung setzt und F1 drückt.
Davon abgesehen liefert CountOfElements nicht die Anzahl Bytes die in das Array geschrieben wurden, sondern die deklarierte Gesamtanzahl Elemente des Arrays. Kann man auch in der Hilfe zur Anweisung nachlesen.


Wenn der Compiler nicht weiß wo seine Variabel im Speicher liegen dann muss ich mir ganz arge Sorgen machen.
Und die Daten liegen auch hintereinander ansonsten würde ein Wahnsinns Chaos im Speichermanagament System vorhanden sein, was eh schon bei Siemens für den Anwender
völlig krank ist. Ich sage nur String Verarbeitung !!! Aber gut anderes Thema ...

Und was die Größe von einem UDT angeht ist folgendes zu sagen, das hier nicht nur 20 Byte sind sondern eher man darauf noch achten muss was auf einem Bool
für eine Variabel folgt. Ich weiß nicht ab welcher CPU Reihe das ist aber grundlegend wird versucht immer Word orientiert den Speicher zu belegen.
Heißt man sollte grundlegend immer mit den höher wertigen Datentypen in einem UDT anlegen.
Hast Du Dich schon mal mit dem Thema "Speicher mit optimiertem Zugriff" und Speicherreserve befasst? Dann würdest Du vielleicht nicht so einen halbgaren Unsinn schreiben sondern wissen, daß Variablen im "optimierten" Speicher unabhängig von der Reihenfolge der Deklaration an einer Position und Reihenfolge abgelegt werden, die der Compiler für optimal hält. siehe z.B. den Programmierleitfaden Kapitel 2.6.2

Der Compiler weiß schon wo seine Variablen liegen, er verrät das nur nicht. Wie gesagt - die Programmierer stellen mit solchen Informationen eh' nur untaugliche Sachen an. ;) z.B. denken SCL-Programmierer, daß das Element ByteArray[7] direkt auf dem nächsten Byte hinter dem Element ByteArray[6] liegt - was in "optimiertem" Speicher aber mitnichten so sein muß.


Nimm einfach einen UDT und über gib ihn als Quelle und das Ziel soll ein Array sein, fast egal wo es liegt, nimm einfach einen globalen DB.
Lass dein Programm zyklisch mit dem Serialisieren einfach laufen und beschreibe deinen UDT und du wirst sehen das in deinem DB wo das Array liegt
genau an die richtig Stelle die Daten geschrieben werden.
Das Serialisieren schreibt in Speicher mit Standard-Zugriff. Das kann man nicht mit "optimiertem" Speicher vergleichen. Im übrigen ist das serialisieren ein äußerst ineffizienter Zykluszeitfresser und das serialisieren von Strukturen aus optimiertem Speicher ist auch nicht ganz trivial, deshalb gab es in der Serialize-Anweisung schon öfter Bugs.

Harald
 
.. Bei "optimierten" Daten musst du beachten, dass 1 Bool hier 1 Byte groß ist. Die Struktur aus dem Beispiel oben besitzt somit insgesamt 18 Bytes. ..
Ich probiere gerade ein bisschen mit. Ich hoffe, ich bringe nicht zu viel Unruhe in die Diskussion. Ich programmiere bis heute eigentlich immer noch konsequent nicht optimiert. Was die optimierte Datenablage angeht, so weiß ich dass es Unterschiede gibt, auch davon abhängig, ob S7-1200 oder S7-1500. Jetzt habe ich mal das Beispiel von Thomas, so wie ein Beispiel mit einem eigenen UDT (180Byte, gemischte Datentypen auch mit boolschen Variablen), sowohl optimiert als auch nicht optimiert, auf einer S7-1500 simuliert. Die Datenlänge "POS", liefert mir immer 18 Bytes, bzw. mit meinem UDT 180 Bytes zurück?

Ich bin jetzt mittelmäßig überrascht. Die Datenlänge scheint in beiden Fällen (optimiert/nichtoptimiert) jeweils das selbe Ergebnis zu liefern? Wie ist das jetzt zu verstehen?


@mactoolz,
Was fehlt dir noch zum Glück ;) ?



Ah, ich glaube, Harald hat meine Frage schon beantwortet, danke.
Das Serialisieren schreibt in Speicher mit Standard-Zugriff. ..



 
Zuletzt bearbeitet:
Zumindest bis TIA V13 darf der Operand von CountOfElements nicht in einem DB liegen. Kann man einfach nachlesen, indem man den Cursor in die Anweisung setzt und F1 drückt.
Davon abgesehen liefert CountOfElements nicht die Anzahl Bytes die in das Array geschrieben wurden, sondern die deklarierte Gesamtanzahl Elemente des Arrays. Kann man auch in der Hilfe zur Anweisung nachlesen.

ok, also im TIA V15 kann ich dem nichts entnehmen oder sehe es nicht, das einzige was dort steht ist das eine genauere Fehlerauswertung eher ReadFromArrayDb genommen werden soll, kann aber jetzt gerade nicht deuten was die damit meinen ...
Und niemand hat gesagt das eigentlich CountOfElements mir die Speichergröße ausgibt, wobei sie das indirekt macht indem ich vorher serialisiert habe ...
weil letzten Endes steht nach dem Serialize jedes einzelne Byte schön aneinander gereiht da drin ...

Hast Du Dich schon mal mit dem Thema "Speicher mit optimiertem Zugriff" und Speicherreserve befasst? Dann würdest Du vielleicht nicht so einen halbgaren Unsinn schreiben sondern wissen, daß Variablen im "optimierten" Speicher unabhängig von der Reihenfolge der Deklaration an einer Position und Reihenfolge abgelegt werden, die der Compiler für optimal hält. siehe z.B. den Programmierleitfaden Kapitel 2.6.2

Der Compiler weiß schon wo seine Variablen liegen, er verrät das nur nicht. Wie gesagt - die Programmierer stellen mit solchen Informationen eh' nur untaugliche Sachen an. ;) z.B. denken SCL-Programmierer, daß das Element ByteArray[7] direkt auf dem nächsten Byte hinter dem Element ByteArray[6] liegt - was in "optimiertem" Speicher aber mitnichten so sein muß.

falls es dich doch genauer interessiert, solltest du nochmal genau hinschauen. Hier geht es darum das ein bit ein bit ist oder ein bool auch ein byte sein kann obwohl eigentlich ein bool rein theoretisch bei der Programmierung nur ein bit wäre. Aber im Speicher wird es tatsächlich als Bit abgelegt in einem Byte oder eher je nachdem werden füll bytes verwendet und das man sogar auf ein word kommt bzw immer gerade heraus kommt, anonsten liegt ALLES hintereinander nur aufgefüllt oder nicht
. Egal wie man es beschreibt, das Bild auf 2.6.2 sagt alles.
Oder du möchtest mir doch jetzt nicht sagen das wir hier es mit defragmentierten Speicher zu tun haben ... ????

Dann würdest Du vielleicht nicht so einen halbgaren Unsinn schreiben sondern wissen

sowas lassen wir bitte, egal ob ungar, halb gar oder gar nicht gar ... ist einfach nicht cool sowas ...

Das Serialisieren schreibt in Speicher mit Standard-Zugriff. Das kann man nicht mit "optimiertem" Speicher vergleichen. Im übrigen ist das serialisieren ein äußerst ineffizienter Zykluszeitfresser und das serialisieren von Strukturen aus optimiertem Speicher ist auch nicht ganz trivial, deshalb gab es in der Serialize-Anweisung schon öfter Bugs.
Harald

Das ist ein Auszug von der Hilfe ...

Optimierter Speicherbereich
Um größere Strukturen zu deserialisieren, können Sie ab der Firmware Version >= 4.2 bei
einer CPU der Baureihe S7-1200 und ab der Firmware Version >= 2.0 bei einer CPU der
Baureihe S7-1500 den Speicherbereich für die sequenzielle Darstellung auch mit optimiertem
Zugriff deklarieren. Der Inhalt der sequenziellen Darstellung bleibt dabei unverändert, wie bei einem standard Speicherbereich. Der Zugriff auf die Bytes des ARRAYs ist ausschließlich symbolisch möglich.

Gruß
 
Serialize kannste auch in die Tonne treten ... wenn String Datentypen dabei sind, dann kommen noch die beiden Bytes dazu (länge/tatsächliche länge) ...
was für ein Müll das, wirklich .... und es macht im V15 keinen Unterschied ob optimiert nicht optimiert ...

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Serialize kannste auch in die Tonne treten ... wenn String Datentypen dabei sind, dann kommen noch die beiden Bytes dazu (länge/tatsächliche länge) ...
Du willst also eine Struktur serialisieren, z.B. mit Aufbau int, string, int, string, int bei dem das Array nur die wirklichen einzelnen Zeichen des Strings besitzt? Und wie willst du in dem Array erkennen wo der String beginnt und wo er endet?

Wenn dir die Funktion nicht gefällt, dann "serialisiere" doch selber, das ist in vielen anderen Programmiersprachen die übliche Vorgehensweise um Netzwerktelegramme zusammenzubauen.
 
Code:
#tempCount := CountOfElements("tempDB".tempArDEbug);

Der Compiler sagt das es eine ungültige Zuweisung wäre. Warum?
Ich vermute CountOfElemtents möchte einen Variant als Parameter bekommen.
Als Variant kann man jede Variabel anhängen, Variant wird indirekt als Referenz intern verwendet und Ausgänge müssen beschalten sein, heißt es wird ein Ausdruck erwartet.
Daher weiß ich gerade nicht was das Problem ist.
Variant als Übergabeparameter heißt nicht unbedingt, daß man da jede Variable anschalten kann. Wenn wir TIA-Anwender einen Baustein programmieren und als Input-Parameter Variant deklarieren, dann kann der Parameter beim Baustein-Aufruf mit beliebigen Variablen beschaltet werden. Siemens kann Anweisungen programmieren, die an Variant-Parametern nur Variant akzeptieren.

Es ist tatsächlich so wie Howard schon vermutet hat: CountOfElements akzeptiert als Operand nur einen Variant, das heißt man kann das zu testende Array gar nicht direkt an CountOfElements übergeben sondern muß es vorher einem Variant zuweisen (Warum will Siemens das so??), z.B. bei einem Bausteinaufruf an einen Variant-Übergabeparameter anschalten und in dem Baustein kann dann der Übergabeparameter an CountOfElements durchgereicht/angeschaltet werden.

Die TIA-Hilfe zu CountOfElements ist in TIA V13 im Detail falsch (was die übergebbaren Variablen betrifft, angeblich E A M L), in V15.1 ist die Hilfe überarbeitet aber immer noch nicht ganz eindeutig.

Harald
 
Zurück
Oben