TIA Graph Parrallelschrittnummern lesen

meikelneit

Level-2
Beiträge
172
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich stehe aktuell vor dem Problem, im TIA Portal (S7-1500, GRAPH) alle aktiven Schrittnummern einer Schrittkette in einem SPS-Zyklus auszulesen. In meinem Anwendungsfall kann es durch parallele oder alternative Abläufe vorkommen, dass mehrere Schritte gleichzeitig aktiv sind, und ich benötige alle aktiven Schrittnummern, nicht nur den "aktuell aktiven Schritt" (DB_Step_Active o. Ä.).

Meine Frage an die Runde:Wie löst ihr das in der Praxis? Gibt es eine saubere Möglichkeit, z. B. über die Instanzdaten des GRAPH-Bausteins, gezielt die Schrittnummern der gesetzten Schritte (z. B. in EXEC_BITS) zu ermitteln?

Ich habe gesehen, dass das Bitfeld EXEC_BITS im Instanz-DB die aktiven Schritte abbildet, allerdings habe ich bisher keine direkte Zuordnung gefunden, mit der ich sagen kann: Bit 3 entspricht Schrittnummer X.

Daher zwei Fragen:

  1. Wie liest ihr im SPS-Zyklus alle gleichzeitig aktiven Schritte (Schrittnummern) einer GRAPH-Schrittkette aus?
  2. Gibt es eine dokumentierte oder praktikable Zuordnung von Bitpositionen in EXEC_BITS zu den tatsächlichen Schrittnummern?

Bin gespannt, wie ihr das angeht – vielleicht kennt jemand sogar eine Möglichkeit, das Mapping programmatisch aufzubauen oder über symbolische Informationen heranzukommen.


Vielen Dank vorab!
Viele Grüße
 
  1. Wie liest ihr im SPS-Zyklus alle gleichzeitig aktiven Schritte (Schrittnummern) einer GRAPH-Schrittkette aus?
  2. Gibt es eine dokumentierte oder praktikable Zuordnung von Bitpositionen in EXEC_BITS zu den tatsächlichen Schrittnummern?
1. noch nie gemacht.. mir ist in meinem Umfeld keine Praxis bekannt wo es notwendig wäre das zu tun
2.


Deswegen noch mal die allgemeine Frage:

Was soll durch das auslesen der aktiven Schritte erreicht werden? Wieso ist das notwendig? Vielleicht gibts ja andere Lösungen..
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wir haben das mal machen und visualisieren müssen für einen Automobilisten. Der hat dann einen Ausdruck der Kette bekommen und konnte so seinen Fehler suchen, wenn was hing.

Wir haben dazu in jedem Schritt eine Variable beschrieben mit der zum Schritt gehörigen S_NO (siehe Struktur). Gibt es Parallelverschaltungen, dann gibt es entsprechend mehr Variablen. In parallelen Schritten werden verschiedene Schrittnummern angezeigt, ansonsten immer die gleichen. Gleiches gilt für weitere Ketten im gleichen Baustein. Wenn du Schritte kopierst und wieder einfügst brauchst du nicht mal etwas tippen, weil die Umbenennung in den Aktionen automatisch erfolgt.
 
@EliteGurke: Vielleicht kannst du noch etwas genauer darauf eingehen.?!

Ich kenne es eigentlich auch so dass man in den Aktionen der Schritte eine Variable vom Typ Bool oder Integer nicht speichernd beschreibt und somit außerhalb der Schrittkette weiß welcher Schritt aktiv ist falls die Schrittkette läuft.

Nun ein paar Jahre später möchte ich das eigentlich eleganter implementieren und brauche die Schrittnummer oder besser noch den Schritt Namen. Zudem soll ein weiteres Zutun beim Erweitern der Schrittkette vermieden werden, da dies öfters vergessen wird.

- Ein durchrollen des Ausgangsparameters S_NO mittels Flanke von S_NEXT (inkl. Grenzerkennung) kann die Schrittnummer liefern, macht aber Probleme oder hohen Aufwand bei der Implementierung wenn es Simultanverzweigugnen gibt und die Schritte nur für eine Zykluszeit aktiv sind.

- Die Schnittstelle von "Standard Schnittstellenparameter" auf "Maximale Schnittstellenparameter" zu stellen, bringt leider nicht die notwendigen Informationen in den Instanzdatenbaustein der Schrittkette.

- Die Verwendung eines Erweiterungsbausteins liefert lediglich die Information wie viele Schritte aktiv sind, aber nicht welche.

Es muss doch eine Lösung für so etwas geben...

Benötigt wird die Information um sie dann in eine Log Datei zu schreiben, zukünftig aber auch um sie im HMI anzuzeigen. Das ganze soll natürlich komfortabel und erweiterungsfreundlich umgesetzt werden.


Über konkrete Hinweise oder besser noch Hilfestellungen, wäre ich sehr dankbar.


Edit: Innerhalb des Erweiterungsbausteins kann man das über die IO Schnittstelle übergebenes Array[*] of G7_StepPlus_V6 erledigen:

// Init
#Steps := #Steps_init;

// Boundaries
#iLowerBound := DINT_TO_INT(LOWER_BOUND(ARR := #io_G7S, DIM := 1));
#iUpperBound := DINT_TO_INT(UPPER_BOUND(ARR := #io_G7S, DIM := 1));

// Data acquisition
FOR #i := #iLowerBound TO #iUpperBound DO
IF #io_G7S[#i].X THEN
#Steps.usiNumber[#siNumberOfActiveSteps] := INT_TO_USINT(#io_G7S[#i].SNO);
END_IF;
END_FOR;

Nur die Schritt Namen bekomme ich noch nicht...
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
- Die Verwendung eines Erweiterungsbausteins liefert lediglich die Information wie viele Schritte aktiv sind, aber nicht welche.
Das stimmt nicht.
Du bekommst ein Array aller Schritte auf einmal.
Mit einer Schleife diese Variable abfragen:

#io_G7S[ #HierDeineINDEXvariable ].X
Die ist TRUE wenn der Schritt aktiv ist.

#io_G7S[ #HierDeineINDEXvariable ].SNO
Da Steht die Graph Schritt Nr drin.

Du musst nur die Array Größe dynamisch ermitteln. Sonst bekommst Du bei Änderungen Probleme
z.B.:
#si_MinSchritteGraph := DINT_TO_INT(LOWER_BOUND(ARR := #io_G7S, DIM := 1));
#si_MaxSchritteGraph := DINT_TO_INT(UPPER_BOUND(ARR := #io_G7S, DIM:= 1));
Also die für deine For-Schleife nutzen
 
Danke. Mir hat das geholfen und den Inhalt des Erweiterungsbausteins folgend befüllt:

// Init
#Steps := #Steps_init;

// Boundaries
#iLowerBound := DINT_TO_INT(LOWER_BOUND(ARR := #io_G7S, DIM := 1));
#iUpperBound := DINT_TO_INT(UPPER_BOUND(ARR := #io_G7S, DIM := 1));

// Data acquisition
FOR #i := #iLowerBound TO #iUpperBound DO
IF #io_G7S[#i].X THEN
#Steps.usiNumber[#siNumberOfActiveSteps] := INT_TO_USINT(#io_G7S[#i].SNO);
END_IF;
END_FOR;

Nur die Schritt Namen bekomme ich noch nicht...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Habe schon die SFC "GetSymbolName" gefunden. Allerdings gibt die dann auf mein Beispiel bezogen z.B. "io_G7S[1]" zurück und löst den Namen damit nicht korrekt auf. Korrekt wäre "BeispielNameFürSchrittkette.Step1". Vermutlich müsste man dann an dieser Stelle mit Zeigern arbeiten...
 
Nur die Schritt Namen bekomme ich noch nicht...
Wenn Du eine Lösung gefunden hast, wäre ich auch daran interessiert.

Das ist genauso ein Thema, wie die Identifikation von Bausteinen bei Fehlern.
Das TIA ist ja sooooo symbolisch. Aber, wenn ein Baustein mit Fehler vom TIA gemeldet wird, wird dieser absolut (FC34, FB56, DB101, ...) angegeben.
Wenn man sein Programm mit Ordnern und Unterordnern strukturiert hat und man viele Bausteine hat, ist das echt blöd.
 
Wenn Du eine Lösung gefunden hast, wäre ich auch daran interessiert.

Das ist genauso ein Thema, wie die Identifikation von Bausteinen bei Fehlern.
Das TIA ist ja sooooo symbolisch. Aber, wenn ein Baustein mit Fehler vom TIA gemeldet wird, wird dieser absolut (FC34, FB56, DB101, ...) angegeben.
Wenn man sein Programm mit Ordnern und Unterordnern strukturiert hat und man viele Bausteine hat, ist das echt blöd.
Vielleicht hilft dir dann GetBlockName?!
 
Ja, ich wollte die Variable siNumberOfActiveSteps einsparen, da ja mit "#io_G7Arrays[#io_RT_Data.OFFSETS.SAX_OFFSET] - 1" schon ermittelt werden kann wie viele Schritte aktiv sind. Merkte aber dass ich die besagte Variabel aber als Laufindex für das Array verwendet habe in das die Informationen dann reinkopiert werden. Bereinigter Code sieht dann so aus:
Allerdings funktioniert die Ausgabe vom Schritt Namen noch nicht. Da braucht es vlt Zeiger für.

1753357465610.png
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nur die Schritt Namen bekomme ich noch nicht...
Wenn Du eine Lösung gefunden hast, wäre ich auch daran interessiert.

Naja, es gibt da schon eine "Lösung".
Die ist ordentlich umständlich und die Namen kommen auch nicht unbedingt in der richtigen Reihenfolge. (Es kann sein, dass der Name von Step1 nach Step10 angegeben ist.)
Weiters geht das nicht ganz in Echtzeit.

Herangehensweise:

Suche die ID der Meldetextliste, die die Namen deiner Schrittkette enthält.
1754395934145.png

Erstelle einen FB der mit Hilfe von Textliste und Schrittnummer den Schrittnamen als Programmalarm ausgibt.
1754396198855.png

Frage die Programmalarme mit GetAlarm ab.

Profit?!?!
1754396823513.png
 
Hier mein etwas aufgeräumter Code dazu:
Code:
FUNCTION_BLOCK "MyStepChainNameAlarm"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      Stepnumber { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt;
      Textlist { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt;
   END_VAR

   VAR
      StepName {InstructionName := 'Program_Alarm'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : Program_Alarm;
      OldStepnumber { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'True'} : UInt;
   END_VAR


BEGIN
    #StepName(SIG:=#Stepnumber<>0 AND #OldStepnumber=#Stepnumber,
              SD_1:=#Textlist, SD_2 := #Stepnumber);
    #OldStepnumber := #Stepnumber;
END_FUNCTION_BLOCK

FUNCTION_BLOCK "GraphDiag"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_IN_OUT
      io_RT_Data {InstructionName := 'G7_RTDataPlus_V6'; LibVersion := '1.0'} : G7_RTDataPlus_V6;
      io_G7T {InstructionName := 'G7_TransitionPlus_V6'; LibVersion := '1.0'} : Array[*] of G7_TransitionPlus_V6;
      io_G7S {InstructionName := 'G7_StepPlus_V6'; LibVersion := '1.0'} : Array[*] of G7_StepPlus_V6;
      io_G7Arrays : Array[*] of USInt;
   END_VAR

   VAR
      ActiveSteps_Numbers { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Array[0..15] of Int;
      ActiveSteps_Alarms { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : Array[0..15] of "MyStepChainNameAlarm";
      ActiveSteps_Names { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'True'} : Array[0..15] of WString;
      Get_Alarm_Instance {InstructionName := 'Get_Alarm'; LibVersion := '1.7'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Get_Alarm;
      AlarmData {InstructionName := 'AlarmData'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : AlarmData;
      TextListIDSteps { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt;
      DisplayClass { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt;
   END_VAR

   VAR_TEMP
      i : DInt;
      j : Int;
      tmp_StepsUpperBound : DInt;
      tmp_StepsLowerBound : DInt;
      tmp_DisplayClassNrs : Array[0..31] of UInt;
      tmp_IsDefraged : Bool;
   END_VAR


BEGIN
    REGION init
        #tmp_StepsLowerBound := LOWER_BOUND(ARR := #io_G7S, DIM := 1);
        #tmp_StepsUpperBound := UPPER_BOUND(ARR := #io_G7S, DIM := 1);
        #j := 0;
    END_REGION
  
    REGION get numbers of active steps
        FOR #i := #tmp_StepsLowerBound TO #tmp_StepsUpperBound DO
            IF #io_G7S[#i].X THEN
                #ActiveSteps_Numbers[#j] := #io_G7S[#i].SNO;
                #j += 1;
            END_IF;
        END_FOR;
      
        // fill remaining numbers with 0
        WHILE #j <= 15 DO
            #ActiveSteps_Numbers[#j] := 0;
            #j += 1;
        END_WHILE;
    END_REGION
  
    REGION trigger alarm via textlist and stepnumber
        FOR #i := 0 TO 15 DO
            #ActiveSteps_Alarms[#i](Stepnumber := INT_TO_UINT(#ActiveSteps_Numbers[#i]),
                                    Textlist := #TextListIDSteps);  //#TextListIDSteps gets its value in the permanent pre-instructions from the graph
        END_FOR;
    END_REGION
  
    REGION only use display class which you reserved for this stepchain
        FOR #i := 0 TO 31 DO
            #tmp_DisplayClassNrs[#i] := #DisplayClass;  //#DisplayClass gets its value in the permanent pre-instructions from the graph
        END_FOR;
    END_REGION
  
    REGION handle operations mode of Get_Alarm
        IF #Get_Alarm_Instance.OperateMode = 1 AND NOT #Get_Alarm_Instance.Busy THEN
            #Get_Alarm_Instance.OperateMode := 2;
        END_IF;
      
        IF (#Get_Alarm_Instance.OperateMode = 0 OR #Get_Alarm_Instance.OperateMode = 3) AND NOT #Get_Alarm_Instance.Busy THEN
            #Get_Alarm_Instance.OperateMode := 1;
        END_IF;
        IF #Get_Alarm_Instance.Status = 16#8085 THEN
            #Get_Alarm_Instance.OperateMode := 3;
            FOR #i := 0 TO 15 DO
                #ActiveSteps_Names[#i] := wstring#'';
            END_FOR;
        END_IF;
    END_REGION
  
    REGION call Get_Alarm
        #Get_Alarm_Instance(DataMode := 1,
                            DispClassNr := #tmp_DisplayClassNrs,
                            Lcid := 1,
                            Data := #AlarmData);
    END_REGION
  
    REGION handle new data from Get_Alarm
        IF #Get_Alarm_Instance.DataReady THEN
            IF #AlarmData.State = 1 THEN
                FOR #i := 0 TO 15 DO
                    IF #ActiveSteps_Names[#i] = wstring#'' THEN
                        #ActiveSteps_Names[#i] := #AlarmData.AlarmText[0];
                        EXIT;
                    END_IF;
                END_FOR;
            ELSE
                #tmp_IsDefraged := false;
                FOR #i := 0 TO 15 DO
                    IF #tmp_IsDefraged THEN
                        #ActiveSteps_Names[#i - 1] := #ActiveSteps_Names[#i];
                        CONTINUE;
                    END_IF;
                    IF #ActiveSteps_Names[#i] = #AlarmData.AlarmText[0] THEN
                        #tmp_IsDefraged := true;
                    END_IF;
                END_FOR;
            END_IF;
        END_IF;
    END_REGION
END_FUNCTION_BLOCK

Der Programmalarm in "MyStepChainNameAlarm" sollte eine Anzeigeklasse haben, die sonst nirgends verwendet wird.
Bei mehreren nebenläufig laufenden Schrittketten wird man je nach Wunsch auch unterschiedliche Anzeigeklassen benötigen.
1754399104216.png
Die Meldung gebe ich über diese Funktion mit TextlistenID und Schrittnummer aus.
1754399197215.png
Den "GraphDiag" Baustein als Erweiterungsbaustein beim Graphbaustein angeben.
1754399419771.png
und eine Instanz davon im "Static" angeben. (Wahlweise soll es auch mit InOut hinhauen)
1754400305169.png

Anzeigeklasse und Textliste weise ich in den Vorausgeschalteten permanenten Anweisungen zu.
1754399500957.png
 
Zuletzt bearbeitet:
Zurück
Oben