TIA Elemente in DB aufrufen

BaumimGarten

Level-1
Beiträge
63
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,
gibt es eine Möglichkeit die Elemente eines DBs wie in einem Array durchzugehen ?
Quasi mit einer For-Schleife einen index hochzuzählen und alle Elemente aufzurufen.
Ich will quasi ein DB mit einem Wert vergleichen, dabei soll er alle Elemente durchgehen und eine Anweisung ausführen wenn der Vergleich true ist.
Den einzigen Ansatz den ich hätte wäre mit indirekter Adressierung zuarbeiten und das Offsett immer weiter zählen. Hab aber ebenfalls auch keine Abbruchbedingung dafür im Kopf.

S7 1511
Tia 17
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Aber wenn ich zum Beispiel

For #i := 0 TO 50 DO
IF DB1 [#i] <> 4.0 //DB1 sind alles LReal
DB1 [2] := 0;
Else
Exit;
End_IF;
End_FOR;

sagt er für mir #i = ungültiger Datentyp (ist bei mir ein INT)
und bei 4.0 ungültige Variablendefinition in Datenbaustein
 
Moin,

Moment mal. Auf was willst Du denn zugreifen?

In Deinem DB legst Du ein Array an. Z.B. rValue array[0..50] of real

Verarbeiten dann so:

Code:
For #i := 0 TO 50 DO
       IF
           "DBxy".rValue[#i] <> 4.0          //DB1 sind alles LReal
       THEN
           "DBxy".rValue[2] := 0;
       Else
           Exit;
       End_IF;
End_FOR;

Nebenbei bemerkt könnte der Vergleich auf 4.0 ins leere laufen. Denn Dein Real-Wert hat wahrscheinlich nicht exakt 4.000000. Realwertvergleiche sollten nur mit >,<,>= oder <= gemacht werden. Ansonsten einen anderen Datentyp verwenden.

Komisch ist auch, dass Du ein Array-Element beschreibst anhand der Abfrage aller Array-Elemente. Das verstehe ich nicht.

VG

MFreiberger
 
okay also ich muss Zwangsweise ein Array erstellen und kann nicht auf die einzelnen Elemente im DB zugreifen?
Weil das war mein ursprünglicher Plan weil ich ein meine Array Quasi über ein UDT erzeuge und das UDT noch für weitere Sachen im Programm verwendet wird.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,

Es kommt halt darauf an, was Du machen willst.
Doch, Du kannst auf einzelne Elemente eines Arrays im DB zugreifen.
Du kannst auch die FOR-Schleife auf ein Array einer UDT anwenden.

"DB".UDT.Irgendwas.ArrayElement[#i]

Vielleicht mal ein Screenshot von Deinem DB? Dann könnte man konkreter helfen.

Und nochmal folgender Hinweis:
Nebenbei bemerkt könnte der Vergleich auf 4.0 ins leere laufen. Denn Dein Real-Wert hat wahrscheinlich nicht exakt 4.000000. Realwertvergleiche sollten nur mit >,<,>= oder <= gemacht werden. Ansonsten einen anderen Datentyp verwenden.

Komisch ist auch, dass Du ein Array-Element beschreibst anhand der Abfrage aller Array-Elemente. Das verstehe ich nicht.

VG

MFreiberger
 
Um einfach mal meine ganze Problematik Darzustellen.
Ich habe eine Datenbank mit verschiedenen Anweisungen, unteranderem eine Variable "Motor_sollwert"
Und bekomme auf die SPS ein JSON Objekt als String geschickt (z.b. {"Motor_sollwert":34.45}) diesen muss ich weiter verarbeiten.

Hauptproblem:
Ich benötige den Variablennamen "Motor_sollwert" als String um meinen schon aufgeteilten JSON (in "Motor_sollwert und in 34.45) mit diesem zu vergleichen und dann den Sollwert der Variable "Motor_sollwert" zu steuern.

Für diesen Vergleich zwischen dem gesendeten JSON und dem Variablennamen als String, muss ich Quasi meine gesamte Datenbank durch gehen um die passende Variable als String zu finden und seinen Wert zusetzen.
Durch mein UDT hat der Kunde die Möglichkeit seine benötigten Daten für seine Anlage selber zu parametrieren, wodurch ich "eigentlich" auch kein Array anlegen, da mein Datenbaustein auch verschiedene Datentypen hat.


Das einzige was ich machen könnte wäre ein Array aus meinem Datensatz aber da müsste ich dann auch noch den vergleich im UDT machen, wenn ich nur einen Wert bei einem Motor ändern will
 

Anhänge

  • DB.PNG
    DB.PNG
    50,1 KB · Aufrufe: 43
Zuletzt bearbeitet:
Das einzige was ich machen könnte wäre ein Array aus meinem Datensatz aber da müsste ich dann auch noch den vergleich im UDT machen, wenn ich nur einen Wert bei einem Motor ändern will
Ist eh' ne grausame Struktur in Deinem DB!
Da macht es IMHO ohnehin Sinn, mal aufzuräumen.
;)

Z.B.:
Code:
TYPE "typeMotor"
VERSION : 0.1
   STRUCT
      Cmd : Struct
         Emergency : Bool;
         Start : Bool;
      END_STRUCT;
      Val : Struct
         Target : LReal;
         Offset : LReal;
      END_STRUCT;
   END_STRUCT;

END_TYPE



DATA_BLOCK "gdbMotor"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
NON_RETAIN
   VAR
      Motor { S7_SetPoint := 'False'} : Array[0.."MOTOR_MAX"] of "typeMotor";   //  MAX_MOTOR = globale Konstante in PLC-Variablen - Tabelle
   END_VAR


BEGIN

END_DATA_BLOCK
1639501678326.png


Und dann z.B. die Verarbeitung:
Code:
FOR #i := 0 TO "MOTOR_MAX" BY 1 DO
    IF "gdbMotor".Motor[#i].Val.Target <> 4.0
    THEN
        "gdbMotor".Motor[#i].Val.Offset := 0.0;
    END_IF;
END_FOR;

Die einzelnen Motoren des Motor-Arrays kann man dann z.B. anstatt mit Zahlen auch wieder per "sprechender" Konstante ansprechen.


PS:
In diesem Motorenpendel findest Du noch ein praktisches/größeres Beispiel zu dieser Verarbeitung.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke für die Mühe!

Ist eh' ne grausame Struktur in Deinem DB!
Da macht es IMHO ohnehin Sinn, mal aufzuräumen.
Da stimme ich dir komplett zu, war auch nur ein schnell erstelltes Beispiel, was ungefähr auf meine Anwendung passt :)

Aber das ist auch tatsächlich recht nebensächlich, da der "Kunde" sein DB quasi selbst anlegen soll, um eine bessere Anpassung auf seine Anlage vorzunehmen. Aus diesen Grund funktioniert ja leider auch nicht das direkte Ansprechen der Variablen ist mein Problem.
Ich gib ihm zwar eine ungefähre Struktur an die Hand, wie er das DB anlegen soll (quasi mein UDT), aber er kann weitere Sachen hinzufügen oder ignorieren.

Man könnte zwar mit indirekter Adressierung arbeiten, aber man wüsste durch die "freie Gestaltung" des Kunden nicht welche Offsets man im Endeffekt wiederfindet.
Zum Beispiel der Kunde legt seinen DB genauso an wie bei dir, aber würde zusätzlich die Kühlung oder sonstiges bestimmen. Dadurch hättest du ja auch eine Verschiebung im Offset für die indirekte Adressierung oder nicht ?

Und ja sry ich weiß es ist recht nervig dem Kunden so viele Freiheiten zugeben, da es für mich deutlich umständlicher wird
 
Und ja sry ich weiß es ist recht nervig dem Kunden so viele Freiheiten zugeben, da es für mich deutlich umständlicher wird
Ja, warum wird das dann gemacht? Ich kann mir auch nicht vorstellen, dass die Mehrzahl der Kunden das will/kann.

Wäre es eine Möglichkeit dem Kunden eine UDT mit einem Mengengerüst mitzugeben und darin darf er sich austoben?
Die Stellen, an der die UDT verwendet wird müssen da sowieso aktualisiert werden und zur Übertragung an eine andere Struktur nutzt Du dann Serialize/Deserialize. Da sollte dann halt nur die Länge der Daten fix sein.

Was genau macht denn der Kunde mit den Daten, die von ihm in einer UDT strukturiert wurden?

VG

MFreiberger
 
Du wirst nicht darum herumkommen, daß Du Dir eine Struktur überlegst, wie Du allgemeingültig mit den Werten umgehen kannst.

Beispielsweise so als Pseudocode:
Code:
Struct Value
    Struct Cmd1
        Enabled        : BOOL;    // Es kann mit diesem Wert dieser Befehl ausgeführt werden
        ActionValue    : DINT;    // Vergleichswert, wann der Befehl ausgeführt werden soll
        Comparison    : INT;    // Ein Zahlenwert, der angibt, ob auf =/>/</>=/<= geprüft werden soll
        Action        : INT;    // Ein Zahlenwert, der eine vordefinierte Aktion angibt oder eine Verknüpfung mit einem Gerät z.B.
    End_Struct
    Struct Cmd2
        Enabled        : BOOL;    // Es kann mit diesem Wert dieser Befehl ausgeführt werden
        ActionValue    : DINT;    // Vergleichswert, wann der Befehl ausgeführt werden soll
        Comparison    : INT;    // Ein Zahlenwert, der angibt, ob auf =/>/</>=/<= geprüft werden soll
        Action        : INT;    // Ein Zahlenwert, der eine vordefinierte Aktion angibt oder eine Verknüpfung mit einem Gerät z.B.
    End_Struct
    Struct Value
        InUse         : BOOL;  // Dieser Wert ist eingestellt und soll im Programm benutzt werden
        RAW            : DINT;    // Eingelesener Rohwert
        Physical    : REAL;    // Umgerechnet auf Strom-/Spannungssignal
        Phys_Unit    : String(5); // Einheit mA / V
        InputType    : INT;    // Ein Zahlenwert, der den Eingangstyp der Karte angibt, über eine zugehörige Tabelle kann dann die Skalierung automatisch erfolgen
        Scaled        : REAL;    // Der umgerechnete Meßwert
        Scaled_Unit : String(5); // Einheit des Meßwerts, z.B. "°C"
        Name         : String;  // Name des Wertes, bspw. "Außentemperatur"
        Struct Scaling
            Factor    : REAL;    // Faktor zur Umrechnung des Meßwerts
            Offset    : REAL;    // Offset zur Umrechnung des Meßwerts
        End_Struct
    End_Struct
End_Struct

Du mußt dann natürlich im Programm irgendwelche Aktionen bereits vordefinieren: Motor startet/stoppt, Prozeß wird angestoßen/gestoppt, irgendetwas Sinnvolles.

Dann kannst Du diese Aktionen als Textliste im HMI hinterlegen und der Kunde kann die Aktionen auswählen, die passieren sollen, bei Vergleich des ankommenden Wertes mit dem hinterlegten Wert.
Ggf. kannst Du auch das Scaling oder die Strom-/Spannungswerte weglassen, wenn Du über den JSON schon fertige Werte bekommst.
Aber wenn ein Kunde sowas wünscht, würde ich es über so eine Struktur machen, die kannst Du dann als Array ablegen, so daß X Werte verarbeitet werden können. Und dann über eine Schleife diese Struktur verarbeiten.

Dann ist das alles anonym und der Kunde kann sich das einstellen, wie er das will.
Alles mit dem Hintergedanken: Die eingestellten Daten können verloren gehen und der Kunde hat keine unendlichen Freiheiten (dann muß er das Programm selber schreiben), sondern Freiheiten in dem Maße, wie Du sie vordefinierst. Und genau hier muß eine genaue Absprache mit dem Kunden erfolgen, was er wünscht und was benötigt wird.
 
Zurück
Oben