TIA Optimierter Bausteinzugriff S7-1500

Zuviel Werbung?
-> Hier kostenlos registrieren
Ich mache es über Slice-Zugriff:

Alarm DB:

Anhang anzeigen 31873

OB100:

Code:
//Anzahl Störmeldungen

      CALL  "T0_Anzahl_Positionen_ermitteln"
         ArraySize :="O2_DB_Stoermeldungen".ErrNrMax
         myArray   :="O2_DB_Stoermeldungen".Error_Msg

      L     "O2_DB_Stoermeldungen".ErrNrMax
      L     2
      /I
      L     16
      *I
      T     "O2_DB_Stoermeldungen".ErrNrMax

ALARM Afruf:

Code:
      L     2                    //Alarm Nummer HMI
      T     #ErrID

      CALL  "O8_ALARM_QUITT"
         Error_Delete  :=#Fehler_ignorieren
         EVENT         :=#Bandriss
         EVENT_NEGIERN :=FALSE
         RESET         :=#Reset_Stoerungen
         ErrMax        :="O2_DB_Stoermeldungen".ErrNrMax
         ErrNr         :=#ErrID
         HmiErrSet     :="O2_DB_Stoermeldungen".HMIErrSet[#ErrID]
         HmiQuit       :="O2_DB_Stoermeldungen".HMIQuitt[#ErrID]

ALARM FC:

Code:
FUNCTION "O8_ALARM_QUITT" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      Error_Delete : Bool;
      EVENT : Bool;
      EVENT_NEGIERN : Bool;
      RESET : Bool;
      ErrMax : Int;
      ErrNr : Int;
   END_VAR

   VAR_IN_OUT 
      HmiErrSet : Bool;
      HmiQuit : Bool;
   END_VAR

   VAR_TEMP 
      SPSQuit : Bool;
      HmiErrWord : Int;
      HmiErrBit : Int;
      SPSQuitWord : Int;
      SPSErrBit : Int;
   END_VAR


BEGIN
    //Bit Nummer eliminieren, Array (Word) Nummer gewinnen
    //+1 ist weil der Index von 1..10 im Array angelegt ist.
    //Im Panel ist dem Bit "0" die ID 1 zugeornet, daher die Korrektur Errnr -1.
    //Das Anlegen von 1 - 160 entspricht der Fehler ID 1 - 160 im Panel.
    
    #HmiErrWord := SHR(IN := (#ErrNr - 1), N := 4) + 1;
    
    //Error ID durch 16 (Bits in Word) teilen, Rest = Bitnummer
    
    #HmiErrBit := (#ErrNr - 1) MOD 16;
    
    //Zweite Hälfte von Error Array ist SPS Quittirbereich
    
    #SPSQuitWord := SHR(IN := (#ErrNr + #ErrMax - 1), N := 4) + 1;
    #SPSErrBit := #HmiErrBit;
    
    
    IF NOT #Error_Delete THEN
        
        //Error vom SPS zurücksetzen
        //
        IF #RESET THEN
            #SPSQuit := true;
        ELSE
            #SPSQuit := false;
        END_IF;
        
        
        //Quittierbit vom HMI zurücksetzen
        //Quittierbit wird zurückgesetzt wenn Quittierbit= 1 und Error = 0 oder im Erste_Zyklus
        
        IF #HmiQuit AND NOT #HmiErrSet THEN
            
            CASE #HmiErrBit OF
                0:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X0 := false;
                1:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X1 := false;
                2:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X2 := false;
                3:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X3 := false;
                4:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X4 := false;
                5:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X5 := false;
                6:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X6 := false;
                7:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X7 := false;
                8:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X8 := false;
                9:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X9 := false;
                10:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X10 := false;
                11:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X11 := false;
                12:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X12 := false;
                13:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X13 := false;
                14:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X14 := false;
                15:
                    "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X15 := false;
            END_CASE;
        END_IF;
        
        //Error setzen
        //Error wird vom OP oder SPS oder Erste Zyklus zurückgesetzt
        
        IF #EVENT XOR #EVENT_NEGIERN THEN
            #HmiErrSet := true;
        ELSIF #SPSQuit OR #HmiQuit THEN
            #HmiErrSet := false;
        END_IF;
        
        //Bits in Word
        
        CASE #HmiErrBit OF
            0:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X0 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X0 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X0;
            1:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X1 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X1 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X1;
            2:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X2 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X2 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X2;
            3:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X3 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X3 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X3;
            4:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X4 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X4 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X4;
            5:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X5 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X5 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X5;
            6:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X6 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X6 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X6;
            7:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X7 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X7 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X7;
            8:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X8 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X8 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X8;
            9:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X9 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X9 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X9;
            10:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X10 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X10 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X10;
            11:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X11 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X11 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X11;
            12:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X12 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X12 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X12;
            13:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X13 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X13 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X13;
            14:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X14 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X14 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X14;
            15:
                "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord].%X15 := #HmiErrSet;
                "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord].%X15 := #SPSQuit;
                #HmiQuit := "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord].%X15;
        END_CASE;
        
    END_IF;
     
    IF #Error_Delete THEN
        #HmiErrSet := false;
        #SPSQuit := false;
        #HmiQuit := false;
        "O2_DB_Stoermeldungen".Error_Msg[#HmiErrWord] := 0;
        "O2_DB_Stoermeldungen".HMI_Quit[#HmiErrWord] := 0;
        "O2_DB_Stoermeldungen".Error_Msg[#SPSQuitWord] := 0;
    END_IF;
    
END_FUNCTION

Klar, wir wissen ja wie das geht, aber durch die Slice-Zugriffe hast du keinen Textbezug zur Störmeldung.
Bei mit steht da "Störmeldungen".STM_128
Wenn ich das sehe, weiß ich genau, das ist Störmeldung 128, im HMI dort zu finden, in der SPS ebenfalls.
Wie siehst du das sofort? Das sollte doch der Vorteil von symbolischer Programmierung sein oder?
 
@vita-2002
Damit hast du aber genau erreicht, was Ralle nicht will
a) Du hast keinen Bezug mehr zwischen Störmeldebit in HMI und PLC (Vielleicht verschmerzbar)
b) Du hast keine wie auch immer gearteten Symbolischen Störbits mehr (Eigentlich nicht tolerabel)
c) Deine ganzen Störmeldebits sind überhaupt nicht mehr Querverweistauglich, da du nur Indirekt in deinem Array rumschweinelst.

In Summe folgt daraus:
Von allen möglichen Lösungen hast du dich in Punkto nachvollziehbarkeit für die schlechtest mögliche Variante entschieden.
 
Ich weiß es.
In Moment geht aber nicht anderes.
Da muss man entscheiden:

a) Nicht optimiert, übersichtlich.
b) Optimiert, aber mit oben beschriebenen Nachteilen.

Ich bin mir nicht mal sicher, ob die ganze Kopierrei und die Sclicezugriffe zum Schluß nicht mehr Zeit kosten, als der Zugriff auf einen nicht optimierten DB. Zumal hier nichts umkopiert wird (von optimiert nach nicht optimiert u. umgekehrt muß das eine Katastrophe sein).
 
Hallo!

Weils dazu passt:
Ich habe eine Automatisierungsaufgabe, die meine S7-1517 an ihre Grenzen bringt. Nun muss ich eine Kommunikationsverbindung über Softnet IE und OPC DA Server zu einem Fremdsystem aufbauen. Dazu müssen meine Kommunikationsbausteine zum OPC DA Server "nicht optimiert" = absolut adressiert sein. Die restliche Steuerung läuft auf "optimierter Zugriff".
Mit welchen Performanceeinbußen muss ich da rechnen?
Ist nur das schreiben der Kommunikations-DBs langsam oder läuft das komplette Programm langsamer?
Gibt es Tabellen oder Formeln um den Verlust berechnen zu können?

mfg mephisto
 
Ist nur das schreiben der Kommunikations-DBs langsam oder läuft das komplette Programm langsamer?
Gibt es Tabellen oder Formeln um den Verlust berechnen zu können?
Nur die Zugriffe sind langsamer... eine Berechnung erscheint schwer.

Hauptproblem ist dass die 1500 mit Intel-Notation (Little Endian Byte-Order) arbeitet und die 300 mit Motorola arbeitet.
Die nicht optimierten Bausteine sind in der Byteorder kompatibel zur 300 und damit muss die 1500 bei jedem Zugriff (lesen/schreiben) Byte-drehen.
Ein weiterer Punkt ist der Bit-Zugriff. Die 1500 verwendet ein volles Byte für ein Bit. Bei jedem Zugriff auf ein Bit im nicht optimierten DB wird immer das
volle Byte gelesen und das gewünschte Bit dann rausmaskiert....

Meiner Meinung ist dass der Hauptgrund für den angeprangerten Performance-Nachteil, positive Eigenschaften der opt. Dbs im Sinne von "Variablen im Speicher
optimal sortiert" halte ich für vernachlässigbar.

Im Kapitel 2.6 hier steht das alles ein wenig beschrieben.
https://support.industry.siemens.com/cs/de/de/view/90885040

Man kann nicht mal pauschal sagen dass opt. DB immer und überall schneller ist.
Hängt ganz davon ab wieviele Operationen benötigt werden um das selbe zu erreichen wenn keine Adressen zur Verfügung stehen.
Bei Standard-Operationen wird opt. aber wegen dem Byte-Gedrehe schneller sein.
Bei deiner 1517 wirst du dass für nen COM-DB aber nicht merken.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!

Den Programmierleitfanden kenn ich. Danke. Daraus geht aber auch nicht hervor um wieviel ich langsamer/schneller sein werde.
In meinem Fall habe ich einen DB mit einem Array[0..9999]of Real. Dieses Array möchte ich als FIFO beschreiben. Da hat er dann schon ganz schön damit zu tun in jedem Zyklus das Real Intel->Motorola und wieder retour zu wandlen. Deshalb hätte es mich interessiert.
Wenn aber nur der Zugriff auf diese Adressen langsamer ist, dann kann ich - denke ich - damit leben.
Ich hab mal was gehört von "Faktor 6-7" aber das waren Schlagworte der Siemens Verkäufer. Hat da vielleicht wer Unterlagen dazu?
Und wenn ich schon dabei bin: Gibt es in der 1500er wieder eine FIFO FUnktion? Die Elemente der 300er gibt's ja anscheinend nicht mehr.
 
Daraus geht aber auch nicht hervor um wieviel ich langsamer/schneller sein werde.
In meinem Fall habe ich einen DB mit einem Array[0..9999]of Real. Dieses Array möchte ich als FIFO beschreiben.
Eine zuverlässige Aussage wirst du wohl nur durch testen bekommen, mit der RUNTIME-Funktion könntest du den Unterschied sogar direkt messen.

Ich hab mal was gehört von "Faktor 6-7" aber das waren Schlagworte der Siemens Verkäufer. Hat da vielleicht wer Unterlagen dazu?
Im Worst-Case durchaus möglich, in Realität hab ich über das komplette Programm nie mehr als 1,5 gesehen. Pauschalaussagen sind schwer.
Aber wie gesagt, betroffen sind definitiv nur Codeteile die mit den nicht optimierten Daten arbeiten.
 
In meinem Fall habe ich einen DB mit einem Array[0..9999]of Real. Dieses Array möchte ich als FIFO beschreiben.
Was willst Du mit den Daten im FIFO anstellen? Den FIFO nach Werten durchsuchen oder einfach nur Werte am Ende reinstecken und vorne auslesen? Wenn Du den einfachen FIFO mit Schreibzeiger und Lesezeiger verwaltest, dann muß nicht umgespeichert werden und es kommt nicht auf die Größe des FIFO an. Und ich behaupte, die Verwaltung des FIFO ist in optimiert oder nicht optimiert ziemlich gleich schnell. Wie RONIN schrieb: ausprobieren und selber mit RUNTIME nachmessen.

Harald
 
@Mephisto: Könntest du uns noch einen Pseudo-Codeschnipsel dazu liefern. Hätte gerne eine Idee wie genau der Zugriff in deinem Beispiel aussah.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!

War nicht viel, ich habe einen db, indem es ein array mit 10000 dint gibt.
Ins erste Arrayelement schreibe ich den Wert, danach verschiebe ich mit MOVE_BLK die ersten 9999 Arrayelemente um 1.
 
Da hast Du quasi nur die Zugriffszeit des Arbeitsspeichers verglichen - da muß ja das gleiche bei rauskommen. Falls nicht, dann wäre das ein Problem der Firmware der CPU.

Du könntest den Test mal mit ARRAY OF BYTE und ARRAY OF BOOL machen und dann um 1 Byte bzw. 1 BOOL verschieben.

Harald
 
Nun ja, immerhin hab ich dadurch gesehen, dass er einfach das DINT, also die 4Byte kopiert, ohne eine Koversion von Big/Little Endian durchzuführen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So Leute,

Extra für euch:
Ich hab den gleichen Versuch wiederholt. Nur hab ich jetzt zusätzlich noch jweils ein Bitarray mit 10.000 Elementen verschoben. Hier sollte sich der Unterschied besonders gravierend auswirken.
Und siehe da:
optimiert: 10-14µs
absolut: 446-456µs
 
Nun ja, immerhin hab ich dadurch gesehen, dass er einfach das DINT, also die 4Byte kopiert, ohne eine Koversion von Big/Little Endian durchzuführen.
Warum auch sollte da die Byteorder eine Rolle spielen? Die ist dafür doch völlig egal.

ein Bitarray mit 10.000 Elementen verschoben. Hier sollte sich der Unterschied besonders gravierend auswirken.
Und siehe da:
optimiert: 10-14µs
absolut: 446-456µs
Ein BOOL-ARRAY umspeichern ist nach m.M. total praxisfremd. Welcher Programmierer tut schon sowas?
Optimiert: Warum dauert das Umspeichern von 10.000 BOOL 25-30% länger als das von 10.000 DINT?

Harald
 
Hallo!

Lesen hilft.
Array of Bool: Um den Unterschied zwischen den Speichertechniken herauszukitzeln. Absolut adressiert: 1Bool = 1 Bit, Optimiert; 1Bool = 1 Byte.
Mir ist durchaus bewuss, dass das in der Praxis keiner machen wird. Wobei ich schon Schieberegister mit mehr als 64Bit benötigt habe.
25-30% länger: Weill ds umkopieren der BOOL ZUSÄTZLICH zu den DINT gemacht wurde.
 
Zurück
Oben