# UDT in FB durchreichen



## thomasgull (26 Februar 2010)

Hallo ich habe eine Frage:

Ich habe einen UDT ( UDT3) der noch einen UDT ( UDT 4) enthält.

Nun die Frage, ich brauche den ganzen UDT (UDT 3) im FB ( FB 5) und im FC ( FC 6 ) der in dem FB ( FB 5 ) aufgerufen wird nur den UDT im UDT ( UDT 4 ).

Nun kann ich im FB ( FB 5 ) den UDT ( UDT 4) durchreichen?


Thomas


----------



## Thomas_v2.1 (26 Februar 2010)

Auf deinem Screenshot kann man leider nicht viel erkennen.
Jedoch gibt es eine Beschränkung wenn der UDT im IN_OUT Bereich liegt, da in den Fall auf den UDT nur ein Zeiger übergeben wird.

Wenn du den UDT im IN-Bereich des FB einträgst sollte es mit dem Durchreichen gehen. Verhindert jedoch schreibenden Zugriff auf die Daten. Das Problem lässt sich aber auch noch umschiffen ;-)


----------



## thomasgull (26 Februar 2010)

Bild verbessert.

Er liegt im IN/Out Bereich da ich sowohl lesen wie schreiben sollte.

Thomas


----------



## Thomas_v2.1 (26 Februar 2010)

Und in deinem Baustein "Modulaufruf" liegt der UDT auch in IN_OUT-Bereich?


----------



## thomasgull (26 Februar 2010)

ja genau.
Wird gelesen und geschrieben

Thomas


----------



## Thomas_v2.1 (26 Februar 2010)

Also mit einfachen Mitteln ist das so nicht zu lösen, zumindest nicht wenn man vollständig symbolisch programmieren möchte.
Mit ein bißchen Pointer- und Adressregisterfrickelei bekommt man das sicher hin, so auf die schnelle fällt mir jedoch nichts elegantes ein.

Abhängig von der Größe der Struktur würde ich evtl. die UDT einmal im IN und dann noch im OUT Bereich anlegen, und dann entsprechend kopieren.

Oder:
Die UDT4 im Stat-Bereich des aufrufenden FB anlegen, dort die Daten vor dem Aufruf mit L #xx T #yy hineinkopieren, und dann den FB #Modulaufruf mit diesen Daten beschalten, und nach aufruf wieder zurückkopieren.
Ich hoffe das war halbwegs verständlich ;-)


----------



## thomasgull (26 Februar 2010)

Mommentan denke ich an Variante 2


----------



## Thomas_v2.1 (26 Februar 2010)

Im Anhang mal ein Screenshot wie ich das meinte. Je nach Größe der Struktur hält sich der Aufwand dann noch in Grenzen.


----------



## thomasgull (26 Februar 2010)

So müsste auch gehen?


----------



## Thomas_v2.1 (26 Februar 2010)

thomasgull schrieb:


> So müsste auch gehen?



Vom Prinzip schon. tUDT liegt im Temp-Bereich? Ansonsten musst du noch den AR2-Offset bei Multiinstanzen beachten.

Funktioniert natürlich nur solange keiner auf die Idee kommt deine "Sub-UDT" in der übergeordneten UDT an anderer Stelle als am Anfang zu positionieren.
Und an den Offset der Sub-UDT kommst du ohne Hardcodierung bei einem IN_OUT Parameter nicht heran.


----------



## Markus (26 Februar 2010)

also...

1. das fummeln am AR2 ist in FBs recht gefährlich, du musst es nach verwendung unbedingt wieder zurücksichern. Der ganze Zugriff auf deine Statvariablen bassiert auf dem AR2, und wenn du den irgendwo verbiegst, dann pasen die Zugriffe danch nicht mehr...

also vorher
  TAR2  #T_AR2
und danach
 LAR2  #T_AR2

 #T_AR2 ist DWORD im temp bereich


2. wie thomas schon sagte geht das mit INOUT so nicht, in dem Fall wird nicht die Struktur übergeben, sonder ein abgespeckter ANY-Zeiger, ein sogenanter "6-byte_pointer". das siehst du relativ leicht wenn du nach der struktur noch ne variable deklarierst, dann siehst du das der utd nur 6 byte hat...


3. den aufbau von anypointer findest du ind er faq hier oder in der hilfe gut beschrieben, er enrhält im wesenltichen den db, die startadresse und die länge des datenblocks.
ein "6-byte-pointer" enthält nur startadresse und länge

4. ich würde anstelle des udt am inout einfach einen any an die in-schnittstelle machen, da kannst du später auch deine struktur symbolisch dranpacken. du hast dann mittels des ans im baustein alles was du brauchst um deine daten zu adressieren.
der zugriff über inout mitels "6-byte-pointer" ist im mc7 code später auch nichts anderes als ein indirekter zugriff auf jede variable, sprich späte in der sps wird für jeden variablenzugriff ein pointer gerechnet - diese bausteine werden deshlab RIESIG im vergleich zur folgenden lösugn wo anfangs alle in den temp bereich kopiert und am ende wieder zurück wird.
(riesig und die pointerrechnerei geht auch noch auf die laufzeit)

5. vorschlag
IN als any wo de struktur später aussen dran kommt(UDT_blabla)
ANY im temp bereich deklarieren (ANY_Aktoren)
struktur im temp bereich deklarieren (blabla)
mit dem any einen pointer für nen blockmov (sfc20) bauen und umkopieren

Pointer einlesen


```
L     P##UDT_blabla
      LAR1  
      L     B [AR1,P#0.0]               // Syntax-ID aus dem Any-Pointer auslesen
      T     #SyntaxID
      L     B [AR1,P#1.0]               // Bereichstyp auslesen (B#16#2 = Byte;  B#16#3 = Int; B#16#4 = Word;  B#16#7 = DInt; B#16#8 = DWord)
      T     #Bereichstyp
      L     W [AR1,P#2.0]               // Anzahl der zu übertragenden Werte (Byte/Word)
      T     #Anzahl_Werte
      L     W [AR1,P#4.0]               // DB-Nummer auslesen
      T     #DB_Nr
      L     D [AR1,P#6.0]               // Pointer Startadresse auslesen
      T     #Startadresse
```
 

pointer für blockmove bauen


```
L     P##ANY_blabla
      LAR1  
      L     #SyntaxID
      T     B [AR1,P#0.0]               // Syntax-ID in den Any-Pointer schreiben
      L     #Bereichstyp
      T     B [AR1,P#1.0]               // Bereichstyp schreiben (B#16#2 = Byte; B#16#4 = Word)
      L     #Anzahl_Werte
      T     W [AR1,P#2.0]               // Anzahl der zu übertragenden Werte (Byte/Word)
      L     #DB_Nr
      T     W [AR1,P#4.0]               // DB-Nummer schreiben
      L     #Startadresse
      T     D [AR1,P#6.0]               // Pointer Startadresse schreiben
```
 
daten in dem temp breich kopieren


```
CALL  "BLKMOV"
       SRCBLK :=#ANY_blabla
       RET_VAL:=#retval
       DSTBLK :=#blabla
```
 
hier steht dein programm wo du die daten im temp bereich manipulierst bzw. die temp struktur auch an die aufgerufenen fcs übergibst (in denen kannst du ja so wie du es hast arbeiten - achte nur auf die codelänge wegen der zugriffe, wenn dir der code zu lange wird, kannst du es ja auch so machen wie beim fb


am ende des fb muss der inhalt der temp struktur zurück in die anparametrierte struktur...


```
CALL  "BLKMOV"
       SRCBLK :=#blabla
       RET_VAL:=#retval
       DSTBLK :=#ANY_blabla
```


----------



## Thomas_v2.1 (26 Februar 2010)

Sehr schön zusammengefasst Markus.

Auch dass ein UDT-Parameter viel Speicher und Rechenleistung frisst ist gut zu erwähnen.
Jedoch muss ich sagen, dass ich mich da mittlerweile nicht mehr drum schere. Die neuen 315 CPU sind so leistungsfähung, dass ich keine Lust mehr habe irgendwo zu Lasten der Übersichtlichkeit was an der Performance oder Speicherauslastung zu optimieren. Bei mir kommt erst der Algorithmus, dann die Optimierung (wenn es Engpässe gibt).
Wenn man sich die Codesys-Steuerungen ansieht: da kann man nichtmal mehr sehen wie viel Speicher sein einzelner Baustein benötigt.

Mit einem Any-Pointer kann ich alles machen, jedoch gebe ich damit auch jedwede Typ-Überprüfung seitens des Compilers auf (der Step7-Editor ist ein Compiler, wenn auch abgespeckt). Vergleichbar ist das in groben Zügen mit dem Void-Zeiger in der C-Programmierung. Dort hat der Compilier auch fast keine Möglichkeiten mehr die Korrektheit der Typen zu überprüfen.


----------



## thomasgull (27 Februar 2010)

ist das ein Problem mit dem Temp bereich? ist ja nur für den Transfer in den IO bereich des nächsten Baustein.


Thomas


----------



## Thomas_v2.1 (27 Februar 2010)

thomasgull schrieb:


> ist das ein Problem mit dem Temp bereich? ist ja nur für den Transfer in den IO bereich des nächsten Baustein.



Der Speicherbereich auf den der Zeiger dann im unterlagerten FB zeigt ist damit vom Typ "vorherige Lokaldaten" (V, Kennung 0x87).
Ich habe damit schonmal rumexperimentiert und in PLCSim funktioniert das auf jeden Fall. Ich erinnere mich aber an ein Handbuch in dem stand, dass es diesen Speicherbereich nur bei den 400er CPUs gibt. Die Step7-Hilfe weist diese Beschränkung jedoch nicht aus.


----------



## Markus (27 Februar 2010)

thomasgull schrieb:


> ist das ein Problem mit dem Temp bereich? ist ja nur für den Transfer in den IO bereich des nächsten Baustein.
> 
> 
> Thomas



achso.. du meinst falll die aufgerufenen bausteine auch im temp bereich rumfummeln?
ja, das kann ein problem geben bzw. ist nicht sauber... in dem fall legst du halt die struktur in den stat bereich des fb...

sorry - das war ein fehler von mir!


----------



## SPS.at (19 Dezember 2013)

Hallo Markus!
Sorry, daß ich den Thread aus der Versenkung hebe, vielleicht gibt es anderenorts schon weiterführende Infos...
Das  mit dem stat bereich ist gut, du meinst also die parametrierte UDT auch  im Statbereich parametrieren und über den Anypointer mit BLKMOV die UDT  dort hin kopieren?
 Aber wie kann ich die Adresse des UDT im STATbereich ermitteln wenn sich die UDT oder andere Parameter am FB geändert haben?
grüße
thomas


----------



## Sioan (20 Dezember 2013)

Man *könnte (?)* auch "TRICK 22" benutzen ... nämlich den Befehl :

*TDB 
*
*Die DB ,DIB sollen  ... über TEMP Bereich kommunizieren !* Adressierung mit P##xxx und AR1 ...etc
" P##xxx " wäre der erste Formalparameter in FB ....(der ist zugleich auch erster in DIB nach TDB )... alle Positionen in DIB nach TDB wären so über dem AR1 aufm DB-Anfang bezogen erreichbar .

Keine Sorge beim OB1-zyklischem FB Aufruf wird immer die richtige DIB gewählt (die ist ja in der CALL FB Definition gegeben )
Umkopieren würde dann über eine einfache Schleife gehen ... ohne ANY ... ohne BLOCKMOVE 
_Alles symbolisch in TEMP ... SELBSTVERSTÄNDLICH_ 

(TEMP Daten werden von dem *TDB *Befehl nicht  verändert)


----------



## Larry Laffer (20 Dezember 2013)

@SPS.at:
was genau möchtest du machen ?
Der IN-Parameter (oder OUT-Parameter) eines FB ist vom Typ her festgelegt - den kannst du nicht variieren. Der Bereich bildet den ganzen UDT ab - das gibt also kein Problem.

@Sioan - 00alex:
Bitte nicht überall herum-spammen ... !!!

Gruß
Larry


----------



## Blockmove (20 Dezember 2013)

SPS.at schrieb:


> Aber wie kann ich die Adresse des UDT im STATbereich ermitteln wenn sich die UDT oder andere Parameter am FB geändert haben?



Du kannst symbolisch auf die UDT im Stat-Bereich zugreifen.
Hier ein Code-Schnippsel von mir


```
// ----------------
// Any-Pointer PSrc
// ----------------
// Adresse des Anypointer PSrc
      L     P##PSrc
      LAR1  
// System-Code für Anypointer
      L     B#16#10
      T     B [AR1,P#0.0]
// Datentype Byte
      L     B#16#2
      T     B [AR1,P#1.0]
// DB-Nr 
      L     #BahnDBNr
      T     W [AR1,P#4.0]
// StartByte-Nr
      L     P#DBX 0.0                   // Daten Platz 1
      T     D [AR1,P#6.0]
// Anzahl der Bytes zum Kopieren
      L     280                         // Grösse UDT_Bahn
      T     W [AR1,P#2.0]
// Daten von BahnDB nach Instanzdaten "Bahn" kopieren
      CALL  "BLKMOV"
       SRCBLK :=#PSrc
       RET_VAL:=#iRetVal
       DSTBLK :=#Bahn
```

PSrc ist als Any-Pointer im Temp-Bereich definiert.
Bahn ist als UDT im Stat-Bereich definert.

Gruß
Dieter


----------



## SPS.at (22 Dezember 2013)

Danke für die Antworten!
@larry
Es geht nach wie vor um das Durchreichen von IN/OUT-UDT's
@blockmove
Ganz steige ich bei deinem Beispiel noch nicht durch...
Du kopierts die Daten von der unter PSrc hinterlegten Adresse auf den InstanzDB?
Die Destinationadresse im IDB beginnt bei 0.0 und das UDT ist 280 Byte lang - bin ich soweit richtig?
Was aber wenn sich die Länge des UDT ändert? Oder jemand einen zusätzlichen IN am FB Parametriert?
grüße
thomas


----------



## Blockmove (22 Dezember 2013)

SPS.at schrieb:


> @blockmove
> Ganz steige ich bei deinem Beispiel noch nicht durch...
> Du kopierts die Daten von der unter PSrc hinterlegten Adresse auf den InstanzDB?
> Die Destinationadresse im IDB beginnt bei 0.0 und das UDT ist 280 Byte lang - bin ich soweit richtig?
> Was aber wenn sich die Länge des UDT ändert? Oder jemand einen zusätzlichen IN am FB Parametriert?



OK ist ein nicht ganz passendes Beispiel ... Sorry.
Wenn du einen Any-Pointer als IN-Parameter anlegst, dann bekommst du alle notwendigen Daten in diesem Pointer.
Die Destination ist NICHT DIX0.0, sondern die Daten werden vom Bahn-DB DBX0.0 in die UDT #Bahn im Stat-Bereich (Instanz) kopiert.
Deren Adresse muss ich überhaupt nich wissen, denn dies erledigt aufgrund der symbolischen Adressierung der Compiler für mich.
Zusätzliche Parameter spielen überhaupt keine Rolle. Beim Übersetzten passt der Compiler dies automatisch an.

Vorteil ist, dass ich dann im FB vollsymbolisch auf die Daten in der UDT zugreifen kann. Am Ende des FBs kopiere ich dann die Daten von #Bahn wieder in den passenden DB.


Gruß
Dieter


----------



## Larry Laffer (23 Dezember 2013)

SPS.at schrieb:


> @larry
> Es geht nach wie vor um das Durchreichen von IN/OUT-UDT's


Naja ... dazu hättest du schon noch etwas mehr schreiben dürfen , wegen :



SPS.at schrieb:


> Was aber wenn sich die Länge des UDT ändert? Oder jemand einen zusätzlichen IN am FB Parametriert?


Die Länge des UDT's ändert sich nicht von selber.
Du kannst auch nicht für einen IN-Parameter vom Typ UDT11 einen UDT12 darufschreiben - selbst dann nicht wenn er gleich groß sein sollte.

Wenn du aber an der Schnittstelle deines Bausteins etwas änders so ist immer ein neu Übersetzen und ein neu generieren der Instanz notwendig. In diesem Fall würde sich ein symbolisch Zugriff (wie in Blockmove-Dieter in seinem Beispiel-Code hat) automatisch anpassen und wenn nötig alles wieder glatt ziehen.

Gruß
Larry


----------

