TIA Scoreboard in HMI einfügen.

MaxH

Level-1
Beiträge
23
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

meine Aufgabe ist es ein "Scoreboard" im HMI zu erzeugen, um anzuzeigen wer der schnellste bei einem Ablauf ist.
Auch eben mit (Spitz-) Namen eingeben und die Zeit soll automatisch angezeigt werden.
Ich benutze eine S7-1500 und ein KTP700 Basic.
Kann mir da wer helfen bitte?

-Max
 
Hallo MaxH,

was hast du schon? welche Tia Version nutzt du? Woher kommen die Werte? Müssen diese nur abgegriffen und angezeigt werden?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Zeiterfassung ist drinnen.

Namen muss eingegeben werden und die Zeit muss nur noch abgegriffen werden?
Kann ich das über eine Benutzeranzeige oder ähnliches visualisieren?

TIA V17
 
Lege HMI-Variablen als String/WString an und mache die Eingabe und Anzeige der Teilnehmernamen mit EA-Feldern. Jeder Name und jede Zeit ein eigenes EA-Feld.
Soll die Liste nach Zeit sortiert werden? Das mache in der SPS. Die String-HMI-Variablen dann auch in der SPS in DB anlegen. Außerdem sind sie dann (standardmäßig) remanent. Die Liste am besten als Array of Struct oder Array of UDT.

Harald
 
Lege HMI-Variablen als String/WString an und mache die Eingabe und Anzeige der Teilnehmernamen mit EA-Feldern. Jeder Name und jede Zeit ein eigenes EA-Feld.
Soll die Liste nach Zeit sortiert werden? Das mache in der SPS. Die String-HMI-Variablen dann auch in der SPS in DB anlegen. Außerdem sind sie dann (standardmäßig) remanent. Die Liste am besten als Array of Struct oder Array of UDT.

Harald
Danke probiere ich sofort.
Ja soll sortiert sein.

-Max
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Lege HMI-Variablen als String/WString an und mache die Eingabe und Anzeige der Teilnehmernamen mit EA-Feldern. Jeder Name und jede Zeit ein eigenes EA-Feld.
Soll die Liste nach Zeit sortiert werden? Das mache in der SPS. Die String-HMI-Variablen dann auch in der SPS in DB anlegen. Außerdem sind sie dann (standardmäßig) remanent. Die Liste am besten als Array of Struct oder Array of UDT.

Harald
Das mit den EA Feldern hätte ich erledigt und die Namen und Zeiten in eigene EA-Felder gegeben und benannt.
Hab auch schon einen Datenbaustein angelegt und die Daten in Array of Struct gespeichert. Stehe jetzt aber neuerdings an.

LG
 

Anhänge

  • DB_Score.PNG
    DB_Score.PNG
    112,9 KB · Aufrufe: 33
  • FB_Scoreboard.PNG
    FB_Scoreboard.PNG
    67,1 KB · Aufrufe: 37
  • HMI.PNG
    HMI.PNG
    52,1 KB · Aufrufe: 37
  • HMI_Variablen.PNG
    HMI_Variablen.PNG
    136,2 KB · Aufrufe: 37
Wie auf einer Ergebnisliste aus Papier brauchst Du eine Liste mit 5 Einträgen/Datensätzen/Zeilen, die jeweils aus (den Spalten) Name und Zeit bestehen. Das könnte im DB_Score so aussehen:
Code:
Ergebnisliste : Array [0..4] of Struct     <--- [v] Remanenz
  Ergebnisliste[0] : Struct
    Zeit : Int         := 0
    Name : String[10]  := ''
  ...
(Weil die Liste später nach "Zeit" sortiert wird, nehme ich hier "Zeit" als erste Variable/Spalte. Ist aber egal.)

Dann kannst Du die Variablen der Einträge so ansprechen:
"DB_Score".Ergebnisliste[0].Zeit und "DB_Score".Ergebnisliste[0].Name
...
"DB_Score".Ergebnisliste[4].Zeit und "DB_Score".Ergebnisliste[4].Name


Tipp: Wenn Du das Struct an mehreren Programmstellen brauchst, dann ist es vorteilhaft und konsistent, den Struct als eigenen PLC-Datentyp (UDT) zu projektieren, dann brauchst Du bei den Verwendungsstellen des Datentyps nicht mehr die Struktur erklären.

Harald
 
Wie auf einer Ergebnisliste aus Papier brauchst Du eine Liste mit 5 Einträgen/Datensätzen/Zeilen, die jeweils aus (den Spalten) Name und Zeit bestehen. Das könnte im DB_Score so aussehen:
Code:
Ergebnisliste : Array [0..4] of Struct     <--- [v] Remanenz
  Ergebnisliste[0] : Struct
    Zeit : Int         := 0
    Name : String[10]  := ''
  ...
(Weil die Liste später nach "Zeit" sortiert wird, nehme ich hier "Zeit" als erste Variable/Spalte. Ist aber egal.)

Dann kannst Du die Variablen der Einträge so ansprechen:
"DB_Score".Ergebnisliste[0].Zeit und "DB_Score".Ergebnisliste[0].Name
...
"DB_Score".Ergebnisliste[4].Zeit und "DB_Score".Ergebnisliste[4].Name


Tipp: Wenn Du das Struct an mehreren Programmstellen brauchst, dann ist es vorteilhaft und konsistent, den Struct als eigenen PLC-Datentyp (UDT) zu projektieren, dann brauchst Du bei den Verwendungsstellen des Datentyps nicht mehr die Struktur erklären.

Harald
Im SCL programmieren bin ich leider echt nicht drinnen, FUP ist für mich die einzig verständliche Sprache...🙈
Kann man das im FUP auch programmieren, oder ist SCL da die einzig gute Lösung?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Da ist überhaupt kein SCL. Das ist die Struktur der Liste, wie Du sie in einem DB zusammenklicken könntest. Ich hatte es nur schnell als Text getippt, wie es in TIA in einem DB aussehen würde. Oder brauchst Du ein buntes Pixelbild von TIA, um das abzutippen? ;)

Wenn der Listeninhalt später sortiert und dazu die Einträge umkopiert werden sollen, dann befürchte ich, daß das nicht mehr schön in FUP geht. Da wäre ein Netzwerk in SCL angebracht und ein paar Zeilen SCL-Code viel verständlicher, als viele FUP-Netzwerke.

Hinweis: bei meinem Vorschlag haben die Listeneinträge nur die Spalten "Zeit" und "Name". Wenn dann nach Zeit sortiert wird und zwei Einträge haben die gleiche Zeit, ist es dann egal in welcher Reihenfolge die beiden Einträge stehen oder soll einer bevorzugt werden? Alphabetisch nach Name oder wer die Zeit zuerst erreicht hat? Bei letzterem brauchst Du noch eine Spalte "Zeitstempel" für Datum+Uhrzeit, wann diese Zeit gemessen wurde.

Harald
 

Anhänge

  • DB_Ergebnisliste.png
    DB_Ergebnisliste.png
    29,1 KB · Aufrufe: 16
Da ist überhaupt kein SCL. Das ist die Struktur der Liste, wie Du sie in einem DB zusammenklicken könntest. Ich hatte es nur schnell als Text getippt, wie es in TIA in einem DB aussehen würde. Oder brauchst Du ein buntes Pixelbild von TIA, um das abzutippen? ;)

Wenn der Listeninhalt später sortiert und dazu die Einträge umkopiert werden sollen, dann befürchte ich, daß das nicht mehr schön in FUP geht. Da wäre ein Netzwerk in SCL angebracht und ein paar Zeilen SCL-Code viel verständlicher, als viele FUP-Netzwerke.

Hinweis: bei meinem Vorschlag haben die Listeneinträge nur die Spalten "Zeit" und "Name". Wenn dann nach Zeit sortiert wird und zwei Einträge haben die gleiche Zeit, ist es dann egal in welcher Reihenfolge die beiden Einträge stehen oder soll einer bevorzugt werden? Alphabetisch nach Name oder wer die Zeit zuerst erreicht hat? Bei letzterem brauchst Du noch eine Spalte "Zeitstempel" für Datum+Uhrzeit, wann diese Zeit gemessen wurde.

Harald
Ahh jetzt weiß ich was du meinst.
Das ist dann egal wer oben steht und wer unten, wenn sie die gleiche Zeit haben.
Das wird noch spannend denn in SCL hab ich absolut keine Erfahrung, genauso wie mit DBs seit dieser Woche😅

Ich checks morgen aus und geb dir daraufhin Bescheid, danke
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Im SCL programmieren bin ich leider echt nicht drinnen, FUP ist für mich die einzig verständliche Sprache...🙈
Wenn der Listeninhalt später sortiert und dazu die Einträge umkopiert werden sollen, dann befürchte ich, daß das nicht mehr schön in FUP geht. Da wäre ein Netzwerk in SCL angebracht und ein paar Zeilen SCL-Code viel verständlicher, als viele FUP-Netzwerke.
Nun gut, dann werde ich Dir den SCL-Code für das Sortieren zeigen. Zunächst ein paar Vorbereitungen...

Tipp: Wenn Du das Struct an mehreren Programmstellen brauchst, dann ist es vorteilhaft und konsistent, den Struct als eigenen PLC-Datentyp (UDT) zu projektieren, dann brauchst Du bei den Verwendungsstellen des Datentyps nicht mehr die Struktur erklären.
Jetzt sind wir in der Situation, daß die Struktur eines Ergebnislisten-Eintrags an mehreren Stellen gebraucht und erklärt werden muß. Also erstellen wir die Struktur als eigenen PLC-Datentyp und brauchen sie so nur einmal erklären:
Code:
PLC-Datentyp "t_Score"

Zeit : Int         := 0
Name : String[10]  := ''

Im DB_Score ändern oder erstellen wir nun die Ergebnisliste als Array of "t_Score", einen Eintrag länger als im HMI angezeigt werden soll:
Code:
DB_Score

Static
  Ergebnisliste : Array[0..5] of "t_Score"      [v] Remanenz
Die Einträge Ergebnisliste[0] .. Ergebnisliste[4] sind die im HMI angezeigten 5 Zeilen für Platz 1 bis 5
Der Eintrag Ergebnisliste[5] ist der Einfügeplatz für neue Einträge und wird am HMI nicht angezeigt.

Wenn ein neuer Datensatz entstanden ist, der zur Ergebnisliste hinzugefügt werden soll, dann immer auf den unsichtbaren Einfügeplatz am Ende der Liste kopieren und danach die Liste sortieren.

Code:
FUP Netzwerk: neues Ergebnis zur Ergebnisliste zufügen

                       +-----+              +--------+
                       |  &  |              |  MOVE  |
 neuenEintragZufuegen--|     |---+----------|EN      |
                       +-----+   |          |     OUT|--"DB_Score".Ergebnisliste[5].Zeit
                                 |   #Zeit--|IN   ENO|--
                                 |          +--------+
                                 |
                                 |          +--------+
                                 |          | S_MOVE |
                                 +----------|EN      |
                                            |     OUT|--"DB_Score".Ergebnisliste[5].Name
                     "DB_HMI".Name_Spieler--|IN   ENO|--
                                            +--------+

Für das Sortieren der Liste brauchen wir ein paar Hilfsvariablen, die wir am besten im TEMP-Bereich des Codebausteins anlegen:
Code:
Temp
  i : Int
  n : Int
  tmp_Score : "t_Score"
  swapped : Bool

Und hier nun der Code für das Sortieren der Liste. Dazu in dem Codebaustein ein "SCL-Netzwerk" einfügen:
Code:
SCL Netzwerk: Ergebnisliste sortieren (Score)
//mit Bubblesort, aufsteigend, 0-Werte ans Ende
//https://de.wikipedia.org/wiki/Bubblesort#Algorithmus , Variante bubbleSort2

IF jetztSortieren THEN
    jetztSortieren := FALSE; //nur einmal sortieren
   
    #n := 6; //Anzahl Einträge in der Liste
    REPEAT
        #swapped := FALSE;
        FOR #i := 0 TO #n - 2 DO
            IF "DB_Score".Ergebnisliste[#i + 1].Zeit <> 0
            AND ( "DB_Score".Ergebnisliste[#i].Zeit > "DB_Score".Ergebnisliste[#i + 1].Zeit
                OR "DB_Score".Ergebnisliste[#i].Zeit = 0 )
            THEN
                REGION Swap(i,i+1)
                    #tmp_Score := "DB_Score".Ergebnisliste[#i];
                    "DB_Score".Ergebnisliste[#i] := "DB_Score".Ergebnisliste[#i + 1];
                    "DB_Score".Ergebnisliste[#i + 1] := #tmp_Score;
                END_REGION
                #swapped := TRUE;
            END_IF;
        END_FOR;
        #n -= 1;
    UNTIL NOT #swapped END_REPEAT;

END_IF;

Beim "Swap(i,i+1)" kann man noch einen Vorteil der Deklaration der Struktur als PLC-Datentyp "t_Score" sehen: man muß nicht jede Variable der Strukturen einzeln umkopieren, sondern gibt einfach die ganze Struktur an. Wie der SCL-Compiler das umkopieren der Strukturen im Detail löst, braucht uns nicht interessieren. Und falls mal die Struktur von "t_Score" geändert/erweitert wird, dann werden einfach alle Verwendungsstellen von "t_Score" neu übersetzt, man muß sie nicht manuell anpassen.

Harald
 
PS: die kleine Liste sortieren reicht einmal zu durchlaufen, danach ist die Liste sortiert und muß nicht nochmal sortiert werden. Es macht performancemässig aber auch nicht nennenswert was aus, wenn das sortieren in jedem Zyklus gemacht wird, weil da geht die FOR-Schleife einmal durch, macht 5 Vergleiche und stellt fest daß nichts getauscht wurde und fertig.

Harald
 
Hallo Harald!

Code:
1) IF "jetztSortieren" THEN
2) "jetztSortieren" := FALSE; //nur einmal sortieren
 
3)    "n" := 6; //Anzahl Einträge in der Liste
4)  REPEAT
5)      "swapped" := FALSE;
6)      FOR "i" := 0 TO "n" - 2 DO
7)          IF "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0
8)              AND "DB_Scoreboard".Ergebnisliste["i"].Menschzeit > "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit
9)              OR "DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0
10)          THEN
11)              REGION Swap(i,i+1)
12)                  "tmp_score" :="DB_Scoreboard".Ergebnisliste["i"];
13)                  "DB_Scoreboard".Ergebnisliste["i"] := "DB_Scoreboard".Ergebnisliste["i" + 1];
14)                  "DB_Scoreboard".Ergebnisliste["i" + 1] := #tmp_Score;
15)              END_REGION
16)              "swapped" := TRUE;
17)        END_IF;
18)      END_FOR;
19)      "n" -= 1;
20)  UNTIL NOT "swapped" END_REPEAT;
21) END_IF;

Soweit bin ich schon mal, die beiden folgenden Befehle sind mir derzeit noch unklar wieso diese unterstrichen werden.
(Rechtschreibung wurde kontrolliert).
"DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0 (Zeile 7)
"DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0 (Zeile 9)

Unter welchen Datentyp muss ich "#tmp_Score" abspeichern?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald!

Code:
1) IF "jetztSortieren" THEN
2) "jetztSortieren" := FALSE; //nur einmal sortieren
 
3)    "n" := 6; //Anzahl Einträge in der Liste
4)  REPEAT
5)      "swapped" := FALSE;
6)      FOR "i" := 0 TO "n" - 2 DO
7)          IF "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0
8)              AND "DB_Scoreboard".Ergebnisliste["i"].Menschzeit > "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit
9)              OR "DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0
10)          THEN
11)              REGION Swap(i,i+1)
12)                  "tmp_score" :="DB_Scoreboard".Ergebnisliste["i"];
13)                  "DB_Scoreboard".Ergebnisliste["i"] := "DB_Scoreboard".Ergebnisliste["i" + 1];
14)                  "DB_Scoreboard".Ergebnisliste["i" + 1] := #tmp_Score;
15)              END_REGION
16)              "swapped" := TRUE;
17)        END_IF;
18)      END_FOR;
19)      "n" -= 1;
20)  UNTIL NOT "swapped" END_REPEAT;
21) END_IF;

Soweit bin ich schon mal, die beiden folgenden Befehle sind mir derzeit noch unklar wieso diese unterstrichen werden.
(Rechtschreibung wurde kontrolliert).
"DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0 (Zeile 7)
"DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0 (Zeile 9)

Unter welchen Datentyp muss ich "#tmp_Score" abspeichern?

Korrektur: das einzige Problem ist nur noch der tmp_Score.
Der PLC-Datentyp ist erstellt aber dennoch läufts nicht so ganz.



Code:
"tmp_score" : t_Score;   //FEHLERMELDUNG: t_Score: "Eine Variable wird hier erwartet."

//mit Bubblesort, aufsteigend, 0-Werte ans Ende
//https://de.wikipedia.org/wiki/Bubblesort#Algorithmus , Variante bubbleSort2

IF "jetztSortieren" THEN
    "jetztSortieren" := FALSE; //nur einmal sortieren
    "n" := 6; //Anzahl Einträge in der Liste
  REPEAT
      "swapped" := FALSE;
      FOR "i" := 0 TO "n" - 2 DO
          IF "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0
              AND "DB_Scoreboard".Ergebnisliste["i"].Menschzeit > "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit
              OR "DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0
          THEN
              REGION Swap(i,i+1)
                  "tmp_score" := "DB_Scoreboard".Ergebnisliste["i"];   //FEHLERMELDUNG "Der Operand "tmp_Score" ist nicht definiert."
                  "DB_Scoreboard".Ergebnisliste["i"] := "DB_Scoreboard".Ergebnisliste["i" + 1];
                  "DB_Scoreboard".Ergebnisliste["i" + 1] := "tmp_score";   //FEHLERMELDUNG "Der Operand "tmp_Score" ist nicht definiert."
              END_REGION
              "swapped" := TRUE;
        END_IF;
      END_FOR;
      "n" -= 1;
  UNTIL NOT "swapped" END_REPEAT;
END_IF;
 
Unter welchen Datentyp muss ich "#tmp_Score" abspeichern?
Du sollst tmp_Score und swapped im TEMP-Bereich des Bausteins anlegen, wo der Code steht, der diese Variablen verwendet.
Es sieht so aus, als ob Du beide Variablen als Merker angelegt hast bzw. wolltest? Weil der Datentyp "t_Score" einen STRING enthält, kann er aber nicht im Bereich der Merker oder E/A angelegt werden.
Für das Sortieren der Liste brauchen wir ein paar Hilfsvariablen, die wir am besten im TEMP-Bereich des Codebausteins anlegen:
Code:
Temp
  i : Int
  n : Int
  tmp_Score : "t_Score"
  swapped : Bool

Harald
 

Anhänge

  • TEMP_t_Score.png
    TEMP_t_Score.png
    11,7 KB · Aufrufe: 7
PS: in Deinem Code im Beitrag #15 sind "i" und "n" auch in Anführungsstrichen und kein # davor - die Variablen hast Du anscheinend auch als Merker angelegt?
Die Variablen i, n, tmp_Score und swapped werden nur kurz im Baustein gebraucht und müssen sich nichts bis zum nächsten Zyklus merken und außerhalb des Bausteins steht nichts informatives drin, was sich lohnt es zu beobachten. Deshalb reicht es, die Variablen ressourcenschonend im Temp-Bereich anzulegen. Wenn Du die Variablen trotzdem von außen beobachtbar anlegen willst, dann lege sie in einem DB an. Wenn Dein Codebaustein ein FB ist, dann an besten bei den Lokal-Variablen im Static-Bereich des FB (dann kannst Du die im Instanz-DB beobachten). Oder lege die Variablen in einen Global-DB, z.B. den DB "DB_Scoreboard"

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
7)          IF "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit <> 0
8)              AND "DB_Scoreboard".Ergebnisliste["i"].Menschzeit > "DB_Scoreboard".Ergebnisliste["i"+ 1].Menschzeit
9)              OR "DB_Scoreboard".Ergebnisliste["i"].Menschzeit = 0
10)          THEN
Mir fällt gerade auf, daß Du bei der Bedingung meine Klammern weggelassen hast - dann wird der Code nicht wie gewünscht funktionieren. Dein Code muß so aussehen:
Code:
7)          IF "DB_Scoreboard".Ergebnisliste[#i + 1].Menschzeit <> 0
8)              AND ( "DB_Scoreboard".Ergebnisliste[#i].Menschzeit > "DB_Scoreboard".Ergebnisliste[#i + 1].Menschzeit
9)              OR "DB_Scoreboard".Ergebnisliste[#i].Menschzeit = 0 )
10)          THEN
 
Ok danke bzgl. der Klammern, dachte die sind ein Schreibfehler...
Ich schaffe es aber nicht die Variablen tmp_Score & t_Score in den PLC-Datentyp einzufügen und F1 & das Internet geben auch keine guten Hinweise.
 
tmp_Score ist auch nicht der Datentyp sondern ein Tag vom benutzerdefinierten Datentyp t_Score. Diesen solltest du allerdings als Datentyp anlegen können.
 
Zurück
Oben