TIA S7-1500 spukhaftes Verhalten, Lokaldatenstackproblem?

Zuviel Werbung?
-> Hier kostenlos registrieren
@Mephisto:
Für Sendedaten würde ich keinen "optimierten" Speicher verwenden, weil Sendedaten immer eine bestimmte Struktur einhalten müssen, die in "optimiertem" Speicher aber umgewürfelt wird - es sei denn die Sendedaten sind als BYTE-Array strukturiert.

Genau das, was Harald da schreibt, war mein Ansatz. Ich bin der Meinung, habe dazu aber gerade keine Quellen (nur deine Fehler-Beschreibung), dass das genau mit dem Phänomen des "optimierten Speichers" zusammen hängt - und zwar auch für den BlockMove.
Wie das wiederum mit dem "externen DB" zusammen hängt erklärt sich für mich gerade noch nicht - außer vielleicht, dass hier die möglicherweise von der "echten" Anordnung her zusammengewürfelte Struktur jedes Mal identisch ist ...

Gruß
Larry
 
Kannst Du vielleicht die Schnittstelle des Daten FB posten, optional vielleicht sogar noch den Code?

Die von dir beschrieben Lösungweise erscheint mir sehr exotisch, da würde ein Codebeispiel sehr helfen.
 
Ich würde als erstes mal die automatische Datenoptimierung abschalten, wenigstens zum probieren.
Würde mich nicht wundern, wenn von Siemens in speziellen Fällen da ein Fehler drin wäre.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
a - b = c;
IF c < 0 THEN
c := c + 1;
END_IF;
In diesem Beispiel, wenn c < 0 ist, dann wird mir aber nicht - wie erwartet - c inkrementiert, sondern es wird ein Nonsens-Wert auf d geschrieben.
Wie sieht der Code genau aus?

Welche TIA-Version verwendest Du eigentlich?

Harald
 
Hallo!

Mir hat nun auch der Siemens-Support eine Abfuhr erteilt: Das könne man in so kurzer Zeit nicht analysieren.
Ich hab mein Programm auf 50 Zeilen, gekürzt. Der Sinn dabei geht zwar verloren, dass Verhalten jedoch bleibt reproduzierbar.
Es kann also nicht an der Größe er Bausteinschnittstelle liegen.

Wenn es sich von euch wer antun will, nachfolgend der Code:
Zunächst die Sendefunktion. Die habe ich komplett ausgeschlachtet. In der Vollversion soll sie die Verbindung zum PC herstellen und die Daten senden.
Übrig geblieben ist davon nur die Sendebestätigung nach der Sendeanforderung.
Code:
FUNCTION_BLOCK "TCP_CTRL"
{ S7_Optimized_Access := 'TRUE' }

   VAR
      Snd_Timer : Real;
      Snd_Buffer { ExternalWritable := 'False'} : Array[1.."Snd_Buffer_Max"] of Int;
      Test : Struct
         TON_Snd_Lock : TON_TIME;
         TON_Snd_Request : TON_TIME;
      END_STRUCT;
   END_VAR


BEGIN
        #Test.TON_Snd_Lock(IN := #State.Snd_Lock,
                           PT := t#50ms);
        
        #Test.TON_Snd_Request(IN := #State.Snd_Request,
                              PT := t#50ms);
        
        IF #Test.TON_Snd_Lock.Q AND #Test.TON_Snd_Request.Q THEN
            #State.Snd_Lock := FALSE;
            #State.Snd_Request := FALSE;
        END_IF;
END_FUNCTION_BLOCK

Das ist jetzt der Datensammel-Baustein. Die ersten 3 Regionen Eingänge lesen, Initialisieren, Fifo schreiben, könnt ihr getrost ignorieren. Die funktionieren tadellos.
Probleme gibt es erst, wenn Daten aus dem FiFo via MOVE_BLK in das Sende-Array geschrieben werden.
Ist Test.Active aktiv, wir in ein Array aus dem Datensammel-iDB geschrieben --> funktioniert
Ist es inaktiv wird in ein Array aus dem Sende-iDB geschrieben --> funktionirt NICHT
Code:
FUNCTION_BLOCK "TCP_DATA_AI"
{ S7_Optimized_Access := 'TRUE' }

   VAR_INPUT 
      Cycletime : Real := 0.001;   // OB Cycletime [s]
      Intervall : Real := 1.0;   // Aufzeichnungsintervall [s]
      Snd_Intervall : Real := 3.0;   // Sende Intervall [s]
      BufferTime : Real := 10.0;   // Pufferzeit [s] (gesamt)
      In_0 : Variant;   // INT, DINT or REAL, Connect to BYTE if not used
      In_1 : Variant;   // INT, DINT or REAL, Connect to BYTE if not used
   END_VAR

   VAR_IN_OUT 
      TCP_Ctrl : "TCP_CTRL";
   END_VAR

   VAR 
      Init : Array[0..#ChMax] of Bool;
      Val : Array[1..#ChMax, 0..1] of Int;
      ChNeed : Int;   // Optimal Channel Size
      ChUsed : Int;
      FiFoUsed : DInt;   // FiFo used Size
      Er : Bool;   // Error
      ElSize : Int;   // Element Size
      ElNumb : Int;   // Number of Elements
      SSW : Int := 1;   // State Machine
      IntCount : Real;   // Intervall Counter
      SndCount : Real;   // Sende Counter
      i : Int := 1;   // Loop Counter
      iFF : DInt := 1;   // Loop Counter for FiFo
      Snd_ElNb : Int;   // Number of Elements to send
      Snd_ElNbMax : Int;   // Number of max. Elements that fit in Buffer
      Snd_EltoMuch : Bool;   // Buffer to small
      Snd_HeaderSize : Int;   // Header Size
      Snd_PtrREndOld : Int;   // End of Element which was send before
      Test : Struct
         Active : Bool;
         Len : UDInt;
         Buffer : Array[1..32768] of Int;
      END_STRUCT;
      Tick : UDInt;   // Ticks
      PtrR : Int;   // Read Pointer
      PtrW : Int := 1;   // Write Pointer
      Type : Array[1..#ChMax] of Int;   // 1..Int 2..Dint 3..Real
      FIFO : Array[1..#FiFoMax] of Int;   // Data Array
   END_VAR

   VAR CONSTANT 
      ChMax : Int := 2;   // Default: 55
      FiFoMax : DInt := 30;   // Default: 1.100.000
   END_VAR


BEGIN
    // Ausführung nur im Intervall
    #IntCount := #IntCount + #Cycletime;
    IF #IntCount >= #Intervall THEN
        #IntCount := 0;

        REGION Eingänge lesen
            "TCP_DATA_Rd_Variant"(IN := #In_0,
                                  Int0 => #Val[1, 0],
                                  Int1 => #Val[1, 1],
                                  Init := #Init[1],
                                  Type := #Type[1]);
                "TCP_DATA_Rd_Variant"(IN := #In_1,
                                      Int0 => #Val[2, 0],
                                      Int1 => #Val[2, 1],
                                      Init := #Init[2],
                                      Type := #Type[2]);
        END_REGION
        
        REGION Initialisierung
                #ElSize := 3;
                #ChNeed := 2;
                #ChUsed := 2;
                #ElNumb := 10;
                #FiFoUsed := 30;
        END_REGION
        
        REGION FiFo beschreiben
                // Array befüllen
                FOR #i := 1 TO #ChMax DO
                    CASE #Type[#i] OF
                        0:      // Datentyp ungültig, kein Array Eintrag
                            ;
                        1:      // 2-Byte Datentyp ins Array eintragen
                            #FIFO[#iFF] := #Val[#i, 0];
                            IF #iFF < #FiFoUsed THEN
                                #iFF := #iFF + 1;
                            ELSE
                                #iFF := 1;
                            END_IF;
                        ELSE    // 4-Byte Datentyp ins Array eintragen
                            #FIFO[#iFF] := #Val[#i, 0];
                            IF #iFF < #FiFoUsed THEN
                                #iFF := #iFF + 1;
                            ELSE
                                #iFF := 1;
                            END_IF;
                            #FIFO[#iFF] := #Val[#i, 1];
                            IF #iFF < #FiFoUsed THEN
                                #iFF := #iFF + 1;
                            ELSE
                                #iFF := 1;
                            END_IF;
                    END_CASE;
                END_FOR;
                
                // Write Pointer setzen
                IF #PtrW < (#FiFoUsed / #ElSize) THEN
                    #PtrW := #PtrW + 1;
                ELSE
                    #PtrW := 1;
                END_IF;
        END_REGION
    END_IF;
    
    REGION Daten senden
        
        CASE #SSW OF
            0:  // nicht initialisiert
                ;
            1:  // Warten auf Sendefreigabe
            #SndCount := #SndCount + #Cycletime;                
            IF NOT #TCP_Ctrl.State.Snd_Lock AND #SndCount >= #Snd_Intervall THEN
                    // Sendebaustein reservieren
                    #TCP_Ctrl.State.Snd_Lock := TRUE;
                    
                    // Header schreiben
                    #Snd_HeaderSize := 8;
                    
                    // Datenlänge bestimmen
                    IF #PtrW < #PtrR THEN
                        #Snd_ElNb := #PtrW - #PtrR + #ElNumb;
                    ELSE
                        #Snd_ElNb := #PtrW - #PtrR;
                    END_IF;
                    // Datenlänge limitieren
                    #Snd_ElNbMax := DINT_TO_INT(("Snd_Buffer_Max" - INT_TO_DINT(#Snd_HeaderSize)) / #ElSize);
                    IF #Snd_ElNb > #Snd_ElNbMax THEN
                        #Snd_EltoMuch := TRUE;
                        #Snd_ElNb := #Snd_ElNbMax;
                    ELSE
                        #Snd_EltoMuch := FALSE;
                    END_IF;
                    
                    // Daten schreiben
                    // Kopierbefehl aufteilen wenn FiFo-Grenze überschritten wird
                    IF #Test.Active THEN
                        #Snd_PtrREndOld := #PtrR - 1;
                        IF #Snd_PtrREndOld + #Snd_ElNb > #ElNumb THEN
                            MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
                                     COUNT := INT_TO_ULINT(#ElSize * (#ElNumb - #Snd_PtrREndOld)),
                                     OUT => #Test.Buffer[#Snd_HeaderSize + 1]);
                            MOVE_BLK(IN := #FIFO[1],
                                     COUNT := INT_TO_ULINT(#ElSize * (#Snd_PtrREndOld + #Snd_ElNb - #ElNumb)),
                                     OUT => #Test.Buffer[#Snd_HeaderSize + 1 + (#ElSize * (#ElNumb - #Snd_PtrREndOld))]);
                        ELSE
                            MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
                                     COUNT := INT_TO_ULINT(#ElSize * #Snd_ElNb),
                                     OUT => #Test.Buffer[#Snd_HeaderSize + 1]);
                        END_IF;
                    ELSE
                        #Snd_PtrREndOld := #PtrR - 1;
                        IF #Snd_PtrREndOld + #Snd_ElNb > #ElNumb THEN
                            MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
                                     COUNT := INT_TO_ULINT(#ElSize * (#ElNumb - #Snd_PtrREndOld)),
                                     OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1]);
                            MOVE_BLK(IN := #FIFO[1],
                                     COUNT := INT_TO_ULINT(#ElSize * (#Snd_PtrREndOld + #Snd_ElNb - #ElNumb)),
                                     OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1 + (#ElSize * (#ElNumb - #Snd_PtrREndOld))]);
                        ELSE
                            MOVE_BLK(IN := #FIFO[(#ElSize * #Snd_PtrREndOld) + 1],
                                     COUNT := INT_TO_ULINT(#ElSize * #Snd_ElNb),
                                     OUT => #TCP_Ctrl.Snd_Buffer[#Snd_HeaderSize + 1]);
                        END_IF;
                    END_IF;
                    
                    // Sendebefehl absetzen
                    #TCP_Ctrl.State.Snd_Request := TRUE;
                    
                    // ReadPointer setzen, Sendebefehle im nächsten Zyklus nachholen, wenn Puffer zu klein
                    IF #Snd_EltoMuch THEN
                        #PtrR:=#PtrR+#Snd_ElNb;
                    ELSE
                        #PtrR := #PtrW;
                    END_IF;
                    #TCP_Ctrl.Snd_Buffer[3] := #PtrR;
                    
                    #SndCount := 0;
                    #SSW := 2;
                END_IF;
                
            2:  // Warten auf Senden beendet
                IF NOT #TCP_Ctrl.State.Snd_Lock AND NOT #TCP_Ctrl.State.Snd_Request THEN
                    #SSW := 1;
                END_IF;
            ELSE
                #SSW := 1;
        END_CASE;
    END_REGION
END_FUNCTION_BLOCK
Vielleicht habt ihr ja eine gute Idee dazu.

Wichtig ist also nur der Bereich im Programm, wo die MOVE_BLK Befehle zu finden sind.
 
Naja ... wie schon geschrieben (und das halt nicht nur von mir) :
Du solltest das mit dem "optimized Access" mal auf die Seite schieben. Ich sehe hier auch nicht, wo es einen Punkt gäbe, der dir da einen Vorteil verschaffen könnte - die Blockgröße hast du ja nunmal und die "Optimierung" bringt m.E. nur bei vielen Bit-Variablen in deinen Struktur etwas und das auch nur dann, wenn die aufgelösst werden. Übergibst du aber via Blockmove einen ganzen Datenblock dann ist das m.E. völlig irrelevant.

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!

Mag sein. Trotzdem gibt Siemens an, dass der Zugriff auf einen optimierten DB schneller ist. Ich kann mir aber auch vorstellen, dass das bei einem einzigen Array, also einem zusammenhängenden Bereich irrelevant ist
 
Mal unabhängig davon ... was hält sich davon ab, es zu probieren um Gewissheit zu bekommen ...
Larry

Eigentlich nur die liebe Zeit. Ich bin nun so verblieben, dass mein Sende-Array in einem Global-DB liegt. Damit habe ich keine Probleme. Bin aber weiterhin am testen. Also wenn ich dazu komme, dann probier ich das mal aus und werde dann berichten.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mal unabhängig davon ... was hält sich davon ab, es zu probieren um Gewissheit zu bekommen ...
Larry

Eigentlich nur die liebe Zeit. Ich bin nun so verblieben, dass mein Sende-Array in einem Global-DB liegt. Damit habe ich keine Probleme. Bin aber weiterhin am testen. Also wenn ich dazu komme, dann probier ich das mal aus und werde dann berichten.
 
Zurück
Oben