# FC Move mittels Any-Pointer



## Toki0604 (1 November 2010)

Guten Tag liebe "SPS-Gemeinde",

ich habe vor ein paar Wochen bei Siemens Lehrgänge zu S7/300 besucht und die Prüfung zum Programmierer abgelegt. Es gab jedoch eine Aufgabenstellung die ich bis heute nicht gelöst habe.(Prüfungsaufgabe, daher hilft Siemens nicht). Das läßt mich Nachts nicht schlafen .
Ich möchte auf keinen Fall eine fertige Lösung zu meinem Problem!
Ich benötige vielmehr eine Starthilfe um das Problem selbst zu lösen.

Thema indirekte Adressierung:
Es sollte ein FC erstellt werden, der "wiederverwendbar" programmiert ist.
Die Funktion ist kurz erklärt: 
In-Parameter : Start ( Bool )
In-Parameter : Quelle ( Any-Pointer )
In/Out-Parameter : Ziel ( Any-Pointer )

Mit dem Start-Impuls sollte aus einem DB-Prozessdaten ein UDT mit einer Datenlänge von 4 Doppelworten in einen DB-Datensicherung geschrieben werden. ( Grundfunktion )
Wenn diese Funktion hergestellt wurde, sollte man die Programmierung und den DB-Datensicherung in soweit ändern, das es 10 Speicherplätze gibt und nach erreichen des letzten Speicherplatz von vorne überschrieben wird. ( erweiterte Funktion )

Problem meinerseits ist das mir bis jetzt jeder Gedankenansatz fehlt wie ich den Datenbereich innerhalb des FC´s von IN nach OUT bekomme.
Ausprobiert habe ich schon vieles, aber ich bekomme immer nur Fehlermeldungen im Simatic Manager das die benutzten Befehle in einem FC nicht gestattet sind etc. 

Würde mich freuen wenn mir jemand "auf die Sprünge" helfen könnte.
Danke
Torsten


----------



## dalbi (1 November 2010)

Hi,

das kopieren kann man schön mit dem SFC20 machen. Vorher musst Du allerdings die ANYs in eine Temporäre Variable kopieren und diese dann an den SFC20 legen.

http://sps-forum.de/showthread.php?t=12923 

Gruss Daniel


----------



## Toki0604 (1 November 2010)

Hi Daniel,
danke für deine schnelle Antwort. 
Habe mir den Link angeschaut. Soweit so gut. Aber der Any-Pointer steht am IN-Parameter eines FC. Ich habe hier keine lokale Adressen die ich nutzen kann. Ich glaube genau hier ist mein Problem ( Gedankenblockade meinerseits?! ).

Gruß, Torsten


----------



## Larry Laffer (1 November 2010)

Hallo,
was Dalbi schreibt bezieht sich auf den IN-Parameter ANY schlecht hin.
Du kannst ihn nicht einfach zu dem FBC20 durchreichen - das geht nicht. Du mußt die Adresse, auf die er zeigt, in einem eigenen "LOKAL angelegten" ANY nachbilden und die dann an den SFC20 übergeben.
Das wird aber in dem Beitrag, den Dalbi dir verlinkt hat, auch dargestellt.
Ansonsten gibt es (speziell zu diesem Thema) hier im Forum noch viele andere Beiträge (Suchfunktion), die das auch noch behandeln ...

Gruß
Larry


----------



## Kai (1 November 2010)

Vielleicht hilft das folgende Programmbeispiel weiter:

In einem FC werden zwei ANY-Pointer (Quellbereich und Zielbereich) aus dem IN-Bereich in den TEMP-Bereich kopiert.

Anschließend wird ein SFC20 BLKMOV mit den beiden ANY-Pointer (Quellbereich und Zielbereich) aus dem TEMP-Bereich beschaltet.

Der SFC20 BLKMOV kopiert dann den Quellbereich (Eingangsbereich) in den Zielbereich (Datenbaustein).


```
UNCTION FC 100 : VOID
TITLE =ANY-Pointer
//14
AUTHOR : Kai
FAMILY : SPSForum
NAME : 'ANY'
VERSION : 1.0
VAR_INPUT
  IN_Quelle : ANY ; 
  IN_Ziel : ANY ; 
END_VAR
VAR_TEMP
  TEMP_DB_Register : WORD ; 
  TEMP_AR1_Register : DWORD ; 
  TEMP_AR2_Register : DWORD ; 
  TEMP_Quelle : ANY ; 
  TEMP_Ziel : ANY ; 
  TEMP_RET_VAL : INT ; 
END_VAR
BEGIN
NETWORK
TITLE =Register sichern
 
      L     DBNO; // DB-Register
      T     #TEMP_DB_Register; 
 
      TAR1  ; // AR1-Register
      T     #TEMP_AR1_Register; 
 
      TAR2  ; // AR2-Register
      T     #TEMP_AR2_Register; 
 
NETWORK
TITLE =Quelle (ANY-Pointer)
//Versorgung ANY-Pointer-Variable mit IN-Variable
//
//Adressierung AR1 im V-Stack
//
//L     P#IN_Quelle
//LAR1
//
//L     B [AR1,P#0.0]
//
//Versorgung ANY-Pointer-Variable mit TEMP-Variable
//
//Adressierung AR2 im L-Stack 
//
//L     P#TEMP_Quelle
//LAR2
//
//T     LB [AR2,P#0.0]
//   
      L     P##IN_Quelle; // Quelle (ANY-Pointer)
      LAR1  ; 
 
      L     P##TEMP_Quelle; // Quelle (ANY-Pointer)
      LAR2  ; 
 
      L     B [AR1,P#0.0]; // Syntax-ID
      T     LB [AR2,P#0.0]; 
 
      L     B [AR1,P#1.0]; // Datentyp
      T     LB [AR2,P#1.0]; 
 
      L     W [AR1,P#2.0]; // Anzahl
      T     LW [AR2,P#2.0]; 
 
      L     W [AR1,P#4.0]; // DB-Nummer
      T     LW [AR2,P#4.0]; 
 
      L     D [AR1,P#6.0]; // Bereichszeiger
      T     LD [AR2,P#6.0]; 
 
NETWORK
TITLE =Ziel (ANY-Pointer)
//Versorgung ANY-Pointer-Variable mit IN-Variable
//
//Adressierung AR1 im V-Stack
//
//L     P#IN_Ziel
//LAR1
//
//L     B [AR1,P#0.0]
//
//Versorgung ANY-Pointer-Variable mit TEMP-Variable
//
//Adressierung AR2 im L-Stack
//
//L     P#TEMP_Ziel
//LAR2
//
//T     LB [AR2,P#0.0]
//   
      L     P##IN_Ziel; // Ziel (ANY-Pointer)
      LAR1  ; 
 
      L     P##TEMP_Ziel; // Ziel (ANY-Pointer)
      LAR2  ; 
 
      L     B [AR1,P#0.0]; // Syntax-ID
      T     LB [AR2,P#0.0]; 
 
      L     B [AR1,P#1.0]; // Datentyp
      T     LB [AR2,P#1.0]; 
 
      L     W [AR1,P#2.0]; // Anzahl
      T     LW [AR2,P#2.0]; 
 
      L     W [AR1,P#4.0]; // DB-Nummer
      T     LW [AR2,P#4.0]; 
 
      L     D [AR1,P#6.0]; // Bereichszeiger
      T     LD [AR2,P#6.0]; 
 
NETWORK
TITLE =Quelle (ANY-Pointer) nach Ziel (ANY-Pointer) kopieren
 
      CALL SFC   20 (
           SRCBLK                   := #TEMP_Quelle,
           RET_VAL                  := #TEMP_RET_VAL,
           DSTBLK                   := #TEMP_Ziel);
      NOP   0; 
 
NETWORK
TITLE =Register wiederherstellen
 
      AUF   DB [#TEMP_DB_Register]; // DB-Register
 
      L     #TEMP_AR1_Register; // AR1-Register
      LAR1  ; 
 
      L     #TEMP_AR2_Register; // AR2-Register
      LAR2  ; 
 
END_FUNCTION
```
 
Gruß Kai


----------



## Kai (1 November 2010)

Und noch ein paar Bilder aus der Simulation mit PLCSIM.

Gruß Kai


----------



## Toki0604 (2 November 2010)

*Erstes Ziel erreicht - Grundfunktion steht*

Mit bestem Dank an Dalbi, Larry und Kai !
Das Einlesen und Schreiben funktioniert. Nun gehe ich an die erweiterte Funktion die Ziel-Speicherplätze dynamisch zu gestalten.
Dazu denke ich muss ich nur entsprechend einen Offset an den Zielspeicherort anhängen.  Werde ich jetzt mal ausprobieren.

Gruß
Torsten


----------



## Toki0604 (2 November 2010)

*Erweiterte Funktion läuft auch*

Hi,
habe meinen Offset auch ans laufen gebracht. (Schwitz ) :s11: 
Schaut ihr vielleicht mal ob das OK ist, oder es ggf. eine elegantere Lösung gibt !? Habe es als PDF angehängt, weil Quellcode ist glaub ich zu viel.
Danke, Gruß
Torsten


----------



## Aksels (21 Dezember 2010)

*Aufruf des FC mit Temp-Daten*

Hallo Leute,

ich habe dieses Beispiel von Kai ausprobiert.
Klappt gut. Warum kann ich aber keine Lokaldaten als Destination angeben:


```
Call "Any"
IN_Quelle:=P#DB100.DBX0.0 Byte 10
IN_Ziel:=P#L 0.0 BYTE 10
```

Gruß,
Aksels


----------



## Gebs (21 Dezember 2010)

Hallo Aksels,

Du kannst mit dem Any-Pionter auf Lokal-Variablen des aktuellen und auf die L-Variablen vorhergehenden 
Bausteins zugreifen. D.h. Du könntest im Baustein "Any" auf die L-Variablen des aufrufenden Bausteins 
zugreifen. Der SFC 20 kann nur auf seine und die des "Any" zugreifen.
Auf die L-Variablen des vor-vorhergehenden Bausteins kann man nicht zugreifen.

Grüße
Gebs


----------



## dkaserer (21 September 2011)

Hallo, ich habe den FC32 nun so nachprogrammiert.

Bei mir verhält er sich aber nicht ganz richtig, weil der Offset nicht richtig berechnet wird:

ich habe 4 DBD und das 10 mal im SicherungsDB
wenn ich den FC nochmal aufrufe, dann erhöht er zwer den Offset aber nur um ein DW und nicht um 4 DW, ich habe haltepunkte gesetzt, und die akkus kontrolliert.

 L     P##Ziel
      LAR1  

      L     W [AR1,P#2.0]
      T     #Datenlaenge
      L     W [AR1,P#4.0]
      T     #Ziel_DBNr

      AUF   DB [#Ziel_DBNr]

      L     DBW    2
      L     DBW    0
      >=I   
      SPBN  weit
      L     0
      T     DBW    2

weit: L     #Datenlaenge
      L     DBW    2
      *I    
      SLW   3
      T     #Offset

      L     DBW    2
      L     1
      +I    
      T     DBW    2

      L     DBW    2

intressanterweise ist bei L #Datenlaenge der Akkuwert auf 10 (das ist die maximale anzahl an sicherungen), dieser wird doch vor der Sprungmarke gelesen, um zu checken, ob die DB voll ist. es ist egal ob ich #datenlaenge oder dbw 2 einlese an der stelle. Gibt es für dieses Phänomen eine Erklärung?

wenn ich das Ganze mal 4 mache (4 Bytes ist ein DW) dann gehts einwandfrei.

und dann hab ich noch eine zweite Frage:

Für was werden die Register (DB,AR1,AR2) in NW 1 und 6 gesichert bzw wiederhergestellt? hat das was mit dem Bausen auf sich, der den FC aufgerufen hat?


----------



## Gebs (21 September 2011)

Hallo dkaserer!

Wie rufst Du den FC 32 auf? Stell doch mal den Aufruf hier rein.



dkaserer schrieb:


> Für was werden die Register (DB,AR1,AR2) in NW 1 und 6 gesichert bzw wiederhergestellt? hat das was mit dem Bausen auf sich, der den FC aufgerufen hat?



=> Such mal nach Multiinstanz.

Grüße
Gebs


----------



## dkaserer (21 September 2011)

Bei mir heist er FC10, ist aber egal

      CALL  FC    10
       Start  :=M4.0
       Quelle :=P#DB110.DBX 16.0 DWORD 4
       RET_VAL:=LW40
       Ziel   :=P#DB120.DBX 4.0 DWORD 4


----------



## Gebs (21 September 2011)

Hallo dkaserer!

Da haben wir doch schon das Problem!!!

Der Baustein von Toki ist so programmiert, dass er den Offset in 
Bytes berechnet.
Entweder programmierst Du die Berechnung des Offsets um, oder Du
gibst beim Aufruf die Länge in Bytes an.

Grüße
Gebs


----------



## dkaserer (21 September 2011)

Danke Gebs, also noch mal zum Verständnis

wenn ich einen ANY Zeiger übergebe, dann ist der Wiederholungsfaktor in BYTE angegeben, ganz egal welcher Datentyp das ist?

dann müsste man sich den Wiederholungsfaktor anhand des Datentyps ausrechnen.


----------



## Gebs (21 September 2011)

Hallo dkaserer,



> wenn ich einen ANY Zeiger übergebe, dann ist der Wiederholungsfaktor in BYTE angegeben, ganz egal welcher Datentyp das ist?


Nein, der Wiederholungsfaktor bezieht sich auf das Datenformat.
4 DBD = 8 DBW = 16 DBB



> dann müsste man sich den Wiederholungsfaktor anhand des Datentyps ausrechnen.


Du musst Dir hier Dein Offset anhand Wiederholungsfaktor und Datentyp ausrechnen. 
Wie Du den Datentyp aus einem ANY auslesen kannst steht hier:
http://www.sps-forum.de/showthread.php?t=12923

Grüße
Gebs


Grüße
Gebs


----------



## dkaserer (21 September 2011)

OK jetzt hab ichs kapiert!

Danke für deine Hilfe.


----------



## Toki0604 (22 September 2011)

Hallo dkaserer,

da Wiederholungsfaktor/Datenformat etc. schon so schön erläutert wurden, möchte ich noch kurz auf deine Frage bezüglich der Sicherung der Register eingehen. 
Das ist keine Erfindung von mir, sondern ich habe mir das von 4Lagig (glaube ich) damals abgeschaut und mir zu eigen gemacht.
Es geht darum das dieser Baustein in mitten anderer Codes aufgerufen werden kann.
Falls diese Codes sich darauf verlassen was vor dem Aufruf dieses Bausteins in den Registern steht (stehen müsste), könnte es ungewollt Fehlfunktionen in der Programmierung geben. 
Um dem grundsätzlich vorzubeugen, ob notwendig oder nicht, wird der Zustand der Register nach Aufruf des Bausteins in den Ursprungszustand zurückversetzt.
Es soll angeblich Firmen geben die darauf sogar bestehen ?!
Ich hatte selbst noch keine Anwendung bei der dies zum Tragen kam, aber ich finde es immer gut wenn etwas verlassen wird wie es vorgefunden wurde ;-)

Gruß
Toki


----------

