Blockmove in einem FC (UDT als IN Parameter)

Jochen Kühner

Level-3
Beiträge
4.291
Reaktionspunkte
525
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe einen FC, dieser bekommt in einem Inparameter einen UDT! Nun möchte Ich gern den Inhalt dieses In Parameters per Blockmove in einen anderen DB schieben (den ANY dazu erstelle Ich im FC). Aber diesen In kann Ich ja nicht an den SFC20 hängen. Ist dies Irgendwie möglich. mit L P##PAR1 (PAR1 ist mein UDT IN Parameter)
kann Ich ja die Adresse des Parameters ins AR1 laden, doch kann Ich mir nun daraus einen ANY basteln???
 
Meines Wissens Nein ...
Der UDT als IN-Parameter ist in Wirklichkeit ein Pointer. Dieser läßt sich so nicht hochreichen.
Einen ANY daraus zu basteln müßte grundsätzlich gehen, da der Pointer im Aufbau mit den "unteren" Bytes des ANY identisch ist ...
 
... hat ein bißchen gedauert ...
Um den Pointer greifbar zu bekommen machst du folgendes :
Code:
L P##PAR1
LAR1
TAK
T LD14
TAK
L W[AR1,p#0.0]
T LW 18
Das LD14 (in meinem Beispiel) enthält jetzt die Adresse des UDT's und das LW18 die DB-Nummer (falls die Daten aus einem DB kommen).
Dieses LD14 kannst du jetzt in den "unteren" Teil deines ANY hineinschieben (bzw. es ist schon der untere Teil desselben).
Den ANY deklarierst du am sinnvollsten auch in deinem L-Daten-Bereich.
Weißt du wie man den ANY aufbaut ? Wenn nein, dann lies dir bitte dazu zunächst das Beispiel von Volker in der Rubrik FAQ durch. Wenn dann noch Fragen sind ... du findest mich hier ...

Gruß
LL
 
Mhh...

Wenn Ich einen UDT als in nehme, ist das dann ein Pointer oder ein Any???

Weil wenn es ein ANY ist müsste ja auch folgendes funzen:

L P##DATEN
LAR1
L D [AR1,P#0.0]
T LD 0
L D [AR1,P#4.0]
T LD 4
L W [AR1,P#8.0]
T LW 8

Oder??? (Mein ANY in den Lokaldaten fängt bei LD 0 an!)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
... hat ein bißchen gedauert ...
Um den Pointer greifbar zu bekommen machst du folgendes :
Code:
L P##PAR1
LAR1
TAK
T LD14
TAK
L W[AR1,p#0.0]
T LW 18
Das LD14 (in meinem Beispiel) enthält jetzt die Adresse des UDT's und das LW18 die DB-Nummer (falls die Daten aus einem DB kommen).
Dieses LD14 kannst du jetzt in den "unteren" Teil deines ANY hineinschieben (bzw. es ist schon der untere Teil desselben).
Den ANY deklarierst du am sinnvollsten auch in deinem L-Daten-Bereich.
Weißt du wie man den ANY aufbaut ? Wenn nein, dann lies dir bitte dazu zunächst das Beispiel von Volker in der Rubrik FAQ durch. Wenn dann noch Fragen sind ... du findest mich hier ...

Gruß
LL


Das
Code:
L P##PAR1
LAR1
TAK

Kann doch eigendlich nicht funktionieren oder??? da LAR1 den Akku nicht ändert und nach TAK steht ja im Akku was vor dem LP## drin war, oder???
 
Nein ...
Der Verweis auf deinen UDT wird in den FC als Pointer übergeben ...
Ein Pointer ist 6 Byte groß und beinhaltet nur die DB-Nummer (falls benutzt) die Speicherbereichs-Kennung und die Speicher-Adresse bezpogen auf die Bit-Ebene (siehe hierzu auch Step7-Hilfe "Pointerformat").
Ein ANY-Pointer ist 10 Byte groß und beinhaltet zusätzlich die Steuerung und den Wiederholfaktor (siehe hierzu Step7-Hilfe "ANY - Format").
Gleichzeitig ist der Aufbau der Einzel-Inhalte etwas unterschiedlich.

Dein Code-Beispiel funktioniert so nicht ...
 
Aber so...

Ahh ja, wenn mans weis das UDT als Pointer übergeben werden...

So sollte es ja dann gehn oder??

Code:
//Any auf Quelldaten
      L     W#16#1002
      T     LB     0
      L     B#16#2
      T     LB     1
      L     255                         //Länge des Datensatzes...
      T     LW     2
      L     P##DATEN
      LAR1  
      L     W [AR1,P#0.0]
      T     LW     4
      L     D [AR1,P#2.0]
      T     LD     6
 
Hä???

Seid wann läd denn der L Befehl was in beide Akkus??? Normalerweise verschiebt er den Akku 1 in 2 und läd dann Akku 1!

Step 7 Hilfe:

L <Operand> lädt den Inhalt des adressierten Bytes, Wortes oder Doppelwortes in AKKU 1, nachdem zuvor der alte Inhalt von AKKU 1 in AKKU 2 gespeichert wurde und AKKU 1 auf "0" zurückgesetzt wurde.

Oder lieg ich jetzt fallsch???
 
... ich kann dir da jetzt im Augenblick keine passende Antwort liefern ... ich kann meine Behauptung auch gerade nicht testen. Es müßte doch aber für dich (wenn du da dran bist) relativ einfach festzustellen sein. Nach meiner Meinung steht bei "L P##Par1" im Akku_1 die DB-Adresse des Pointers und in Akku_2 das Adresse-Offset und die Kennung ...
Ich werde das aber später auf jeden Fall noch einmal gegen-checken ...

Gruß
LL
 
Nee...

Laut Step 7 Hilfe:

LAR1 lädt das Adreßregister AR1 mit dem Inhalt von AKKU 1 (32 Bit-Pointer). AKKU 1 und AKKU 2 werden nicht verändert. Die Operation wird ausgeführt, ohne die Statusbits zu berücksichtigen oder zu beeinflussen.
 
Blockmove in einem FC (UDT als In-Parameter)

Lösungsvorschlag:

Die FC hat den In-Parameter udtBlock vom Typ UDT xy (irgendein UDT, z.B. mit 40 Byte Länge). Der Parameter ist ein Pointer mit 6 Byte und beinhaltet die Startadresse des Datenblockes vom Typ UDT xy.

In der FC folgende Lokalvariablen definieren:

_SaveAR1 : DINT
_SaveAR2 : DINT // Dienen zum Sichern der Adressregister

_anySource : ANY // Anypointer für die Quelle, der In-Parameter
// Das Ziel sei ein Struktur im dbDest, z.B. dbDest.sUDT_Ziel
TAR1 _SaveAR1
TAR2 _SaveAR2 // sicherheitshalber Adressregister retten

......

LAR1 _anySource // Quellanypointer aufbereiten
L P#udtBlock // Zeiger auf den In-Parameter
LAR2 // LAR2 P#udtBlock geht n icht direkt in einer FC

L W#16#1002 // Kennung S7 und Datentyp Byte
T W[AR1,P#0.0]
L 40 // 40 Byte sei der UDT groß
T W[AR1,P#2.0]
L W[AR2,P#0.0] // Das ist der Datenbereich des Parametrierten UDTs!!!
T W[AR1,P#4.0]
L D[AR2,P#2.0] // Das ist die Startadresse des UDT-Blockes
T D[AR1,P#6.0] // Fertig ist der Anypointer

CALL "BLKMOV"
SRCBLK := _anySource
RÉT_VAL := _RetVal // irgendeine INT-Variable
DSTBLK := dbDest.sUDTZ_Ziel

......

LAR1 _SaveAR1
LAR2 _SaveAR2

Gruß Puddl
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Jochen:
Das mit dem TAK habe ich mittlerweile gecheckt. Es muß so sein, wie von mir beschrieben ...

@Puddl:
Dein Vorschlag, mit dem AR2-Register zu arbeiten ist aber auch nicht schlecht ... Da war ich nicht drauf gekommen ...
 
Nee...

@Larry....

Ich habs ja in meinem letzte Bsp. eigendlich genau wie Puddl, und das sollte funktionieren. Brauch auch kein TAK dazu, und sehe auch noch nicht denn sin von den TAK's

Denke so wie ich es als letztes hatte wirds funktionieren...
 
Um IN-Parameter für einen Aufruf weiterzuverwenden müssen diese in eine TEMP-Variable kopiert werden. Hier könnte das so aussehen:

L P##PAR1
T #eingang //TEMP-Variable DWORD

CALL "BLKMOV"
SRCBLK :=#eingang
RET_VAL:=MW abc
DSTBLK :=P#DBxy.DBX0.0 BYTE z //"z" ist länge des UDTs

Konnte leider noch nicht checken ob es funktioniert.

MfG
FrankW
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Blockmove...

Hallo FrankW

Das geht so nicht, BlockMove würde so den Inhalt der Variable eingang auf das Ziel kopieren, und der Inhalt von eingang ist die Adresse (Lokalvariable der FC) des Parameters para1.

Man muss schon einen richtigen Any-Pointer aufbauen, sonst klappt das nicht.

Gruß Puddl
 
Hallo Puddl,

ich weiß nicht so recht, bei mir stand da nur ein Pointer auf "Vorheriger Lokaldatenbereich" und wenn ich diesen ins Adressregister geladen habe, stand da nur der POINTER noch mal als DATEN drin (aber auch nur mit PLCSim getestet).

Hat es bei Euch funktioniert?

MfG
FrankW
 
Blockmove...

Hallo FrankW.

Also, ich habe eine FC programmiert mit einem Input-Parameter udtTest vom Typ UDT 920. Sonst hat der FC keine weiteren Parameter.

Die UDT 920, mit Trallalla-Daten, hat 32 Byte. Im DB 1 gibt es eine Struktur udtTest vom Typ UDT 920.

Diese FC habe ich im OB 1 aufgerufen. Als aktualparameter an udtTest habe ich "dbTest".udtTest parametriert, eine Struktur vom Typ UDT 920. Sonst ist im OB1 kein weiterer Aufruf. Der OB1 enthält nur seine Standard-Lokalvariablen (20 Byte).

Im FC 1 habe ich folgende Befehle eingefügt:

L P##udtTest
LAR1
L W [AR1,P#0.0]
L W [AR1,P#2.0]
L W [AR1,P#4.0]

So. Dann habe ich das Miniprogramm im PLCSIM gestartet und mir die FC 1 online angesehen.

Der erste Befehl liefert 870000a8 (hex). Das ist ein Pointer! Er bedeutet Lokalvariablen des Vorgängers (die 87) und die BIT-Adresse dieser Variablen. Man mus also a8 durch 8 dividieren und erhält dann 15 (hex) oder 21. Der In-Parameter verweist also auf eine Lokalvariable des Vorgängers (des OB1) die ab Adresse 21 steht. Und das ist korrekt.
Mit dem 2. Befehl wird dieser Pointer in das Adressregister 1 geladen.
Die Befehlszeilen 3 - 4 liefern den Inhalt der Lokalvariablen, nämlich den eigentlichen Pointer auf meine Struktur im DB 1.
Online kann man lesen:
Befehlszeile 3 -> eine 1. Das ist DB 1
Befehlszeile 4 -> 8400 (hex). Das bedeutet Speicherbereich DB (die 84) und ein Teil der Adresse, welche hier null ist.
Befehlszeile 5 -> 01b0 (hex). Das ist die Bitadresse im DB 1 der Struktur udtTest. 1bh umgerechnet ergibt Byte 54, das Startbyte meiner Struktur.

Ein besonderer Hinweis für alle, die sich mit Pointern und Co etwas schwer tun. In der Simatic-Onlinedokumentation (Titel: STEP 7 - Programmieren mit STEP 7) im Anhang A3 findet ihr alles über Speicherbereiche, Pointer, Anypointer, Datenformate... Das sind die wichtigsten 30 Seiten des Handbuches, die man lesen sollte. Der Rest des Buches, na ja.:rolleyes:

Gruß Puddl
 

Anhänge

  • Test_udt_BLKMOV.zip
    1 MB · Aufrufe: 23
Zurück
Oben