TIA Datentyp im FC Automatisch ändern

Canopus231171

Level-1
Beiträge
70
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Datentyp.jpg

Moin,

ist es möglich bei den lokalen Ausgängen, durch Vorgabe den Datentyp zu ändern. Sprich wenn Kunde für die Wertübergabe Dint haben möchte, dann soll durch Format_Ausgabe=1 die Outputwerte in DINT ausgegben werden, bei Vorwahl von Format_Ausgabe=2 Outputwerte in REAL.

Geht das überhaupt????
 
Dein Problem sollte sich mit Variant-Ausgängen lösen lassen (siehe angehängtes Bild mit SCL-Beispiel).
Je nachdem, welchen Datentyp dein Kunde dann am Ausgang anhängt, wird entsprechend reagiert.
Variant.jpg

ABER: die Typeof() und VariantPut()-Funktionen verhältnismäßig lahme Krücken - ich persönlich würde eher 2 SCL-Bausteine mit verschiedenen Datentypen schreiben und die implizite Datentypkonvertierung von TIA geschickt ausnutzen.
Das könnte dann z.B. so aussehen:
Impl.jpg
hier ist lediglich die Deklaration unterschiedlich (und die Skalierung des Ausgangs), der Code bleibt aber gleich

lg
 
Meines Wissens geht das nicht bei S7-1200.
Und spätestens beim beschalten der FC-Ausgänge würdest Du ein Problem bekommen, daß da der Ausgang und die anzuschaltenden Variablen den selben Datentyp haben müssen. Der Editor kann nicht wissen, welcher Datentyp das zur Laufzeit sein wird.
Aufwendige und daher nicht zu empfehlende Möglichkeiten:
- irgendeinen "Dummy"-Datentyp übergeben und danach in den Zieltyp kopieren
- doppelt so viele Ausgänge mit beiden Datentypen vorsehen und beschalten und nur eine Sorte weiterverwenden

Ich würde 2 Versionen des FC erstellen.

Harald
 
Ich habe vergessen zu erwähnen das der Datentyp einmal zur IBN festgelegt wird dann nie wieder, der Kunde hat aber keine Möglichkeit in unsere Bausteine zu ändern..

Ich habe da auch schon ein bisschen mit Variant experimentiert. Das ist dabei Rausgekommen.
Code:
FUNCTION "SKAL" : Void
TITLE = 'scaling Peripherical Input words'
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : VoR
FAMILY : Peripher
NAME : W_skal_R
VERSION : 1.6
// Input will be converted directly from PEW to AUSG_REAL and AUSG_INT
// the Linearity is calculatet from UGR_IN to UGR_Out and OGR_IN to OGR_OUT
   VAR_INPUT 
      EING : Variant;   // Input. IF Word then PEW scal unipolar
      OGR_IN : Real;   // Upper limit input in format REAL
      UGR_IN : Real;   // Lower limit input in format REAL
      UGR_OUT : Real;   // Lower Output = Lower Input
      OGR_OUT : Real;   // Upper Output = Upper Input
      INT_FACTOR : Real;   // Faktor for the Integer Input (Normaly 10.0) means 13.7 REAL out is 137 for INT
      OBJ_AH : Bool;   // Manualoverride aktiv inaktiv
   END_VAR


   VAR_OUTPUT 
      FE : Bool;   // Fehler bei PEW Wandlung
   END_VAR


   VAR_IN_OUT 
      AUSG : Variant;   // Output scaled (Format REAL)
   END_VAR


   VAR_TEMP 
      OGR_IN_MAX : Bool;   // Input >= Upper limit input
      UGR_IN_MAX : Bool;   // Input <= Upper limit input
      EING_REAL : Real;   // Input im format REAL
      EING_WORD : Word;
      EING_INT : Int;
      LIMIT_R : Real;   // limited input (for calculation)
      LIM_X_UG : Real;   // temporary VAR for limiter
      LIM_X_OG : Real;   // Dito
      Status : Word;
      Ausg_REAL : Real;
      EING_REAL_PEW : Real;
   END_VAR




BEGIN
	CASE TypeOf(#EING) OF
	    Word: // Wenn Wort, dann behandeln wie einen Analogeingang
	        VariantGet(SRC := #EING,
	                   DST => #EING_WORD);
	        #Status := SCALE(IN := WORD_TO_INT(#EING_WORD), HI_LIM := #OGR_OUT, LO_LIM := #UGR_OUT, BIPOLAR := 0, OUT => #EING_REAL_PEW);
	        #FE := #Status <> 0;
	    Int: // Wenn Int dann in REAL wandeln
	        VariantGet(SRC := #EING,
	                   DST => #EING_INT);
	        #EING_REAL := INT_TO_REAL(#EING_INT);
	        #FE := 0;
	    Real: // Wenn Real dann So übernehmen
	        VariantGet(SRC := #EING,
	                   DST => #EING_REAL);
	        #FE := 0;
	    ELSE
	        #FE := 1;
	        #Status := 12; // Nicht unterstütztes Format
	END_CASE;
	
	(*sorting limits for calculation*) 
	IF #UGR_IN < #OGR_IN THEN
	    #LIM_X_UG := #UGR_IN;
	    #LIM_X_OG := #OGR_IN;
	    
	ELSIF #OGR_IN <= #UGR_IN THEN
	    #LIM_X_UG := #OGR_IN;
	    #LIM_X_OG := #UGR_IN;
	END_IF;
	
	(*input should be limited*)
	#LIMIT_R := LIMIT(MN := #LIM_X_UG, IN := #EING_REAL, MX := #LIM_X_OG);
	
	(*calculating limited data*)
	IF NOT #OBJ_AH THEN
	    IF NOT (TypeOf(#EING) = Word) THEN
	        #Ausg_REAL := ((#OGR_OUT - #UGR_OUT) / (#OGR_IN - #UGR_IN)
	        * #LIMIT_R
	        + (#OGR_OUT - (#OGR_OUT - #UGR_OUT)
	        / (#OGR_IN - #UGR_IN) * #OGR_IN));
	    ELSE
	        #Ausg_REAL := #EING_REAL_PEW;
	    END_IF;
	    
	    CASE TypeOf(#AUSG) OF
	        Real:
	            VariantPut(SRC := #Ausg_REAL,
	                       DST := #AUSG);
	        Int:
	            VariantPut(SRC := REAL_TO_INT(#INT_FACTOR * #Ausg_REAL),
	                       DST := #AUSG);
	    END_CASE;
	END_IF;
	
	
END_FUNCTION

Das funktioniert gut. Da bei dir aber schon alles per Laufzeit bekannt ist, kannst du auf Typeof grunsätzlich verzichten und das z.B. durch einen Int Eingang auswählbar machen.
Dann mit VariantPUT und VariantGET arbeiten.

mfG René
 
Uebrigens 1000 Durchläufe des Bausteins ohne die Variant funktion also direkt als REal deklarierte Ein und Ausgänge dauern in einer s7-1511 nicht ganz 10ms
1000 Durchläufe genau dieses bausteins mit Variant Ein und Ausgang und den CASE Abfragen. Benötigen 16ms in einer s7-1511
Um den Unterschied etwas zu verdeutlichen.
Wenn man an die Eingänge einen DB anhängt erhöht sich die Zykluszeit bei 1000 Durchläufen des Variant Bausteins auf 26ms.

Rein aus gwunder habe ich den Baustein ohne den SCALE inhalt auch in einer 1212C ausprobiert.
1000 Durchläufe des Bausteins ohne die Variant funktion brauchen da 35ms.
mit Variant funktion optimiertes REAL DB Array angehängt brauchen 70ms.

Ich würde mich jetzt soweit ausdem Fenster lehnen und sagen Variantarbeiten (VARIANT PUT/GET TYPEOF) brauchen ca 50% mehr Zeit wie die einfache Zuweisung.
Eher Vernachlässigbar.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Man lernt nie aus....

Mal direkt paar Fragen: Wie verschaltet man Variant-Ausgänge von FC (also "aussen" beim Aufruf)? Müssen die angeschalteten Variablen vom Typ Variant sein? Oder kann man direkt REAL-Variablen anschalten? Woher weiß der KOP/FUP/SCL-Editor welche Datentypen angeschaltet werden dürfen? Kann der FC ermitteln welchen Typ die aussen angeschaltete Variable hat? Werden Variant-Ausgänge von FC irgendwie initialisiert? Was passiert, wenn ein unerwarteter Datentyp angeschlossen wird und der FC dem Ausgang dann nichts zuweist?

Harald
 
Offenbar funktionieren Variant Eingänge wie ANY. Also reine Pointer. Die angehängte Variable wird nicht verändert durch den Aufruf des Bausteins.
Die angehängte Variable kann direkt eine REAL sein oder halt INT oder was auch immer. Bei dem Baustein den ich oben gepostet habe, werte ich ja auch nur grad die typischen Grundtypen aus. Also ich erkenne wenn ein WORD, ein INT oder ein REAL dranhängt und verarbeite entsprechend.
Viel Cooler wirds dann mit Complexen datentypen also UDTs. Die kann man per Type_of auch erkennen. So könnte man z.B. einen Baustein bauen der erkennt ob jetzt ein Anwenderdatentyp vom TYP Ampel oder vom Typ Ampel_mit_Reservelampe angehängt sind. die haben ja dann z.B verschieden viele Variablen im Typ. Oder Der Baustein muss anders damit umgehen. Oder beides.

Ich hab noch irgendwo so ein Beispiel rumliegen. Ich poste das später mal.

Falscher Datentyp wird am Eingang nicht erkannt. Durch Typ_of auswertung liegt das in der Verantwortung des Programmierers das auszuwerten.
Kein Datentyp anhängen wird vom Compiler erkannt. (Any halt)

mfG René
 
Hier noch etwas abgespeckt Typauswertung mit Anwenderdatentypen.
Code:
TYPE "SIG_HW_FLS"
VERSION : 0.1
   STRUCT
      DI : Struct
         Signal_nicht_Ein : Bool;
         Reservelampe_Ein : Bool;
         Stromueberwachung : Bool;
      END_STRUCT;
      DA : Struct
         gruen : Bool;
         rot : Bool;
         links : Bool;
         rechts : Bool;
      END_STRUCT;
   END_STRUCT;


END_TYPE


TYPE "SIG_HW_VA"
VERSION : 0.1
   STRUCT
      DI : Struct
         Stromueberwachung : Bool;
      END_STRUCT;
      DA : Struct
         gruen : Bool;
         rot : Bool;
         gelb : Bool;
      END_STRUCT;
   END_STRUCT;


END_TYPE


TYPE "typSignal"
VERSION : 0.1
   STRUCT
      Soll : Int := -1;   // Sollwert für Signal
      Ist : Int;   // Istwert von Signal
      Alert : Array[0..10] of Bool;
   END_STRUCT;


END_TYPE


FUNCTION "OBJ_Sig" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      HW : Variant;
   END_VAR


   VAR_IN_OUT 
      Sig : "typSignal";
   END_VAR


   VAR_TEMP 
      FLS : "SIG_HW_FLS";
      VA : "SIG_HW_VA";
   END_VAR




BEGIN
    CASE TypeOf(#HW) OF
       SIG_HW_FLS: 
           VariantGet(SRC:=#HW,
                      DST=>#FLS);
           #Sig.Alert[2] := #FLS.DI.Reservelampe_Ein;
           #Sig.Alert[3] := #FLS.DI.Signal_nicht_Ein;
           #Sig.Alert[4] := NOT #FLS.DI.Stromueberwachung;
           CASE #Sig.Soll OF
               1:
                   #FLS.DA.gruen := true;
                   #FLS.DA.rot := false;
                   #FLS.DA.links := false;
                   #FLS.DA.rechts := false;
               2:
                   #FLS.DA.gruen := false;
                   #FLS.DA.rot := false;
                   #FLS.DA.links := true;
                   #FLS.DA.rechts := false;
           END_CASE;
                   VariantPut(SRC:=#FLS,
                              DST:=#HW);
                   
               SIG_HW_VA: 
           VariantGet(SRC:=#HW,
                      DST=>#VA);
           #Sig.Alert[2] := NOT #VA.DI.Stromueberwachung;
           CASE #Sig.Soll OF
               1:
                   #VA.DA.gruen := false;
                   #VA.DA.rot := true;
                   #VA.DA.gelb := false;
               2:
                   #VA.DA.gruen := false;
                   #VA.DA.rot := true;
                   #VA.DA.gelb := true;
               3:
                   #VA.DA.gruen := TRUE;
                   #VA.DA.rot := false;
                   #VA.DA.gelb := false;
           END_CASE;
           VariantPut(SRC := #VA,
                      DST := #HW);
          
    END_CASE;
    
    
END_FUNCTION
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde mich jetzt soweit ausdem Fenster lehnen und sagen Variantarbeiten (VARIANT PUT/GET TYPEOF) brauchen ca 50% mehr Zeit wie die einfache Zuweisung.
Eher Vernachlässigbar.

Das Problem kenne ich auch. Ich wollte aber trotzdem gerne auch den Variant zur Erkennung nutzen. Habe nun den Kompromiss gefunden und lasse nur einmal beim ersten OB1 Zyklus die Datentypen auswerten.
 
Unbenannt1.JPGUnbenannt2.JPGUnbenannt3.JPG

Nochmal zu dem Thema zurück zu kommen,

kann mir mal jemand verraten wie ich nun die Werte aus Projekt in den Kundenbereich kopieren kann??? Entweder Kunde Real oder DINT.
 
Schau dir mein Beispiel nochmal an. Typeof real oder INT ist nicht nötig das sind Schlüsselwörter. Getvariant und putvariant machen das was du mit move versuchst.



Gesendet von iPhone mit Tapatalk
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nochmal zu dem Thema zurück zu kommen,

kann mir mal jemand verraten wie ich nun die Werte aus Projekt in den Kundenbereich kopieren kann??? Entweder Kunde Real oder DINT.
Da es bei Dir sehr viele Werte betrifft, welche ihren Datentyp ändern sollen (auch viele interne Variablen), und weil es nicht damit getan ist, einen DINT einfach auf eine REAL-Variable zu kopieren, nochmal der Tipp: Erstelle 2 Versionen des FC und gut ist's.

Harald
 
Zurück
Oben