Step 7 SCL - Timerproblem innerhalb einer While-Schleife

Rados

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

ich habe ein Problem mit einem Timer innerhalb einer While-Schleife.

Der Code-Teil ist folgender:

...
Schleife1 := 0;
...
...
WHILE Schleife1 <20 DO
Schleife1:= Schleife1 + 1;

... //= Code innerhalb der Schleife, der funktioniert

// Die Schleife wird 20x durchlaufen. Dabei werden aus einem DB verschiedene Datensaetze (Bloecke) ausgelesen und in einen anderen DB geschrieben
// Der Schleifenzaehler laesst die Datensatzadressen entsprechend mehrerer Formeln hochzaehlen. Das funktioniert alles.
// Am Ende eines jeden Auslesens und Schreibens soll in der Visualisierung ein Bit (DB500.DBX4.5) fuer 1 Sekunde gesetzt und danach wieder zurueckgesetzt werden.
// Dieses Bit MUSS bei jedem Zyklusdurchlauf fuer eine Sekunde an und danach wieder aus sein.
// Dann beginnt die Schleife wieder, die naechsten Datensaetze einzulesen und in den anderen DB zu schreiben.
// Und wieder soll am Ende dieses Lesens und Schreibens dieses Bit fuer 1 Sekunde gesetzt und danach wieder zurueckgesetzt werden.
// Nach 20 Durchlaeufen wird die While-Schleife verlassen.

// Ich hatte mir gedacht, dieses zeitverzoegerte Setzen und Ruecksetzen des Bits mit einem Timer zu realisieren und habe innerhalb der While Schleife1 (siehe oben)
// Einen Timer wie folgt gesetzt:


DB500.DBX4.5:= true;
CurrTime_2:= S_PEXT (T_NO:=10, S:=DB500.DBX4.5, TV:=T#1s, BI:=BinVal_2, Q:=ActFlag_2);

M18.2:= ActFlag_2;

IF NOT M18.2 THEN
DB500.DBX4.5:= false;
END_IF;

...
...
END_WHILE;

...
...
// Der Timer macht nicht das, was ich gerne haette, er zaehlt nur einmal, in der Zeit ist natuerlich meine Schleife schon laengst 20x durchgelaufen. Es sollte jedoch so sein, dass
// die Schleife auf den Timer wartet und erst nach 1 Sekunde an der pausierten Stelle fortsetzt.
// Da ich SCL-Neuling bin, kenne ich keine Methode, die Schleife auf diese Art pausieren zu lassen. Koennt Ihr mir da Hinweise geben?

Vielen Dank vorweg!
Ralf

 
Hallo,

Du hast 2 Probleme
- Du setzt DB500.DBX4.5 direkt vor dem Timer-Aufruf auf TRUE, so daß der Timer am Eingang S immer nur TRUE sehen kann. Er muß aber auch mal FALSE sehen, weil er zum neu starten eine 0-1-Flanke braucht.
- Du kannst die Schleife unmöglich 1 Sekunde warten lassen, weil dann die Zykluszeitüberwachung die SPS in STOP schaltet

Harald
 
Hallo Ralf.

Wenn ich dein Vorhaben richtig verstanden habe, benötigst du keine WHILE-Schleife. Dafür könntest Du auch eine FOR-Schleife nehmen.
WHILE-Schleifen bergen immer das Risiko, dass sich das Programm festbeißt und der SPS-Zyklus zu lang wird, falls man da Fehler macht.
Deswegen vermeide ich WHILE-Schleifen.

Du könntest am Ende der FOR-Schleife einen Triggerimpuls für einen TOF-Timer setzen. Solange der Timerausgang an ist, hast du dein Kontrollbit und die Schleife könntest du in ein IF einbetten damit die Schleife dann nicht durchlaufen wird.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
das widerspricht dem Konzept der zyklischen Bearbeitung einens sps-programms.
https://www.sps-lehrgang.de/funktionsweise-arbeitsweise-sps/
https://www.google.de/url?sa=t&rct=...10/04/sps.pdf&usg=AOvVaw1NbSfRhW4XFywSP0aYp69-

wenn du das so programmieren würdest, dass die schleife verzögert würde, würde die cpu mit zykluszeitüberschreitung in stop gehen.
und stell dir mal vor sie würde nicht in stop gehen.
jemand drückt während das Programm in der schleife ist den stop taster einer Bewegung oder sonst was. die Reaktion würde erst dann passieren wenn der MA 20 sek (max)
den stop taster drückt. dann ist alles kaputt und 10 menschen tot
 
Zuletzt bearbeitet:
Hallo,

Du hast 2 Probleme
- Du setzt DB500.DBX4.5 direkt vor dem Timer-Aufruf auf TRUE, so daß der Timer am Eingang S immer nur TRUE sehen kann. Er muß aber auch mal FALSE sehen, weil er zum neu starten eine 0-1-Flanke braucht.
- Du kannst die Schleife unmöglich 1 Sekunde warten lassen, weil dann die Zykluszeitüberwachung die SPS in STOP schaltet

Harald

Da hast Du Recht, deshalb suche ich nach einer Lösung, die mir neben der zyklischen Abarbeitung dennoch erst in 1 Sekunde Verzögerung immer dieses beschriebene Bit setzt.
Ich möchte natürlich nicht erst jeweils nach 1 Sekunde (und das 20 mal) den Gesamtcode weiter abarbeiten lassen, damit wäre die Anlage ja für diese Zeit total ausser Kontrolle.
 
das widerspricht dem Konzept der zyklischen Bearbeitung einens sps-programms.
https://www.sps-lehrgang.de/funktionsweise-arbeitsweise-sps/
https://www.google.de/url?sa=t&rct=...10/04/sps.pdf&usg=AOvVaw1NbSfRhW4XFywSP0aYp69-

wenn du das so programmieren würdest, dass die schleife verzögert würde, würde die cpu mit zykluszeitüberschreitung in stop gehen.
und stell dir mal vor sie würde nicht in stop gehen.
jemand drückt während das Programm in der schleife ist den stop taster einer Bewegung oder sonst was. die Reaktion würde erst dann passieren wenn der MA 20 sek (max)
den stop taster drückt. dann ist alles kaputt und 10 menschen tot

Das ist mir bewusst, daher suche ich eine Lösung, die bei zyklischer Abarbeitung des Gesamtprogramms dennoch den Timer in diesem Unterprogramm so berücksichtigt, dass der Schreibbefehl innerhalb der Schleife 20 mal je eine Sekunde ansteht, ohne dass dabei der Ablauf des Gesamtprogramms für diese Zeit unterbrochen wird.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
WHILE-Schleifen bergen immer das Risiko, dass sich das Programm festbeißt und der SPS-Zyklus zu lang wird, falls man da Fehler macht.
Deswegen vermeide ich WHILE-Schleifen.
So'n Quatsch!
:p

WHILE-Schleifen bergen genau das gleiche Risiko für eine Zykluszeitüberschreitung, wie der gesamte Rest des Programms, wenn man falsch programmiert.
Hier z.B. würde auch eine FOR-Schleife nicht fertig werden, wenn die Weiterschaltung der FOR-Variablen erst auf den Timer warten soll.

Wie bei allen anderen Befehlen, muss man sich halt über deren Funktionsweise und der eines SPS-Programms allgemein bewusst sein, um sie richtig einzusetzen.
Dann spricht auch nichts für die Diskriminierung einzelner Befehle, auch wenn man sie vielleicht trotzdem nicht so häufig benötigt.
:wink:
 
Ja du hast Recht:
Mit einer FOR-Schleife kriegt man die Zykluszeit auch in die Knie.
Da muss man aber schon einiges an Abarbeitung reinschreiben oder eine sehr lange Schleife machen.

Eine "klassische" FOR-Schleife läuft einfach durch. Das birgt gerade für Anfänger weniger Fehlerquellen.
 
Hallo Rados,

ich würde das eher so versuchen:
Code:
IF not DB500.DBX4.5 THEN
   FOR i=1 to 20 DO
   //= Code innerhalb der Schleife, der funktioniert
   ...
   END_FOR;
   DB500.DBX4.5:= true;
END_IF;
  
IF CurrTime_2.Q THEN
   DB500.DBX4.5:= false;
END_IF;

CurrTime_2 (IN:=DB500.DBX4.5 , PT:=t#1s , Q=> , ET=> );

Timer und auch andere Programm-Bausteine sollten in der SPS immer zyklisch aufgerufen werden. Daher nie innerhalb von bedingten Aufrufen wie IF, FOR, While…

Liebe Grüße
Lilli
 
Zuletzt bearbeitet:
ich würde das eher so versuchen:
Code:
IF not DB500.DBX4.5 THEN
   FOR i=1 to 20 DO
   //= Code innerhalb der Schleife, der funktioniert
   ...
   END_FOR;
   DB500.DBX4.5:= true;
END_IF;
  
CurrTime_2 (IN:=DB500.DBX4.5 , PT:=t#1s , Q=> , ET=> );

IF CurrTime_2.Q THEN
   DB500.DBX4.5:= false;
END_IF;
Das sieht schon besser aus, allerdings würde auch hier der Timer immer nur DB500.DBX4.5=TRUE sehen und höchstens einmal laufen.
Abhilfe: am einfachsten den Timeraufruf vor die erste Abfrage des DB500.DBX4.5 (und Schleife) setzen und nochmal nachdenken, ob ein S_PEXT, S_PULSE, S_ODT oder S_OFFDT am besten geeignet ist.

Wird der DB500.DBX4.5 eigentlich noch von woanders her gesetzt/rückgesetzt?

Harald
 
Hallo Lilli,

vielen Dank fuer Deinen Vorschlag, der mir aehnlich durch den Kopf ging. Ist es in Deinem Vorschlag nicht so, dass der Timer die For-Schleife anstoesst, die dann 20x durchlaeuft und das tut, was in ihr steht und dann ausser Kraft gesetzt wird, wenn er abgelaufen ist? Doch da beginnt mein Problem, was ich momentan noch nicht geloest sehe. Mit umschreibenden Worten konnte ich das nicht so rueberbringen, es fuehrte eher zu Unklarheiten.

Fuer Dich und auch fuer all die anderen, die so freundlich waren und mir beantwortet haben (vielen Dank dafuer), habe ich das mal grafisch zum Ausdruck gebracht, was da wie funktionieren soll.

Daten in Visu-Tabelle schreiben.jpg

Ich glaube, aus der Grafik geht eher hervor, was ich mit "Schleife soll auf Timer warten" meinte... Ich weiss es nicht anders auszudruecken :) "Wartet die Schleife nicht auf den Timer", dann wird die Liste rechts nicht oder nicht vollstaendig gefaellt, weil es der Visu zu schnell geht (habe ich schon getestet).

LG Ralf

------------------------------------

Hallo Harald,

der DB500.DBX4.5 soll ausschliesslich an dieser Stelle gesetzt / rueckgesetzt werden. Ich brauche ihn, um je eine Zeile meiner erwaehnten Liste in der VISU zu fuellen, allerdings zwingend mit der Zeitcharakteristik, die ich in der Grafik beschreibe.

BG Ralf

PS: Wo kann ich einstellen, dass mir die Forumsoftware nicht die Umlaute zerschiesst?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Rados,

einmal angenommen, das ist keine Hausaufgabe, dann bin ich mir ziemlich sicher, dass du die Aufgabe nicht korrekt verstanden hat. Oder dir hat jemand das ganze unverständlich erklärt! :ROFLMAO:

1) Das umspeichern von DB1 nach DB2 macht nur Sinn, wenn es in einem Zyklus geschieht.
Als Momentaufnahme, damit die Daten sich nicht während der Übertragung ändern können,
aus Gründen der Datenkonsistenz.

2) Ein OPC-Server der immer nur ein Wert lesen kann ist lächerlich. Bevor ich so was einsetzen würde, würde ich die Bits am DA einzeln morsen… :rolleyes:

Liebe Grüße
Lilli
 
mir ist schon klar was du prinzipiel vor hast. der code dazu ist auch nicht alzu komliziert.
aber ich denke das dein ansatz die daten auf den pc zu bekommen ehr falsch ist.
was für eine visu hast du denn? wenn ich das bild richtig interpretiere holt die visu die daten via opc aus der sps.

ansatz.
du schreibst deine 20 datensätze in den db2.
es wird ein bit gesetzt "daten_zur_abholung_bereit". db2 wird für weitere schreibzugriffe "gesperrt"
opc liest dieses bit und holt die 20 datensätze.
opc schreibt "daten_abgeholt". db2 wird wieder freigegeben um die nächsten 20 datensätze aufzunehmen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Lilli / Hallo Volker,


die Grafik enthält lediglich eine stark vereinfachte Darstellung der Abläufe, denn ich wollte die Funktionsweise erklären und was passieren soll bzw. muss und nicht, ob der OPC ausgelastet ist oder nicht. ;) Aber ich sehe ein, nun tiefer eintauchen zu müssen. :)

Beim DB1 handelt es sich um eine Auflistung von insgesamt 20 identischen UDTs. Jeder UDT enthält 203 Dateneinträge (String / Int / Real). Es kommen also 4060 Dateneinträge zusammen, der erste belegt Adresse DB1.DBW0 und der letzte DB1.DBD44046.

Ich benötige für meine Liste (siehe Grafik, ganz rechts) von jedem der 20 UDTs die ersten drei Dateneinträge:

- Fahrzeug-Nummer
- Fahrzeug-Typ
- Zeichnungs-Nummer.

Die hole ich mir beim ersten, zweiten, …, 20sten Schleifendurchlauf in den DB2.

Der DB2 sieht in seiner vertikalen Datenliste so aus:
Adr. 0.0 Fahrzeug-Nr. (INT)
Adr. 2.0 Fahrzeug-Typ (String[25])
Adr. 30.0 Zeichnungs-Nr. (String[25])

Der OPC hat demzufolge die Einträge DB2.DBW0; DB2.DBD2 und DB2.DBD30.

Der Schreib/Lesebaustein der Visualisierung hat diese drei OPC-Variablen als Eingang. (Er ist so von den Entwicklern konstruiert, dass je ein Eingang nur eine Single-Variable aufnehmen kann. Ich kann also keinen Datenblock übertragen.)

Aus diesen Eingängen baut er sich intern eine horizontale Datenliste, und zwar EINE TABELLENZEILE! Diese legt er erst dann in der Tabelle ab, wenn der boolesche Schreib-Eingang (gekoppelt an die OPC-Variable DB500.DBX4.5) mit fallender Flanke einmal aktiviert wird.

Achtung: Würde ich also meinen DB2 mit allen Daten aus dem DB1 füttern (alle ersten 3 Daten aus allen 20 UDTs = 60 Dateneinträge) und würde ich diese 60 Dateneinträge im OPC als Adress-Variablen hinterlegen und diese dann an den Schreib/Lese-Baustein als Eingänge ankoppeln (was natürlich ginge), dann würde der Baustein diese 60 Daten in EINER TABELLENZEILE nebeneinander schreiben! Ich will jedoch meine 20 Fahrzeugdaten (-Nr., -Typ, Zeichnungs-Nr.) untereinander in der Tabelle haben und zwar so:

Fahrzeug(1)-Nr… Fahrzeug(1)-Typ… Zeichnung(1)s-Nr…
Fahrzeug(2)-Nr… Fahrzeug(2)-Typ… Zeichnung(2)s-Nr…
Fahrzeug(3)-Nr… Fahrzeug(3)-Typ… Zeichnung(3)s-Nr…

Fahrzeug(20)-Nr… Fahrzeug(20)-Typ… Zeichnung(20)s-Nr…


Das geht aber nur in der Form
Fahrzeug(1)-Nr… Fahrzeug(1)-Typ… Zeichnung(1)s-Nr… [Schreibbefehl DB500.DBX4.5] {Pause}
Fahrzeug(2)-Nr… Fahrzeug(2)-Typ… Zeichnung(2)s-Nr… [Schreibbefehl DB500.DBX4.5] {Pause}
Fahrzeug(3)-Nr… Fahrzeug(3)-Typ… Zeichnung(3)s-Nr… [Schreibbefehl DB500.DBX4.5] {Pause}

Fahrzeug(20)-Nr… Fahrzeug(20)-Typ… Zeichnung(20)s-Nr… [Schreibbefehl DB500.DBX4.5] {Pause}

Bei 20 Schleifendurchläufen in meinem SCL-Programm hätte ich somit meine 20 x (3 Fahrzeugdaten-Einträge) in Tabellenform untereinander stehen.

Der Bediener der Anlage kann sich jetzt orientieren und die ihn interessierende Fahrzeugnummer in einem Eingabefeld eingeben. Dazu kann er wählen: modifizieren, löschen, Messdaten erstellen, …

Durch weitere FBs werden dadurch mithilfe von Befehlen, wie z.B. BLKMOV, ganze Datenbereiche - indirekt adressiert - selektiert, verschoben, gelöscht, aufgefüllt. Das funktioniert alles schon.
Wird ein Fahrzeugtyp gelöscht, muss die Tabelle natürlich neu aufgebaut werden, damit der neue Datenbestand – dann natürlich ohne Lücke – erscheinen kann. Dazu habe ich in den Code am Anfang einen Timer eingebaut, der an dieser Stelle funktioniert und mit Timer.Q einen einmaligen Löschbefehl an DB500.DBX4.4 ausgibt. Da dieser keine Probleme macht, hatte ich ihn in meinem Code hier im Forum nicht erwähnt. Probleme machen mir immer nur die {Pausen}n für das Schreiben der Zeilen der Tabelle.

Ich denke inzwischen, mit einer Schleife wird das nichts werden, ich werde eine Schrittkette bauen…


BG Ralf
 
das funktioniert schon in einer schleife.
mal auf die schnelle was zusammengetippt.

das mit dem erhöhen der Adresse in der schleife könnte man ein wenig schöner machen.
das erhöhen des DB10.DBD 0 musst du passend machen. kenne die länge deines udt's nicht.
 

Anhänge

  • test.AWL.txt
    3,9 KB · Aufrufe: 18
Zuletzt bearbeitet:
Hallo Volker,

ich danke Dir erst mal für Deine Zeit, die Du für mich investiert hast. Werde den Code heute, sobald ich etwas Zeit habe, mal genau ansehen bzw. testen.

BG Ralf
 
Zurück
Oben