Schrittrelais mit Logo

Zuviel Werbung?
-> Hier kostenlos registrieren
Hab' Dir mal eine SBR rausgesucht, die einen mehrfach verwendbaren Timer mit Einschaltverzögerung darstellt:
Code:
[FONT=courier new]SUBROUTINE_BLOCK SBR_TON:SBR61
TITLE=Mehrfach verwendbarer Timer mit Einschaltverzögerung (TON)

VAR_INPUT
Start:BOOL;    // L0.0
PT:INT;    // LW1, in ms
END_VAR

VAR_IN_OUT
Memory:DINT;    // LD3
END_VAR

VAR_OUTPUT
Ausgang:BOOL;    // L7.0
CV:INT;    // LW8
END_VAR

VAR
Diff:DINT;    // LD10
END_VAR


BEGIN

Network 1 // Start = Low
// Bei inaktivem Start-Eingang den Speicher mit 0 beschreiben
LDN    L0.0
UD<>   LD3, 0
MOVD   0, LD3

Network 2 // Start = High
// Bei Aktivierung des Start-Eingang den Speicher mit der aktuellen Systemzeit beschreiben.
LD     L0.0
UD=    LD3, 0
BITIM  LD3

Network 3 // Gespeicherte Zeit erkennbar machen
// Ist die so gespeicherte Systemzeit zufällig gerade = 0, dann im Speicher um 1 ms erhöhen, damit die Speicherung erkannt wird
LD     L0.0
UD=    LD3, 0
INCD   LD3

Network 4 // Timerwert
// Ist die gespeicherte Systemzeit <>0, dann mit der aktuellen Systemzeit vergleichen und die Differenz als Timerwert ausgeben
LDD<>  LD3, 0
CITIM  LD3, LD10
UENO
DTI    LD10, LW8

Network 5 // Ausgang
// Das Timerbit setzen, wenn der Timerwert >= dem Vorgabewert.
LD     L0.0
UW>    LW1, 0
UW>=   LW8, LW1
=      L7.0

END_SUBROUTINE_BLOCK[/FONT]
Die Funktion ist genauso, wie die systeminterne Funktion TON. Der Unterschied ist, das die Speicherung der Zwischendaten über den Ein-/Ausgang Memory in einer selbst gewählten Variable erfolgt (die Ausgänge natürlich auch), anstatt die Systemvariable Tx zu verwenden. Damit kann man die auch mit einer lokalen Variable belegen und so über die Schnittstelle der SBR nach außen weiter geben.

Wenn Du den Code in einer Textdatei mit der Endung .awl speicherst und diese Datei dann in Dein Projekt importierst, kannst Du ja ein bißchen damit herum experimentieren.
Ich hab' extra eine hohe SBR-Nummer gewählt, damit solltest Du keine Probleme mit vlt. schon vorhandenen SBRs bekommen.
Die Ansicht oben ist in AWL. Ich hab' die originalen Netzwerke so umgestaltet/aufgetrennt, dass Du über das Menü Ansicht diese auch auf KOP oder FUP umstellen kannst, je nachdem, was Du bevorzugst.
 
Zuletzt bearbeitet:
Flanken selbst programmiert

Hi Taschenklemme,

hier noch die selbstprogrammierten Flanken, die Du vlt. brauchen wirst:
Code:
[FONT=courier new]Network 1 // Flanke positiv (EU)
[/FONT][FONT=courier new]// Wenn der Eingang #IN HIGH ist und im vorigen Zyklus LOW war, dann Flanke = TRUE[/FONT]
[FONT=courier new]LD     #IN[/FONT]
[FONT=courier new]UN     #Memory[/FONT]
[FONT=courier new]=      #EU[/FONT]
[FONT=courier new]
Network 2 //Flanke negativ (ED)[/FONT]
[FONT=courier new]// Wenn der Eingang #IN LOW ist und im vorigen Zyklus HIGH war, dann Flanke = TRUE[/FONT]
[FONT=courier new]LDN    [/FONT][FONT=courier new]#IN[/FONT]
[FONT=courier new]U      [/FONT][FONT=courier new]#Memory[/FONT]
[FONT=courier new]=      #ED[/FONT]
[FONT=courier new]
Network 3 // Zustand speichern[/FONT]
[FONT=courier new]// Den Zustand von #IN [U]nach[/U] dem Vergleich auf #Memory übertragen[/FONT]
[FONT=courier new]LD     [/FONT][FONT=courier new]#IN[/FONT]
[FONT=courier new]=      [/FONT][FONT=courier new]#Memory[/FONT]
Genau wie bei den systeminternen Flanken wird immer der Zustand eines Bits mit dem Zustand des vorigen Zyklus verglichen. Nach dem Vergleich wird dann der Zustand des aktuellen Zyklus für den nächsten Zyklus wieder abgespeichert. Das muss über eine Variable außerhalb der SBR erfolgen, da temporäre lokale Variablen nach Ausführung der SBR (normalerweise) wieder gelöscht werden.
Bei mehrfach verwendeten SBRs macht man dies über IN-/OUT-Variablen außerhalb der SBR.

PS: Systeminterne Flanken sind meines Wissens nach auch auf 256 Stück im Programm begrenzt. Eigene natürlich nicht.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vorweg erstmal vielen Dank für deine Mühe.

Ich habe deine Timer-SBR mal importiert, aber das ist schon schwere Kost :)
Ich versuche gerade durch Vergleich und mit deinen Hinweise herauszufinden, was was ist. Mit meiner wenigen Erfahrung ist das nicht so leicht :)

In der Hilfe habe ich mir gerade mal die Infos zu Unterprogrammen durchgelesen.

Damit habe ich nun mal versucht deinen Timer zu verstehen. Bisher meine ich es so verstanden zu haben:

Mit "Start" (Bool) startet man den Timer. Wenn Start = 0, dann wird auch der Timer auf 0 gesetzt. Es ist also kein speichernder Timer.

Mit "PT" (Integer) gibt man den Schwellwert in ms an, ab dem der Ausgang auf 1 schaltet. Ich vermute, den Eingang könnte man auch mit einer Variablen füttern. Wenn ich dort z.B. "M5" angebe, dann bekommt die M5 mit einer grünen Schlange unterlegt. Wenn ich "MW5" angebe, dann gibt es keine Schlange.

In "Memory" (DINT) wird die Startzeit abgelegt, bei der "Start" zuletzt gesetzt worden ist. Ich muss dort also einen Speicherbereich angeben, in dem, dieser Wert global abgelegt wird. Z.B.: "MD3"

"Ausgang" (Bool) wird 1, wenn der Schwellwert erreicht worden ist, sonst 0.

"CV" (Int) ist die Differenz zwischen Systemzeit und Startzeit. Daran kann ich also ablesen, wie lange der Timer schon läuft.


Was mache ich mit "EN"? Ich schätze, das muss ich auf "1" setzen, damit das Unterprogramm aufgerufen wird. Was ist, wenn ich es nicht aufrufe? Die Werte gehen dadurch nicht verloren. Das ergibt wohl nur dann Sinn, wenn man umfangreichere Programme hat und dadurch Rechenzeit einsparen kann.


Insgesamt sieht das für mich nun so aus:
Du hast durch Vergleich mit der Systemzeit einen Timer in einem Unterprogramm gebaut, der die jeweiligen Startzeiten in einem globalen Speicherbereich "rettet", damit man das Unterprogramm mehrmals an unterschiedlichen Stellen aufrufen kann.
Sehe ich es richtig, dass das nur funktioniert, wenn man das Unterprogramm aus dem Hauptprogramm heraus aufruft? Wenn man deinen Timer aus einem Unterprogramm heraus aufruft, müsste dieses Unterprogramm wiederum die Timerwerte an das Hauptprogramm weitergeben, damit die nicht verloren gehen, richtig?


Wenn das wirklich so ist, dann baut man sich auf die Art ein paar Fallstricke ein, wenn man später noch mal etwas an dem Programm ändern möchte.

Wäre es eigentlich sinnvoll im Hauptprogramm Merkerbytes als Zwischenspeicher zu verwenden, oder kann man da auch etwas aus dem L-Bereich nehmen?
 
Fast alles richtig erkannt.

...
Mit "Start" (Bool) startet man den Timer. Wenn Start = 0, dann wird auch der Timer auf 0 gesetzt. Es ist also kein speichernder Timer.
...
Speichernd schon, aber nicht im System, sondern dort wo Du es festlegst. Mit der 0 erkennt das Programm, dass bis dahin noch keine Start-Zeit gespeichert wurde.



...
Mit "PT" (Integer) gibt man den Schwellwert in ms an, ab dem der Ausgang auf 1 schaltet. Ich vermute, den Eingang könnte man auch mit einer Variablen füttern. Wenn ich dort z.B. "M5" angebe, dann bekommt die M5 mit einer grünen Schlange unterlegt. Wenn ich "MW5" angebe, dann gibt es keine Schlange.
...
Der Eingang muß eine Variable vom Typ INTeger sein, genau wie beim systeminternen Timer. Das kann ein fester Wert sein (z.B. 2000), der Wert in einer externen Variablen (z.B. MW.. oder VW...) oder aber wieder eine lokale Variable (#... / LW..).



...
In "Memory" (DINT) wird die Startzeit abgelegt, bei der "Start" zuletzt gesetzt worden ist. Ich muss dort also einen Speicherbereich angeben, in dem, dieser Wert global abgelegt wird. Z.B.: "MD3"
...
Richtig. Hier ist durch die verwendete Funktion BGN_ITIME der Typ auf DINT festgelegt, man braucht also ein Doppelwort.



...
"Ausgang" (Bool) wird 1, wenn der Schwellwert erreicht worden ist, sonst 0.

"CV" (Int) ist die Differenz zwischen Systemzeit und Startzeit. Daran kann ich also ablesen, wie lange der Timer schon läuft.
...
Wieder richtig!



...
Was mache ich mit "EN"? Ich schätze, das muss ich auf "1" setzen, damit das Unterprogramm aufgerufen wird. Was ist, wenn ich es nicht aufrufe? Die Werte gehen dadurch nicht verloren. Das ergibt wohl nur dann Sinn, wenn man umfangreichere Programme hat und dadurch Rechenzeit einsparen kann.
...
Ja, damit aktiviert/deaktiviert man eine SBR. Ich würde dazu raten, eine SBR in jedem Zyklus auszuführen und innerhalb der SBR zu bestimmen, was wie ausgeführt wird. Man kann die Ausführung auch überspringen, aber oft reagieren dann die Ausgänge nicht so, wie wann's eigentlich erwarten würde. Ich sag' jetzt mal: "Ist was für später, momentan immer Sondermerker SM0.0 (Immer_Ein) anlegen."



...
Insgesamt sieht das für mich nun so aus:
Du hast durch Vergleich mit der Systemzeit einen Timer in einem Unterprogramm gebaut, der die jeweiligen Startzeiten in einem globalen Speicherbereich "rettet", damit man das Unterprogramm mehrmals an unterschiedlichen Stellen aufrufen kann.
Sehe ich es richtig, dass das nur funktioniert, wenn man das Unterprogramm aus dem Hauptprogramm heraus aufruft? Wenn man deinen Timer aus einem Unterprogramm heraus aufruft, müsste dieses Unterprogramm wiederum die Timerwerte an das Hauptprogramm weitergeben, damit die nicht verloren gehen, richtig?
...
Jein. Wenn das aufrufende Unterprogramm nur einmal pro Zyklus verwendet wird, kann man natürlich auch absolute Adressen verwenden. So wie T1 eben auch eine absolute Adresse ist.
Der Vorteil ist, wie Du richtig erkannt hast, daß man aber auch lokale Variablen verwenden und die SBR damit mehrmals pro Zyklus benutzen kann, da damit die absolute Adresse wieder außerhalb angegeben wird.



...
Wenn das wirklich so ist, dann baut man sich auf die Art ein paar Fallstricke ein, wenn man später noch mal etwas an dem Programm ändern möchte.
...
Wieder jein. Wichtig ist, seine lokalen Variablen aussagekräftig zu bezeichnen.
Ein normales UND funktioniert im Prinzip genauso. Siemens weiß ja vorher auch nicht, welche Ein- und Ausgänge Du an dieses Gatter legst. Also steht innerhalb des Gatters (SBR) Eingang1 mit Eingang2 als UND zum Ausgang verknüpfen und Du schreibst dann draußen dran, welche Adressen das in Wirklichkeit sind.



...
Wäre es eigentlich sinnvoll im Hauptprogramm Merkerbytes als Zwischenspeicher zu verwenden, oder kann man da auch etwas aus dem L-Bereich nehmen?
Wie gesagt, für alles, was mehrfach mit verschiedenen Sachen im Zyklus benutzt werden soll, benutzt man lokale Variablen, z.B. die Eingänge für die Taster -> die unterscheiden sich ja von Rollladen zu Rolladen. Die Zeit soll vlt. immer gleich sein, also könnte man die auch über ein Merkerwort übergeben.
PS: In meinen Augen ist es aber eine gute Angewohnheit, innerhalb von SBR's möglichst immer lokale Variablen zu verwenden.
 
Zuletzt bearbeitet:
Hi Taschenklemme,

hier noch die selbstprogrammierten Flanken, die Du vlt. brauchen wirst:

Danke Hucki. Ich komm gar nicht hinterher :)

Ich habe es gerade einfach versucht zu importieren, aber dabei bekomme ich einen Parserfehler.
Ich muss wohl noch die Variablen definieren.

Memory muss wieder In/out werden.
"In" ist eine Eingangsvariable und EU und ED sind die Ausgangsvariablen, die anzeigen, ob eine Flanke aufgetreten ist.
Damit gibt es auch keine Parserfehler mehr :)

Also die systeminternen Flanken funktionieren einfacher :)
Aber ich steh ja noch ganz am Anfang.


Ist es eigentlich sinnvoll, so etwas Simples, wie die Flankenauswertung als SBR abzulegen? Da man eh für jede Flanke einen eigenen globalen Speicher braucht, könnte man das doch auch gleich komplett im Hauptprogramm programmieren.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nein, sowas einfaches würde ich auch nicht als eigene SBR ablegen. Das sollte nur aufzeigen, wie man Flanken selbst programmiert. Ein UND von vorher und jetzt und dann jetzt wieder als vorher abspeichern. Genauso macht es auch das System.
 
Zurück
Oben