Element aus Array kopieren

guidokk

Level-1
Beiträge
9
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen!

Ich gebe es zu, ich habe von der nachfolgenden Thematik kaum eine Ahnung, aber ich möchte aus einem Array of UDT einen Datensatz, den ich über den Index (INT) referenziere kopieren.

Konkret gibt es einen DB:

AktuellerDS: UDT_DSTyp
Datenbank: Array [1..10] of UDT_DSTyp

Ich habe jetzt mit einem hier im Forum entdeckten Quelltext etwas experimentiert, scheitere aber an der Stelle dem SFC20 die Zieladresse zu übergeben.

Vielleicht kann mich mal jemand unterstützen, der sich damit auskennt.

Vielen Dank!
Code:
FUNCTION FC 2005 : INT
TITLE = FC_COPY
AUTHOR : Guido
VERSION : 0.1
 
VAR_INPUT
SourceData : ANY ; //Datenbereich in dem die Parametersätze abgelegt sind
SourceIndex : INT ; //Index des zu bearbeitenden Parametersatzes
END_VAR
VAR_OUTPUT
DestinationData : ANY ; //Datenbereich in dem der Parametersatz kopiert werden soll 
END_VAR
VAR_TEMP
AR1_TEMP : DWORD ; 
AKT_DATENSATZ : DWORD ; 
LAENGE_UDT : INT ; //Länge des Parametersatzes
DB_UDT : INT ; //Nummer des DB
STARTADRESSE : DWORD ; //Startadresse im DB = 1. Datensatz
END_VAR
BEGIN
NETWORK
TITLE =
//*** AR1 sichern
TAR1 #AR1_TEMP; 
SET ; 
SAVE ; 
//*** Ergebnisse initialisieren
L B#16#0; 
T #RET_VAL; 
//*** AR2 auf Datenbereich im DB
L P##SourceData; 
LAR2 ; 
//*** ANY-Pointer zerlegen
//*** wir brauchen nur die DB-Nr und Länge des UDT
//*** sowie die Startadresse im DB (Bereichszeiger)
L B [AR2,P#0.0]; // Syntax-ID, bei S7 immer 10hex
L B [AR2,P#1.0]; // Datentyp
L W [AR2,P#2.0]; // Anzahl von "Datentyp" = Länge des UDT
T #LAENGE_UDT; // temporär ablegen
L W [AR2,P#4.0]; // Nummer des DB [INT]
T #DB_UDT; // temporär ablegen
L D [AR2,P#6.0]; // Bereichszeiger = Startadresse
T #STARTADRESSE; // Startadresse im DB = 1. Datensatz
//*** Prüfe, ob DATENBEREICH vom Typ=Byte
L B [AR2,P#1.0]; // Datentyp
L B#16#2; // 02hex == BYTE
==I ; 
L 1; // Fehler 1: DATENBEREICH nicht vom Typ BYTE
SPBN ERR; // !!! Baustein bei Parameterfehler beenden !!!
//*** Source-DB öffnen und Adressregister AR2 auf Bereichszeiger
AUF DB [#DB_UDT]; // DB öffnen
L #STARTADRESSE; // Bereichszeiger == Startadresse 1. Datensatz
LAR2 ; // DATENBEREICH
//*** Offset des aktuellen Datensatzes zu AR2 addieren
L #SourceIndex; // Nummer des aktuellen Datensatzes (1..n) [INT]
L 1; // beim 1. Datensatz ist Offset=0
-I ; // Nummer des aktuellen Datensatzes (0..n-1) [INT]
// Länge des UDT in BIT umrechnen, ohne Akku 2 zu verändern
L #LAENGE_UDT; // Länge des UDT (Anzahl DWORD) [INT]
SLW 5; // Länge des UDT (Anzahl BIT), (SLW 5 == *32)
// Länge des UDT mit aktueller (Datensatznummer-1) multiplizieren
*I ; 
// Offset [BIT] zu AR2 addieren
+AR2 ; // AR2 zeigt jetzt auf aktuellen Datensatz im DB
//*** AR2 für späteres Zurückkopieren zwischenspeichern
TAR2 #AKT_DATENSATZ; 
//*** Den Datensatz kopieren
CALL "BLKMOV" (
SRCBLK := #AKT_DATENSATZ,
RET_VAL := #RET_VAL,
DSTBLK := MD 1000); //<- Hier sollte eigentlich #DestinationData stehen!
//***************************************************************************************************
// Ende
//***************************************************************************************************
//*** AR1-Register wiederherstellen
LAR1 #AR1_TEMP; 
BEA ; 
//*** Fehler
ERR: T #RET_VAL; 
//*** AR1-Register wiederherstellen
LAR1 #AR1_TEMP; 
BE ; 
END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wozu brauchst du in dem Zusammenhang den Block-Move ?
Ich denke mal, es geht dir da drum, den jeweils indexierten UDT einem anderen Programm (oder so) zur Verfügung zu stellen ...
Das kannst du doch auch mit einem Übergabe-Bereich machen, wo du die gewünschten Daten hinkopierst ...
 
@Larry

Alle Bausteine des restlichen Programmes greifen nur auf "AktuellerDS" im DB zu. Dieser wird aus einer "Datenbank" ausgewählt und in "AktuellerDS" hineinkopiert. Was meinst du mit Übergabebereich und wie kopiere ich die gewünschten Daten dort hin?

@Volker

Danke erst mal, dein Link ist sehr informativ ich arbeite daran...
 
Ich hatte das so gemeint, dass in deinem DB (?) z.B. als erstes der Übergabe-UDT liegt. In diesen schiebst du das jeweils gewünschte ARRAY-UDT hinein. Auf diese Weise kannst du m.E. auf die ANY-Pointer-Geschichte verzichten.

Das heißt allerdings nicht, dass es nicht ganz sinnvoll ist sich mit dieser Thematik zu beschäftigen ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Genau das möchte ich doch damit erreichen. Der FC COPY hat als Eingangsparameter das erste Element des Arrays und den Index (als Integer) des gewünschten Arrayelementes. Ich möchte die Angabe des Index als Integer haben, damit der Bediener dies vom Bedienpanel vorgeben kann. Als Ausgangsparameter wird "AktuellerDS" angegeben, in dem das Arrayelement kopiert wird. Natürlich könnte ich das auch fest angeben, aber ich möchte den Baustein gerne flexibel verwenden.

So ich bin jetzt (auch vom Verständnis) viel weiter.

Code:
FUNCTION "FC_LIB Copy" : INT
TITLE =FC_LIB Copy
AUTHOR : Guido
VERSION : 0.1

VAR_INPUT
  SourceData : ANY ; //Datenbereich der in dem die Parametersätze abgelegt sind
  SourceIndex : INT ; //Index des zu bearbeitenden Parametersatzes
END_VAR
VAR_OUTPUT
  DestData : ANY ; 
END_VAR
VAR_TEMP
  AR1_TEMP : DWORD ; 
  UDT_Length : INT ; //Länge des Parametersatzes
  UDT_DB : INT ; //Nummer des DB
  Source_Start : DWORD ; //Startadresse im DB = 1. Datensatz
  Source_SFC : ANY ; 
  Dest_SFC : ANY ; 
END_VAR
BEGIN
NETWORK
TITLE =
//*** AR1 sichern
      TAR1  #AR1_TEMP; 
      SET   ; 
      SAVE  ; 
//*** Ergebnisse initialisieren
      L     B#16#0; 
      T     #RET_VAL; 
//*** AR2 auf Datenbereich im DB
      L     P##SourceData; 
      LAR2  ; 
//*** Prüfe, ob DATENBEREICH vom Typ = BYTE
      L     B [AR2,P#1.0]; // Datentyp
      L     B#16#2; // 02hex == BYTE
      ==I   ; 
      L     1; // Fehler 1: DATENBEREICH nicht vom Typ BYTE
      SPBN  ERR; // !!! Baustein bei Parameterfehler beenden !!!
//*** ANY-Pointer zerlegen
//*** wir brauchen die DB-Nr und Länge des UDT
//*** sowie die Startadresse im DB (Bereichszeiger)
      L     W [AR2,P#2.0]; // Anzahl von Datentyp
      T     #UDT_Length; 
      L     W [AR2,P#4.0]; // Nummer des DB
      T     #UDT_DB; 
      L     D [AR2,P#6.0]; // Bereichszeiger = Startadresse
      T     #Source_Start; // Startadresse im DB = 1. Datensatz
//*** Adressregister AR2 auf Bereichszeiger
      L     #Source_Start; // Bereichszeiger == Startadresse 1. Datensatz
      LAR2  ; 
//*** Offset des aktuellen Datensatzes zu AR2 addieren
      L     #SourceIndex; // Nummer des aktuellen Datensatzes (1..n)
      L     1; // beim 1. Datensatz ist Offset=0
      -I    ; // Nummer des aktuellen Datensatzes (0..n-1)
//    Länge des UDT in BIT umrechnen, ohne Akku 2 zu verändern
      L     #UDT_Length; // Länge des UDT (Anzahl BYTE)
      SLW   3; // Länge des UDT (Anzahl BIT), (SLW 3 == *8)
//    Länge des UDT mit aktueller (Datensatznummer-1) multiplizieren
      *I    ; 
//    Offset [BIT] zu AR2 addieren
      +AR2  ; // AR2 zeigt jetzt auf aktuellen Datensatz im DB
//*** AR2 als neue Startadresse sichern      
      TAR2  #Source_Start; 

// Hier wird für die SFC_20 die Anfangsadresse und Datenlänge in den Pointer gelegt
      LAR1  P##Source_SFC; // Hier wir die Quelladresse für die SFC_20 in den Pointer gelegt
      L     B#16#10; //Syntax-ID
      T     LB [AR1,P#0.0]; 
      L     B#16#2; //Datentyp Byte
      T     LB [AR1,P#1.0]; 
      L     #UDT_Length; //Anzahl von Datentyp
      T     LW [AR1,P#2.0]; 
      L     #UDT_DB; //Nummer des DB
      T     LW [AR1,P#4.0]; 
      L     #Source_Start; //Bereichszeiger
      T     LD [AR1,P#6.0]; 
//*** Den Datensatz kopieren
      CALL "BLKMOV" (
           SRCBLK                   := #Source_SFC,
           RET_VAL                  := #RET_VAL,
           DSTBLK                   := MD  1000);
//***************************************************************************************************
// Ende
//***************************************************************************************************
//*** AR1-Register wiederherstellen
      LAR1  #AR1_TEMP; 
      BEA   ; 
//*** Fehler
ERR:  T     #RET_VAL; 
//*** AR1-Register wiederherstellen
      LAR1  #AR1_TEMP; 
      BE    ; 
END_FUNCTION

ABER! Warum kann ich den als Any deklarierten Output Parameter "DestData" nicht als DSTBLK am SFC20 anlegen???
 
Zuletzt bearbeitet:
ABER! Warum kann ich den als Any deklarierten Output Parameter "DestData" nicht als DSTBLK am SFC20 anlegen???

Denk-Fehler ...!
Die Ziel-Adresse für deine Daten wird nicht von deinem Baustein erzeugt, sondern die gibst du ja (von außen) vor. Somit muß das ein IN-Parameter sein. Der SFC akzeptiert den OUT-Parameter aus dem Grund nicht ...
 
Denk-Fehler ...!
Die Ziel-Adresse für deine Daten wird nicht von deinem Baustein erzeugt, sondern die gibst du ja (von außen) vor. Somit muß das ein IN-Parameter sein. Der SFC akzeptiert den OUT-Parameter aus dem Grund nicht ...

Ich habe das probiert, aber:

Der Deklarationsbereich der Aktualseite VAR_INPUT passt nicht zum formalen Deklarationsbereich VAR_OUTPUT des Formalparameters DSTBLK
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Stimmt ... habe ich schon wieder vergessen ...
Du kannst einen ANY-Pointer nicht durchreichen ...
Du mußt den Eingangs-Parameter zunächst in einem TEMP zwischen-speichern. Das geht allerdings nicht mit "L IN_ANY ... T TEMP_ANY" sondern du mußt den Doppelwort-weise (z.B.) über die Hilfsregister (AR1) auf deine TEMP-Variable bringen. Diese kannst du dann an den SFC übergeben.
Code:
L  P##Source_Data
L AR1
 
L P##Temp_ANY_Pointer
L AR2
 
L DBD [AR1,P#0.0]
T DBD [AR2,P#0.0]
usw.

Anmerkung am Rande:
man vergißt so Einiges, wenn man sich angewöhnt, solche Dinge in SCL zu programmieren ... Da wird einem schon Einiges abgenommen ...
 
Herzlichen Dank an die beiden Helfer, es funktioniert jetzt zufriedenstellend.

Der Vollständigkeit halber meine Lösung:
Code:
FUNCTION "FC_LIB Copy" : VOID
TITLE =FC_LIB Copy
AUTHOR : Guido
VERSION : 0.1
 
VAR_INPUT
  SourceData : ANY ; //Erstes Datenelement des Quelldatenbereichs
  SourceIndex : INT ; //Index des Quelldatensatzes
  DestData : ANY ; //Erstes Datenelement des Zieldatenbereichs
  DestIndex : INT ; //Index des Zieldatensatzes
END_VAR
VAR_TEMP
  AR1_Temp : DWORD ; 
  SourceLength : INT ; //Länge des Parametersatzes
  SourceDB : INT ; //Nummer des DB
  SourceStart : DWORD ; //Startadresse im DB = 1. Datensatz
  SourceSFC : ANY ; 
  DestSFC : ANY ; 
  RET_VAL_SFC : INT ; 
  DestLength : INT ; 
  DestDB : INT ; 
  DestStart : DWORD ; 
END_VAR
BEGIN
NETWORK
TITLE =
//*** AR1 sichern
      TAR1  #AR1_Temp; 
      SET   ; 
      SAVE  ; 
//*** AR2 auf Quelldatenbereich
      L     P##SourceData; 
      LAR2  ; 
//*** ANY-Pointer zerlegen
      L     W [AR2,P#2.0]; // Anzahl von Datentyp
      T     #SourceLength; 
      L     W [AR2,P#4.0]; // Nummer des DB
      T     #SourceDB; 
      L     D [AR2,P#6.0]; // Bereichszeiger = Startadresse
      T     #SourceStart; // Startadresse im DB = 1. Datensatz
//*** Adressregister AR2 auf Bereichszeiger
      L     #SourceStart; // Bereichszeiger = Startadresse 1. Datensatz
      LAR2  ; 
//*** Offset zu AR2 addieren
      L     #SourceIndex; // Nummer des aktuellen Index (1..n)
      L     1; // beim 1. Datensatz ist Offset=0
      -I    ; // Nummer des aktuellen Index (0..n-1)
//    Länge in BIT umrechnen, ohne Akku 2 zu verändern
      L     #SourceLength; // Länge des UDT (Anzahl BYTE)
      SLW   3; // Länge des UDT (Anzahl BIT), (SLW 3 == *8)
//    Länge aktuellem (Index-1) multiplizieren
      *I    ; 
//    Offset [BIT] zu AR2 addieren
      +AR2  ; // AR2 zeigt jetzt auf aktuellen Datensatz im DB
//*** AR2 als neue Startadresse sichern      
      TAR2  #SourceStart; 
//*** Quellzeiger für SFC20 aufbauen
      LAR1  P##SourceSFC; 
      L     B#16#10; //Syntax-ID
      T     LB [AR1,P#0.0]; 
      L     B#16#2; //Datentyp Byte
      T     LB [AR1,P#1.0]; 
      L     #SourceLength; //Anzahl von Datentyp
      T     LW [AR1,P#2.0]; 
      L     #SourceDB; //Nummer des DB
      T     LW [AR1,P#4.0]; 
      L     #SourceStart; //Bereichszeiger
      T     LD [AR1,P#6.0]; 
//*** AR2 auf Zieldatenbereich
      L     P##DestData; 
      LAR2  ; 
//*** ANY-Pointer zerlegen
      L     W [AR2,P#2.0]; // Anzahl von Datentyp
      T     #DestLength; 
      L     W [AR2,P#4.0]; // Nummer des DB
      T     #DestDB; 
      L     D [AR2,P#6.0]; // Bereichszeiger = Startadresse
      T     #DestStart; // Startadresse im DB = 1. Datensatz
//*** Adressregister AR2 auf Bereichszeiger
      L     #DestStart; // Bereichszeiger = Startadresse 1. Datensatz
      LAR2  ; 
//*** Offset zu AR2 addieren
      L     #DestIndex; // Nummer des aktuellen Index (1..n)
      L     1; // beim 1. Datensatz ist Offset=0
      -I    ; // Nummer des aktuellen Index (0..n-1)
//    Länge in BIT umrechnen, ohne Akku 2 zu verändern
      L     #DestLength; // Länge des UDT (Anzahl BYTE)
      SLW   3; // Länge des UDT (Anzahl BIT), (SLW 3 == *8)
//    Länge aktuellem (Index-1) multiplizieren
      *I    ; 
//    Offset [BIT] zu AR2 addieren
      +AR2  ; // AR2 zeigt jetzt auf aktuellen Datensatz im DB
//*** AR2 als neue Startadresse sichern      
      TAR2  #DestStart; 
//*** Zielzeiger für SFC20 aufbauen
      LAR1  P##DestSFC; 
      L     B#16#10; //Syntax-ID
      T     LB [AR1,P#0.0]; 
      L     B#16#2; //Datentyp Byte
      T     LB [AR1,P#1.0]; 
      L     #DestLength; //Anzahl von Datentyp
      T     LW [AR1,P#2.0]; 
      L     #DestDB; //Nummer des DB
      T     LW [AR1,P#4.0]; 
      L     #DestStart; //Bereichszeiger
      T     LD [AR1,P#6.0]; 
//*** Den Datensatz kopieren
      CALL "BLKMOV" (
           SRCBLK                   := #SourceSFC,
           RET_VAL                  := #RET_VAL_SFC,
           DSTBLK                   := #DestSFC);
//***************************************************************************************************
// Ende
//***************************************************************************************************
//*** AR1-Register wiederherstellen
      LAR1  #AR1_Temp; 
      BE    ; 
END_FUNCTION
 
Zurück
Oben