Wertübergabe eines UDT an einer Funktion in SCL

Guten Morgen,

ich hab den Fehler jetzt etwas eingegrenzt. Die Wertübergabe mit BOOL scheint jetzt soweit zu funktionieren, aber bei der Übergabe mit DINT oder TIME gibt es noch ein Problem. Meine Function sieht im Moment so aus:
Code:
[COLOR=black][FONT=Verdana]FUNCTION MYFunctionDINT : BOOL  [/FONT][/COLOR]
[FONT=Verdana][COLOR=black]VAR_INPUT[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] TemptUDT:GlobalUDT;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] Array1 :DINT;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]END_VAR  [/COLOR][/FONT]
[FONT=Verdana][COLOR=black]VAR_IN_OUT     [/COLOR][/FONT]
[FONT=Verdana][COLOR=black] Array2 :DINT;[/COLOR][/FONT]
[COLOR=black][FONT=Verdana] Array3  :DINT[/FONT][/COLOR]
[COLOR=black][FONT=Verdana] DINT1   :DINT;[/FONT][/COLOR]
[FONT=Verdana][COLOR=black]END_VAR[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]BEGIN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option1 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array2 :=DINT1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option2 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array3  :=DINT1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;    [/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option3 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     DINT1   :=Array2;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option4 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     DINT1    := Array1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array2   := Array1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] MYFunctionDINT:=(Array2 <> DINT1);[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]END_FUNCTION[/COLOR][/FONT]

Wenn ich jetzt an Array2 irgendeinen Wert des Arrays im FB übergebe mit dem Index größer 1, also z.B. MYArray[3] funktioniert das ganze so wie es soll. Bei MYArray[1] funktioniert die Option1, also die Übergabe vom DINT1 nach Array2 nicht, der Rest aber schon. Wenn ich den ganzen Vorgang beobachte, kann man erkennen dass der Wert in der Funktion geändert wird, aber die Übergabe an dem Array im FB funktioniert nicht. Zum Schluss hab ich den Code noch folgendermaßen geändert:

Code:
[COLOR=black][FONT=Verdana]FUNCTION MYFunctionDINT : BOOL  [/FONT][/COLOR]
[FONT=Verdana][COLOR=black]VAR_INPUT[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] TemptUDT:GlobalUDT;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] Array1 :DINT;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]END_VAR  [/COLOR][/FONT]
[FONT=Verdana][COLOR=red][B]VAR_OUTPUT[/B][/COLOR][/FONT]
[FONT=Verdana][COLOR=red][B] Array2 :DINT;[/B][/COLOR][/FONT]
[FONT=Verdana][COLOR=red][B]END_VAR[/B][/COLOR][/FONT]
[FONT=Verdana][COLOR=black]VAR_IN_OUT         [/COLOR][/FONT]
[COLOR=black][FONT=Verdana] Array3  :DINT[/FONT][/COLOR]
[COLOR=black][FONT=Verdana] DINT1   :DINT;[/FONT][/COLOR]
[FONT=Verdana][COLOR=black]END_VAR[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]BEGIN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option1 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array2 :=DINT1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option2 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array3  :=DINT1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;    [/COLOR][/FONT]
[FONT=Verdana][COLOR=black] IF TemptUDT.Option4 THEN[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     DINT1    := Array1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]     Array2   := Array1;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] END_IF;[/COLOR][/FONT]
[FONT=Verdana][COLOR=black] MYFunctionDINT:=(Array2 <> DINT1);[/COLOR][/FONT]
[FONT=Verdana][COLOR=black]END_FUNCTION[/COLOR][/FONT]

Dies funktioniert auch, aber da ich dann die Option3 nicht benutzen kann ist das keine endgültige Lösung.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
eine schlaue Antwort habe ich da jetzt gerade nicht ... :oops:
ich befürchte allerdings, dass das Problem jetzt aus dem aufrufenden FB kommt ...

Das Beste wäre, wenn du dein Werk immer komplett postest ...
 
Ich würde auf jeden Fall mal versuchen, nicht ein Element des Arrays zu übergeben, sondern dieses Element vorher an eine Temp-Variable des entsprechenden Typs übergeben und dann die Temp-Var an den FC legen.
 
Erstmal danke für eure Hilfe. Ich hab den Fehler jetzt auch gefunden. Ich übergebe die Arrays an die Funktion mit drei Indexvariablen. Jeweils eine für Array1, Array2 und Array3, wenn dieser Index gleich ist, dann ist z.B. Array1 = Array2 und dann funktioniert die Übergabe nicht.

Jetzt hätte ich noch eine "kleine" Erweiterung meines Programms geplant, vielleicht könnt ihr mir dabei auch noch mal helfen. Im Moment hab ich vier Funktionen, jeweils eine für BOOL, DINT, INT und TIME. Der Code sieht so aus wie das was ich oben gepostet hab. Nun ist mein Plan das ich aus diesen vier Funktionen eine mache die dann sämtliche Datentypen verarbeiten kann. Ist so was mit Variablen vom Typ ANY möglich? Im Moment weigert sich der Compiler bei der Zeile:
MYFunctionDINT:=(Array2 <> DINT1);
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
... das wäre mit dem ANY möglich. Du mußt diesen dann nur in deiner Funktion zerlegen und entsprechend auswerten um ann daraus wieder eine "greifbare" Variable zu machen. Dafür gibt es einen schönen Beitrag in der FAQ - ich habe da aber auch noch etwas, dass ich bei Bedarf posten könnte - das muss ich dann nur erst "rauskramen" ...
 
Wäre nett von dir, wenn du deine Sache mit dem Any-Zeiger posten könntest. Ich hab damit jetzt etwas rumgespielt, aber irgendwie klappt es nicht so, wie ich mir das vorstelle.
 
... klar ... kein Problem
Code:
FUNCTION FC399 : VOID
Title   = 'UP Any-Pointer zerlegen'  // UP Any-Pointer zerlegen
AUTHOR  : 'Larry'
VERSION : '0.1'

//     Bausteinparameter
VAR_INPUT
   // Eingangsparameter
   DatenQuelle : ANY ;
END_VAR

VAR_OUTPUT
   // Ausgangsparameter
   Daten_Mem : STRING [4] ;
   Daten_Typ : STRING [4] ;
   Daten_DB  : WORD ;
   Daten_Ptr : DWORD ;
   Daten_1W  : INT ;
   Daten_Len : INT ; 
//   Inhalt : INT ;
END_VAR

VAR_TEMP
   // temporäre Variablen
   hDatenQuelle : ANY ;
   xDatenQuelle AT hDatenQuelle : STRUCT
              ID_Code   : BYTE ;  // 10h für S7
              DataTyp   : BYTE ;
              Anzahl    : WORD ;
              DB_Nr     : WORD ;
              SpeicherPtr : DWORD ;
              END_STRUCT ;
   yDatenQuelle AT hDatenQuelle : STRUCT
              ID_Code   : BYTE ;  // 10h für S7
              DataTyp   : BYTE ;
              Anzahl    : WORD ;
              DB_Nr     : WORD ;
              Speicherbereich : ARRAY [0..3] OF BYTE ;
              END_STRUCT ;
END_VAR

// --------------------------------------------------------------------------------------
//     Anweisungsteil 
// --------------------------------------------------------------------------------------
 
BEGIN
   hDatenQuelle := DatenQuelle ;
   
   IF    xDatenQuelle.DataTyp = w#16#00 THEN Daten_Typ := 'Nil' ;   // Nil
   ELSIF xDatenQuelle.DataTyp = w#16#01 THEN Daten_Typ := 'X' ;     // Bool
   ELSIF xDatenQuelle.DataTyp = w#16#02 THEN Daten_Typ := 'B' ;     // Byte
   ELSIF xDatenQuelle.DataTyp = w#16#03 THEN Daten_Typ := 'Char' ;  // Char
   ELSIF xDatenQuelle.DataTyp = w#16#04 THEN Daten_Typ := 'W' ;     // Word
   ELSIF xDatenQuelle.DataTyp = w#16#05 THEN Daten_Typ := 'Int' ;   // Integer
   ELSIF xDatenQuelle.DataTyp = w#16#06 THEN Daten_Typ := 'DW' ;    // Double-Word
   ELSIF xDatenQuelle.DataTyp = w#16#07 THEN Daten_Typ := 'DInt' ;  // Double-Integer
   ELSIF xDatenQuelle.DataTyp = w#16#08 THEN Daten_Typ := 'Real' ;  // Real
   ELSIF xDatenQuelle.DataTyp = w#16#09 THEN Daten_Typ := 'Date' ;  // Date
   ELSIF xDatenQuelle.DataTyp = w#16#0A THEN Daten_Typ := 'TOD' ;   // Time-of-Day
   ELSIF xDatenQuelle.DataTyp = w#16#0B THEN Daten_Typ := 'Time' ;  // Time
   ELSIF xDatenQuelle.DataTyp = w#16#0C THEN Daten_Typ := 'S5T' ;   // S5Time
   ELSIF xDatenQuelle.DataTyp = w#16#0E THEN Daten_Typ := 'DT' ;    // Date-and-Time
   ELSIF xDatenQuelle.DataTyp = w#16#13 THEN Daten_Typ := 'Str' ;   // String
   END_IF ;
   IF    yDatenQuelle.Speicherbereich[0] = w#16#81 THEN Daten_Mem := 'E' ;   //Eingänge
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#82 THEN Daten_Mem := 'A' ;   // Ausgänge
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#83 THEN Daten_Mem := 'M' ;   // Merker
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#84 THEN Daten_Mem := 'DB' ;  // DB
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#85 THEN Daten_Mem := 'DI' ;  // Instanz-DB
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#86 THEN Daten_Mem := 'L' ;   // Lokaldaten
   ELSIF yDatenQuelle.Speicherbereich[0] = w#16#87 THEN Daten_Mem := 'LV' ;  // vorherige Lokaldaten
   END_IF ;
   Daten_DB  := xDatenQuelle.DB_Nr ;  
   Daten_Len := WORD_TO_INT (xDatenQuelle.Anzahl) ;
   Daten_Ptr := xDatenQuelle.SpeicherPtr AND dw#16#00FF_FFFF ;
   Daten_1W  := DWORD_TO_INT(SHR (IN:=Daten_Ptr , n:=3)) ;
// --------------------------------------------------------------------------------------
END_FUNCTION
Dieses Script ist einfach nur ein Zerlege-Script. Es hat weiter keinen Sinn. Ich denke aber, dass du es für Versuche und als Basis für Weiteres gut hernehmen kannst ...

Gruß
LL
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was ich nicht ganz kapiere ist, wie ich den Inhalt von einem Anyzeiger auf einen anderen übertrage. Ich nehme mal an dies würde in deinem Programm mit der "xDatenQuelle.SpeicherPtr" geschehen. Aber als ich das bei mir ausprobiert hab mit:

AnyPointer1.SpeicherPtr:=AnyPointer2.SpeicherPtr;

ist die SPS in stopp gewechselt und die entsprechende Fehlermeldung war dann DB 4103 nicht geladen.
 
... das geht so nicht ...

Du musst dir aus dem Ganzen wieder eine "richtige" Adresse "bauen".

Also z.B. :
Code:
if Daten_Mem = 'M" then myWord := MW[Daten_1W] ; end_if ;
Wenn du von einem Pointer auf den anderen übertragen willst dann könntest du auch Blockmove verwenden - das wäre dann deutlich schneller.

----------------

Ich glaube nicht, dass du auf diese Weise wirklich das erhälst, was du vorhast. Vielleicht solltest du einfach mal deine komplette "Aufgabenstellung" offen legen. Dann könnte man sich gemeinsam dazu etwas einfallen lassen ...

Gruß
LL
 
Ich hatte das auch mal probiert, also einen Inputparameter für unterschiedliche Variablen nutzen. Leider geht das, wenn überhaupt nur mit Any, denn der Parametertyp kann nicht zur Laufzeit Bool, Int oder Real sein. Ich hatte gemeint irgendwann genau das aber mal bei einem Siemens-Baustein gesehen zu haben, fand diesen aber nicht mehr, der war wohl auch nicht in AWL oder SCL programmiert worden! Hab das dann so gelöst, daß ich dem Baustein 3 Eingänge verpaßt habe und ihm dann mit einem 4. Eingang mitgeteilt habe, welchen er nutzen soll. War auch nicht so doll, denn mit einem Output hat man dann evtl. wieder das selbe Problem.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nochmal als Erklärung was ich überhaupt bezweckt habe.
Ich wollte mir ein einfaches Array-Handling basteln. Im Moment sieht das Programm so aus das ich fünf unterschiedliche IF Anweisungen hab und je nach dem Zustand der Variablen in meinem UDT wird die Entsprechende IF Anweisung aufgerufen und Daten werden innerhalb eines Arrays kopiert. Da ich dies mit mehren Arrays machen, werden die IF Anweisungen recht lang und blöd zu handeln. Nun war meine Idee, dass ich eine Funktion für jedes Array aufrufe. Dieser Funktion wird das UDT, sowie der allererste Array wert übergeben (z.B. MyArray[1]), außerdem noch weitere int Variablen die dann festlegen was kopiert werden soll (z.B. Index1 :=3, Index2:=6, daraus folgt dann MyArray[6]:=MyArray[3]). Mein Haupthindernis im Moment ist das ich den Inhalt auf dem der Anypointer zeigt, nicht vergleichen kann. Außerdem müsste ich dann noch die Adresse des Arrays je nach Index anpassen und dem Anypointer übergeben. Da der Umgang mit Pointern in Step7 meiner Meinung nach sehr zu wünschen übrig lässt, werden ich das Vorhaben wohl aufgeben. Da selbst wenn ich die Funktion irgendwie hin bekomme, sie wahrscheinlich so umfangreich und langsam ist das es nicht wirklich einen Vorteil bringt. Aber zumindest habe ich was daraus gelernt :rolleyes:.
 
Zurück
Oben