TIA Die Länge eines festen Arrays im UDT definieren und in SCL heraus bekommen

Marty2000

Level-2
Beiträge
23
Reaktionspunkte
9
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe einen komplexen PLC-Datentyp (UDT), der unter anderem mehrere Arrays beinhaltet, die alle gleich lang sein sollen. Die Länge ist fix, sollte aber in einem anderen Projekt geändert werden können. Klassische Lösung wäre, die Arraylänge über globale Anwenderkonstanten zu definieren. Das ist aber nicht gewünscht, da der PLC-Datentyp, mitsamt einem FB, in die Bibliothek unter Typen versionskontrolliert abgelegt werden soll. Beim freigeben der Version wird davor gewarnt, das zu tun. Gibt es dann einen anderen Weg, die Länge der Arrays einheitlich zu machen? Eine Anwenderkonstante im PLC-Datentyp festlegen, geht scheinbar nicht. Eine Anwenderkonstante von einem FB im PLC-Datentyp zu benutzen, geht wohl auch nicht.

Zweites Problem. Diese "feste" Array-Längenangabe würde ich gerne im FB in SCL wissen (und nutzen für Schleifen), kann diese aber mit UPPER_BOUND nicht abfragen, da diese Abfrage angeblich nur mit variablen aber nicht mit festen Arrays funktioniert. Wie komme ich an die Arraylänge?
 
Im FB kannst Du ein Array of UDT beliebiger Länge anlegen und dann die aktuellen Grenzen im FB abfragen:
Code:
   VAR_IN_OUT
      MyUDT         : Array [*] of "typeUDT";
   END_VAR


   VAR_TEMP
      Bound         : Struct   // array borders
         L          : DInt;    //     first
         U          : DInt;    //     last
      END_STRUCT;
   END_VAR


BEGIN
        #Bound.L := LOWER_BOUND(ARR := #MyUDT, DIM := 1);                               // lower bound of array
        #Bound.U := UPPER_BOUND(ARR := #MyUDT, DIM := 1);                               // upper bound of array
...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hab hier einen Code der UDT's aus Arrays kopieren kann, da ist die Längenermittlung des UDT drin.

Code:
FUNCTION m7_udtCopyArray : VOID
    TITLE = 'udtCopyArray'

// ACHTUNG:
//   trotz UC Aufruf durch den SCL-Kompiler können keine Daten von/zu TEMP-Variablen erfolgen.
//   Daten stimmen in diesem Fall nicht!
//
// ==============================================================================
// udtCopyArray:
//
//    Kopiert UDT's aus Arrays, die Datenlänge des UDT wird automatisch ermittelt.
//    Anpassungen der Datenlänge nach Änderungen an den UDT's entfällt somit.
//   
//    Achtung Array bzw. Speichergrenzen werden nicht überprüft.
//    Gegebenenfalls, Indexangaben vorher auf Korrektheit prüfen bzw. limittieren!
//    Bei inkorrekten Indexangaben geht CPU in STOP.
//   
//    Verwendung: Verwaltung von Datensätzen wie Rezepturen, Betriebsdaten,
//    Positionsdaten usw. in der Steuerung.
//   
//    Kopiert wird von/zu: DB, statischen Lokaldaten im Instanz-DB
//    (Multinnstanzfähig, ohne zus. Adresskorrektur, da Step7 bei Verwendung von
//    Instanzdaten bei UDT's automatisch als Quelle [#84] DB und Nr. mit korrekter
//    Adress angibt statt nur DI [#85])
//   
//    Nicht kopiert wrid von/zu lokalen Daten (TEMP), da vor- vorherige Lokaldaten
//    benötigt werden (S7 aber nur vorherige Lokaldaten unterstützt)
//   
//    [IN]
//    srcUdtArray : Anypointer auf den ersten UDT im Quell-Array
//    srcIndex    : Index des Quell-UDT im Array, beginnend bei 0
//    destUdtArray: Anypointer auf den ersten UDT im Ziel-Array
//    destIndex   : Index des Ziel-UDT im Array, beginnend mit 0
// ==============================================================================
//
// DATE: 10/2007
//
// CHANGELOG:
// ------------------------------------------------------------------------------
// DATE         NAME        DESCRIPTION
// ------------------------------------------------------------------------------
// 20.03.2017   S.Maag      Converted AWL Version m7b_udtCopyArray to SCL
// ------------------------------------------------------------------------------

    VERSION : '3.0'
    AUTHOR  : 'S.Maag'
    FAMILY  : 'Maagic7'

VAR_INPUT
    srcUdtArray : ANY;  // AnyPointer to first UDT in SourceArray
    srcIndex : INT;     // Index of Source_UDT in the Array[0..x]
    destUdtArray : ANY; // AnyPointer to first UDT in DestinationArray
    destIndex : INT;    // Index of Destination_UDT in the Array[0..x]
END_VAR

VAR_OUTPUT
    BLKMOVE_RET : INT;   
END_VAR

VAR_TEMP
 
    anySRC : ANY;
    anyDEST :ANY;
  
    p_anySRC AT anySRC: STRUCT  // Mit dem  AT Befehl wird der gleiche Bereich in einer anderen Form définiert
       ID  : WORD;  // ID für ANY (1002 hex = es wird mit Bytes gearbeitet)
       REP :INT;    // Wiederholungsfaktor
       DBNo : INT;   // DB der im ANY Pointer benutzt wird ANY
       PTR : DWORD; // Pointer Doppelwort um den Angfang des Datenbereichs und den Datentyp zu definieren (84hex = DB Datentyp)
    END_STRUCT;
 
     p_anyDEST AT anyDEST: STRUCT  // Mit dem  AT Befehl wird der gleiche Bereich in einer anderen Form définiert
       ID  : WORD;  // ID für ANY (1002 hex = es wird mit Bytes gearbeitet)
       REP :INT;    // Wiederholungsfaktor
       DBNo : INT;   // DB der im ANY Pointer benutzt wird ANY
       PTR : DWORD; // Pointer Doppelwort um den Angfang des Datenbereichs und den Datentyp zu definieren (84hex = DB Datentyp)
    END_STRUCT;
      
    tmpDataPointer : DWORD;
    
END_VAR

BEGIN
    anySRC := srcUdtArray;
    anyDEST := destUdtArray;
    
    tmpDataPointer := DINT_TO_DWORD(DWORD_TO_DINT(p_anySRC.PTR AND DW#16#FFFFFF) + INT_TO_DINT(p_anySRC.REP) * INT_TO_DINT(srcIndex)* 8);
    p_anySRC.PTR := (p_anySRC.PTR AND DW#16#FF000000) OR tmpDataPointer;
 
    tmpDataPointer := DINT_TO_DWORD(DWORD_TO_DINT(p_anyDEST.PTR AND DW#16#FFFFFF) + INT_TO_DINT(p_anyDEST.REP) * INT_TO_DINT(destIndex) * 8);
    p_anyDEST.PTR := (p_anyDEST.PTR AND DW#16#FF000000) OR tmpDataPointer;
  
    BLKMOVE_RET := BLKMOV(srcblk:= anySRC, dstblk:= anyDEST); // SFC20
    OK := TRUE; // ENO
END_FUNCTION
 
Im FB kannst Du ein Array of UDT beliebiger Länge anlegen und dann die aktuellen Grenzen im FB abfragen:
#Bound.L := LOWER_BOUND(ARR := #MyUDT, DIM := 1); // lower bound of array
#Bound.U := UPPER_BOUND(ARR := #MyUDT, DIM := 1); // upper bound of array
...
Wie bereits erwähnt ist der Befehl UPPER_BOUND, aber auch LOWER_BOUND, hier nicht möglich. Der Editor sagt das auch ganz deutlich: "Nur ARRAYs mit variablen Grenzen sind zulässig" .
1761056828879.png
 

Anhänge

  • 1761056792548.png
    1761056792548.png
    4,9 KB · Aufrufe: 8
Ich hab hier einen Code der UDT's aus Arrays kopieren kann, da ist die Längenermittlung des UDT drin.

// Achtung Array bzw. Speichergrenzen werden nicht überprüft.
// Gegebenenfalls, Indexangaben vorher auf Korrektheit prüfen bzw. limittieren!
// Bei inkorrekten Indexangaben geht CPU in STOP.
UDT-Länge wird ermittelt, ja. Aber es steht ja drin, dass Arraygrenzen selbst geprüft werden müssen, sonst CPU-STOP.

Außerdem brauche ich die Array-Länge, nicht die Speichergröße, und die wird NICHT ermittelt.
 
Du kannst dir einen Hilfs-FC erstellen. Dem übergibst du das Array als "Array [*]" und gibst die Länge zurück.
Stimmt! Gute Idee, müsste klappen. Aber dann müsste ich den FC auch noch mit in die Bibliothek legen und immer mit schicken und erklären, warum da noch ein FC mit dazu gehört .... noch nicht ganz optimal.... :unsure:
 
Variable Arraygrenzen, die direkt im Funktionsbaustein deklariert sind und gleichzeitig bibliotheksfähig sein sollen, stellen einen Widerspruch in sich dar. Oder habe ich mich zwischen den Zeilen verlesen?

Lege diese Daten in einem lokalen DB ab und übergib sie als Parameter an den Baustein. Dann funktionieren auch variable Arraygrenzen.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Dann hast du ja bei jeder Anwendung neue Typen / Versionen wenn man das UDT für jede Anwendung anpassen muss
Wenn die Arrays immer gleich lang sein müssen, könnte man die ja auch in ein Array of UDT zusammenfassen und die sonstigen Daten in ein 2. UDT_Sonstiges

Dann kann in der Anwendung das UDT_Sonstiges und das Array of UDT als getrennte Variablen anlegen und so an den FB übergeben dann funktioniert das im FB mit Array[*] und Upper/lower Bound zum auslesen. Dann müsste der Anwender keine Typen ändern / neue Version erstellen.

Ich denke man wird nicht drum herum kommen die Arrays getrennt an den FB zu übergeben wenn man die Länge auslesen möchte.
Die alternative wäre dann wohl
Array1 [*] of UDT?
Array2 [*] of UDT?
..
UDT_Sonstiges
an den FB zu übergeben

Dann könnten die Arrays auch (Optional) unterschiedliche Längen haben
für die Deklaration im DB kann man ja noch ein UDT_gesamt darüber legen, das wird dann nicht direkt im FB verwendet kann also durch die Änderung der Array Grenzen angepasst werden ohne neue FB Versionen zu erstellen.
 
Zurück
Oben