FUNCTION_BLOCK "FB10_puls"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
number_of_pulses : Int;
duration : Time;
breake_time : Time;
start : Bool;
END_VAR
VAR_OUTPUT
Q : Bool;
finished : Bool;
END_VAR
VAR
HM_start : Bool;
HM_01 : Bool;
HM_02 : Bool;
HM_03 : Bool;
R_Trig_start {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : R_TRIG;
HM_number_of_pulses : Int;
HM_breake_time : Time;
HM_duration : Time;
"counter" : Int;
TP_Pulse {InstructionName := 'TP_TIME'; LibVersion := '1.0'} : TP_TIME;
F_Trig_1 {InstructionName := 'F_TRIG'; LibVersion := '1.0'} : F_TRIG;
TP_Breake {InstructionName := 'TP_TIME'; LibVersion := '1.0'} : TP_TIME;
xxx : Int;
END_VAR
BEGIN
#R_Trig_start(CLK:=#start,
Q=>#HM_start);
IF (#HM_start = TRUE) THEN
#HM_number_of_pulses := #number_of_pulses;
#HM_duration := #duration;
#HM_breake_time := #breake_time;
END_IF;
FOR #counter := 0 TO #HM_number_of_pulses DO
#TP_Pulse(IN := #HM_start OR #HM_03,
PT := #HM_duration,
Q => #Q);
#F_Trig_1(CLK := #TP_Pulse.Q,
Q => #HM_01);
#TP_Breake(IN := #HM_01,
PT := #HM_breake_time,
Q => #HM_02);
"F_TRIG_DB"(CLK := #HM_02,
Q => #HM_03);
END_FOR;
END_FUNCTION_BLOCK
Nein, das kann nicht zum Erfolg führen.Die Pulse werden auch erzeugt, aber er zählt die Pulse nicht.
Kann der eingeschlagene weg überhaupt zum erfolg führen?
Code:... FOR #counter := 0 TO #HM_number_of_pulses DO ... END_FOR; END_FUNCTION_BLOCK
Nein, das kann nicht zum Erfolg führen.
Das Prinzip einer SPS wurde hier nämlich nicht beachtet (Hochsprachenprogrammierer?):
Die SPS liest die Eingänge ein, rattert ihr Programm einmal komplett durch und gibt dann entsprechend den letzten Ergebnissen die Ausgänge aus. Dann das Ganze von vorn.
Ich weiss nicht so genau, auf welchen kleinen Unterschied Du hinweisen willst.Nicht ganz, und das ist was viele und vor allend Dingen viele viele SPS Schulungsanbieter vergessen und wehalb auch fast alle Schaubilder im Netz falsch sind:
Der Zyklus beginnt mit dem schreiben des Prozessabbilds der Ausgänge und danach wird wer das PAE gelesen und DANN wird das Programm bearbeitet.
FUNCTION_BLOCK FB_Taktgeber
VAR_INPUT
START : BOOL := TRUE; (* Ein-, Ausschalten *)
PTH : TIME; (* Arbeitstakt *)
PTL : TIME; (* Pausentakt *)
N : UINT; (* Anzahl der Impulse *)
END_VAR
VAR_OUTPUT
Q : BOOL; (* Ausgang *)
BUSY : BOOL; (* Laeuft noch ? , nettes Schmankerl*)
END_VAR
VAR
Timer : TON; (* Damit wir alles realisiert *)
cnt : UINT; (* Counter *)
step : USINT; (* Schrittkette *)
END_VAR
Timer(); (* Immer laufen lassen *)
(* Nun die Schrittkette abarbeiten *)
CASE step OF
0: (* INT: Am Anfang alles einstellen, nullstellen etc.*)
cnt := 0;
Timer.IN := FALSE;
Q := FALSE;
BUSY := FALSE;
IF START THEN
step := 10;
END_IF
10: (* Es geht los: Timer fuellen und aktivieren fuer High *)
Q := TRUE;
BUSY := TRUE;
Timer.PT := PTH;
Timer.IN := TRUE;
IF Timer.Q THEN
Timer.IN := FALSE;
step := 20;
END_IF
20: (* Arbeitstakt ist zu ende, Nun Zaehlen und ggf. mit Pause weiter oder Ende *)
Q := FALSE;
cnt := cnt +1;
IF cnt < N THEN
step := 30;
ELSE
step := 0;
END_IF
30: (* Identisch mit 10, jedoch Pausentakt, könnte man alles mit Toggle-Vars erledigen *)
Q := FALSE;
Timer.PT := PTL;
Timer.IN := TRUE;
IF Timer.Q THEN
Timer.IN := FALSE;
step := 10;
END_IF
END_CASE
END_FUNCTION_BLOCK
warum einfach wenns auch kompliziert geht
Stimmt. Ich frage mich warum für selbst einfache UND-verknüpfungen oder ähnliches scl verwendet wird.Und nebenbei hat der TE in SCL angefangen...
// Jede PulsFolge besteht aus n_pulses Pulsen und n_pulses Pausen.
// Sie beginnt mit dem ersten Puls und endet mit der letzten Pause.
// Der counter wird mit 2 * n_pulses geladen, sofern er auf 0 steht UND run = TRUE ist.
// Bei jedem Ablaufen einer Puls- oder Pause-Zeit wird counter dekrementiert bis counter=0.
// Es werden 3 Zustände unterschieden:
// - counter = 0 : idle (= NOT busy) - die Ausgabe einer PulsFolge ist inaktiv.
// - counter enthält eine gerade Zahl <> 0: TON_Pulse läuft mit hi_time.
// - counter enthält eine ungerade Zahl: TON_Pause läuft mit lo_time.
// Durch Laden oder Dekrementieren von counter wechselt der Zustand und
// dadurch wird der entsprechende TON gestartet.
// Das Laden des counter (= Start der Ausgabe einer PulsFolge) geschieht, wenn
// - schon oder noch run=TRUE ist und der counter in den Zustand idle übergeht,
// - sich der counter im Zustand idle befindet und run in den Zustand TRUE wechselt.
FUNCTION_BLOCK FB_Taktgeber
VAR_INPUT
run : BOOL;
n_pulses : INT;
hi_time : TIME;
lo_time : TIME;
END_VAR
VAR_OUTPUT
pulse : BOOL;
busy : BOOL;
END_VAR
VAR
counter : INT;
TON_Pulse : TON;
TON_Pause : TON;
END_VAR
VAR_TEMP
odd : BOOL;
END_VAR
// Zähler laden ==> PulsFolge Starten
IF (counter = 0) AND run THEN
counter := n_pulses * 2; // Anzahl Pulse + Anzahl Pausen
END_IF;
// Zähler: 0 ==> inaktiv, ungerade ==> Pause, gerade UND counter<>0 ==> Puls
odd := (counter MOD 2)<>0;
// Timer starten
TON_Pulse(IN:=(counter<>0) XOR odd, PT:=hi_time);
TON_Pause(IN:=odd, PT:=lo_time);
// Zähler dekrementieren bei Ablauf von Puls oder Pause
IF TON_Pulse.Q OR TON_Pause.Q THEN
counter := counter - 1;
END_IF;
// Ausgänge
busy := counter<>0; // PulsFolge ausgeben ist aktiv
pulse := ((counter MOD 2)<>0) XOR busy;
END_FUNCTION_BLOCK
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?