TIA Funktion SCL indirekter Aufruf

pramkies

Level-2
Beiträge
57
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo SPS-Gemeinde,

Ich habe eine Herausforderung die ich nicht so optimal lösen kann. Seit langen bin ich schon dabei für unsere Firma einen TIA-Framework für unsere Prozesse zu entwickel. Wir Automatisieren hauptsächlich Prozess Anlagen in der Milchindustrie.

Zu dem Framework gehören Programme/Units, zu den Units einige Funktionen. Ein Part sind die Parameter-DB der Units ( Eingabe Sollwerte über der VISU/WinCC).

Von Unit zu Unit habe ich unterschiedliche Parameteranzahl (optimierter BA). Aber die Schnittelle zu der Visu möchte ich einen Standard Funktion habe. Es soll mit Request-bits gearbeitet werden. Über eine Maske sollen nur 20. Parameter immer angezeigt werden. Das passt auch alles.

Problem:

1: HMI-Schnittelle DB, Adressen bzw. keine optimierter BA.

Paramter Typ = 32 Bit Auswertung / TRUE = REAL , FALSE = DINT > Bit 0 = TRUE > Parameter 1 as REAL
Parameter Set = 1 > Datensätzen von Parameter 1 bis 20 rangieren/ anzeigen, 2 > von Parameter 21 bis 40 rangieren/ anzeigen

2: PLC-Parameter DB, keine Adressen bzw. optimierter BA. von Unit zu Unit unterschiedlich


Parameter.jpg

nun möchte ich einen Standard SCL Funktion schreiben, die von der HMI-DB die 20-Array- Werte in den richtigen Prameter- DB zu transferieren.
Mein Parameter-DB hat unterschiedliche "Datensätze" (REAl/DINT), aber die Größe ist immer identisch > 4 Byte.
Die SCL-Funktion übergebe ich den Paramter-DB als IN/OUT als VARIANT Datentyp. Jetzt weis ich nicht mehr weiter.

Hat einer einer Idee ? Ich hoffe ich konnte mein Problem einigermaßen verständlich beschreiben. Würde mich für Anmerkungen und Kommentare freuen.
 
Moin pramkies,

Du benutzt nicht optimierte Datenbausteine. Da ist m.E. eine Datensatzübergabe mit "klassischer" Adressberechnung (Any-Pointer) der richtige Weg.
Ich denke mal, dass die Datenbausteine aus der klassischen Welt migriert wurden? Oder ist die Vorgabe, dass nicht optimierte DBs verwendet werden?

Also ich denke mal, dass dein Array[1..20] of DWORD einfach nur einen Speicherbereich zur Verfügung stellt, unabhängig vom Inhalt (Also Datentypinterpretation)?
Das Kopieren von einem Datentyp in einen anderen Datentyp ist nicht einfach per Zuweisung oder so möglich.

Wenn auf die klassische Adressberechnung verzichtet werden soll (allerdings warum, wenn man eh nicht optimierte DBs hat?), dann geht das meines Wissens nur mit den Bausteinen Serialize und Deserialize. Mit Serialize wird ein Datenfeld in ein Array[0..n] of byte übertragen (wobei das Array groß genug gewählt werden muss, um das Feld aufzunehmen). Mit Deserialize wird ein Array[0..n] of Byte in einen beliebigen Datenbereich übertragen.

Ich nutze die beiden Funktionen in Kombination, um einen Datentyp in einen anderen Datentyp zu kopieren. Also z.B. um ein "Rohtelegramm" in ein spezifiertes Telegramm (Auftrag, Status, etc.) zu übertragen.

VG

MFreiberger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi MFreiberger,

Danke für deine Antwort. Ja in dem Bild ist der Parameter_DB nicht optimiert, war fürs testen.
Ich möchte das mit optimierten DB hinbekommen. Das Framework soll aus Performance gründen nur optimierte DB haben.
Nur die Schnittstelle nach außen ( nicht TIA WELT/ Symbolischer zugriff), soll Adressen haben.

Ich werde mich dann schlau machen mit
Deserialize & Serialize Funktion. Danke
 
Meinst du sowas wie hier?
Code:
FUNCTION_BLOCK "array test"{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_IN_OUT 
      parameter : Variant;
      intarray : Array[0..100] of Int;
      realarray : Array[0..100] of Real;
      dintarray : Array[0..100] of DInt;
   END_VAR


   VAR 
      status : Int;
   END_VAR




BEGIN
	
	
	IF TypeOfElements(#parameter) = TypeOf(#intarray[0]) THEN // wenn parameter vom typ des zielarrays ist dann koppiere die ersten 3 elemente
	    #status := MOVE_BLK_VARIANT(SRC := #parameter, COUNT := 3, SRC_INDEX := 0, DEST_INDEX := 0, DEST => #intarray);
	    
	ELSIF TypeOfElements(#parameter) = TypeOf(#realarray[0]) THEN 
	    #status := MOVE_BLK_VARIANT(SRC := #parameter, COUNT := 3, SRC_INDEX := 0, DEST_INDEX := 0, DEST => #realarray);
	    
	ELSIF TypeOfElements(#parameter) = TypeOf(#dintarray[0]) THEN
	    #status := MOVE_BLK_VARIANT(SRC := #parameter, COUNT := 3, SRC_INDEX := 0, DEST_INDEX := 0, DEST => #dintarray);
	END_IF;
	    
	    
END_FUNCTION_BLOCK
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Parameter.jpg

Hi Vollmi,

mein Parameter DB ist kein Array sondern eine Struct (Udt). Ich möchte einfach in beiden Richtungen die Werte hin und her kopieren.
Als Trigger > Parameter Set (DINT) bei Änderung:

Wenn sich der Trigger ändert ( Beispiel 0>1), dann einmalig die ersten 20 ( Trigger x20) Elements von Parameter DB in HMI-DB kopieren. Danach wieder nur in eine Richtung kopieren von HMI-DB in Parameter DB.

Mit der Funktion möchte ich eine Standard Struktur haben, egal wie groß der Parameter DB ist. Und auch an WinCC Variabel sparen.

Mit Deserialize & Serialize klappt das nicht, bzw. ich bekomme das nicht hin. In der Hilfe habe ich gelesen das der Array als Byte deklariert sein muss.
 
Moin pramkies,

ja, das Array muss ein Array[0..n] of Byte sein.
Ich habe das so gemacht:

COPY.PNG
An 'source' kommt bei mir häufig ein PLC Datentyp und an 'target' auch.

Das Array[0..n] of Byte verwende ich nur, um die Daten von Serialize zu Deserialize zu übertragen.

VG

MFreiberger


Vielleicht kann der Variant ja auch ein Pointer aufnehmen? Aber dann muss die Adresse des Pointers wieder berechnet werden. Dann geht es auch mit klassischer Adressberechnung und einer Schleife.

Für mich zum Verständnis: Kannst Du einmal sagen, warum Die Daten in unterschiedliche Bereiche des Ziel-DBs geschrieben werden sollen, wobei die Datentypen im Ziel-DB immer unterschiedlich sind? Wie werden die Daten weiter verarbeitet? Woher kommen sie? Vielleicht könnte man für die Zieldaten unterschiedliche Datentypen zusammenbauen, die immer 20x4Byte => 80Byte groß sind? Dann kannst Du Serialize/deserialize sinnvoll einsetzen.
 
Zuletzt bearbeitet:
mein Parameter DB ist kein Array sondern eine Struct (Udt). Ich möchte einfach in beiden Richtungen die Werte hin und her kopieren.
Als Trigger > Parameter Set (DINT) bei Änderung:

Ja aber die Parameter sind als array abgelegt. Darum meinte ich mit TypeOfElements den Elementtyp des arrays erfragen und entsprechend dann die kopie ausführen.
Wenn du das Value_SP an deinen Baustein an einen Variant Input hängst.

Mit der Funktion möchte ich eine Standard Struktur haben, egal wie groß der Parameter DB ist. Und auch an WinCC Variabel sparen.

Mit Deserialize & Serialize klappt das nicht, bzw. ich bekomme das nicht hin. In der Hilfe habe ich gelesen das der Array als Byte deklariert sein muss.

Achso das. Das habe ich bis jetzt auch nur mit einem Zwischenschritt hingekriegt.
das heisst das wordarray in ein temporäres bytearray kopieren (FOR Schleife) und dann deserialisieren.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
HI Volmi,

ich bin in dem Punkt nicht so weit gekommen. Musste mir jetzt eine andere Lösung ausdenken. Die IBN ist auch schon durch.
TrotzdemDPA__3.jpg brauche ich eine bessere Lösung.

Wenn beide DB's als Array angelegt ist funktioniert es einwandfrei:
SPA_05_12_2019.jpg
DB Links nicht Optimiert ! DB rechts Optimiert !

Trigger PageNr > Bei Änderung ein Zyklus von DB rechts nach links Kopieren ! Dann wieder die ganze Zeit von Links nach Rechts Kopieren:


SPA_05_12_2019_Skript.jpg

Soweit alles Gut nun möchte das mit meinen DINT-Paramter genauso umgehen!


DPA_05_12_2019.jpg


Mit Serialze bekomme ich es umkopiert auf ein Array von Bytes, aber zurück Funktioniert es nicht !

DPA__2.jpg DPA__3.jpg

// Statement section REGION
// TypeOf
#iResult := Serialize(SRC_VARIABLE := #DPA,
DEST_ARRAY => "Array_Byte"."Byte",
POS := #Pos);

#iResult := Deserialize(SRC_ARRAY := "Array_Byte"."Byte",
DEST_VARIABLE => "C1U1_DPA_Tank BP1_1".DPA,
POS := #Pos);
 
Vor den Aufruf von serialize/deserialize muss #Pos initialisiert werden.

Code:
[COLOR=#333333]#Pos := 0;[/COLOR]
[COLOR=#333333]#iResult := Serialize(SRC_VARIABLE := #DPA, [/COLOR]
[COLOR=#333333]DEST_ARRAY => "Array_Byte"."Byte",[/COLOR]
[COLOR=#333333]POS := #Pos);[/COLOR]

[COLOR=#333333]#Pos := 0;[/COLOR]
[COLOR=#333333]#iResult := Deserialize(SRC_ARRAY := "Array_Byte"."Byte",[/COLOR]
[COLOR=#333333]DEST_VARIABLE => "C1U1_DPA_Tank BP1_1".DPA,[/COLOR]
[COLOR=#333333]POS := #Pos);[/COLOR]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wieso soll die Schnittstelle zur VISU denn nicht optimiert sein wenn WinCC zum Einsatz kommt? Du verwendest doch Datentypen in der SPS dann kannst dich auch gleich in der HMI benutzen das erleichtert das Anbinden ungemein, vor allem kann das ganze kopieren entfallen. Sollte es nur darum gehen Variablen sparen zu wollen kannst du pro Koppel DB ein Element von deinem Datentyp anlegen plus ein Array dieses Datentypes. In dem Array stehen die Parameter aller deiner Objekte, in dem einzelnen Element werden dann immer nur die Daten reinkopiert auf die die HMI zugreifen will.
 
Moin miasma,

vielleicht wird die VISU separat (d.h. in einem eigenen Projekt) programmiert und dann geht es nicht direkt, sondern nur über den (durchaus gangbaren) Weg mit einem Proxy-Device zu arbeiten. Oder man verwendet halt nicht optimierte Daten(-bausteine), um auf die Adressen zugreifen zu können.

VG

MFreiberger
 
HI,

wir Sind immer Separat Unterwegs. TIA 15.1 mit WInCC 7.4. Daher habe ich alle DB als optimierten Zugriff, nur die HMI-Schnittelle nicht.
Desweiteren ist es auch mit TP1500 wieder mit kompatibel. Die Struktur soll so flexibel wie möglich sein. Beispiel Erweiterungen in vorhanden Kunden WInCC-Projekte.

Funktioniert nun einwandfrei. ES lebe SPS-Forum.
 
Zurück
Oben