Add s7-1500/demo-advance-scl-contol.md
This commit is contained in:
parent
1f1d9a933e
commit
2cf2ab3814
531
s7-1500/demo-advance-scl-contol.md
Normal file
531
s7-1500/demo-advance-scl-contol.md
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
# README — S7-1500 SCL Sequencer (AUTO / INCR) with Pause vs Stop, Stop Categories, Skip/Disable, Safety-Locked Steps
|
||||
|
||||
This project shows a Siemens S7-1500 step sequencer in SCL with:
|
||||
- AUTO mode (advance automatically)
|
||||
- INCR mode (advance only on operator NEXT pulse)
|
||||
- Pause vs Stop
|
||||
- Stop categories (immediate / end-of-step / end-of-cycle / no-stop)
|
||||
- Per-step UDT configuration (timeout + operator text)
|
||||
- Skip/disable steps (optional steps can be disabled)
|
||||
- Prevent disabling safety steps (PLC forces critical steps enabled)
|
||||
|
||||
You can paste the TYPES into "PLC data types" and the FB code into an SCL FB.
|
||||
|
||||
------------------------------------------------------------
|
||||
1) Concepts / How it works
|
||||
------------------------------------------------------------
|
||||
|
||||
1. Step machine (FSM)
|
||||
- Variable "Step" defines the state:
|
||||
Step = 0 -> IDLE
|
||||
Step = 1..10 -> execute step logic
|
||||
- Each step has:
|
||||
- Actions (outputs to command)
|
||||
- Done condition (when it is allowed to advance)
|
||||
- Timeout (if not done within time -> Error)
|
||||
|
||||
2. Modes
|
||||
We use enum E_Mode:
|
||||
- MODE_STOP = 0 (not running, safe outputs)
|
||||
- MODE_AUTO = 1 (auto advance)
|
||||
- MODE_INCR = 2 (manual advance with NEXT)
|
||||
|
||||
Mode selection priority:
|
||||
- If Enable=FALSE OR Cmd_Stop=TRUE OR ErrorActive=TRUE => MODE_STOP
|
||||
- Else if Mode_Auto=TRUE => MODE_AUTO
|
||||
- Else if Mode_Incr=TRUE => MODE_INCR
|
||||
- Else MODE_STOP
|
||||
|
||||
3. Pause vs Stop
|
||||
- STOP:
|
||||
- forces safe outputs (FALSE)
|
||||
- typically sets Step=0 (IDLE)
|
||||
- PAUSE:
|
||||
- freezes step progression and timer
|
||||
- keeps outputs frozen at last values (freeze outputs)
|
||||
|
||||
Pause is implemented by:
|
||||
- PauseLatched toggled by Cmd_Pause edge
|
||||
- when pause becomes TRUE, capture current outputs into Frozen_* variables
|
||||
- while paused, outputs are forced to Frozen_* values
|
||||
|
||||
4. Stop categories (StopReq + StopCat)
|
||||
Enum E_StopCat:
|
||||
- STOPCAT_IMMEDIATE:
|
||||
stop instantly (Step=0 + safe outputs)
|
||||
- STOPCAT_END_OF_STEP:
|
||||
finish current step then stop
|
||||
- STOPCAT_END_OF_CYCLE:
|
||||
continue until the configured end-of-cycle step completes, then stop
|
||||
- STOPCAT_NO_STOP:
|
||||
info only (never stops)
|
||||
|
||||
Stop requests are latched:
|
||||
- STOPCAT_IMMEDIATE / END_OF_STEP / END_OF_CYCLE -> latched in PLC
|
||||
- STOPCAT_NO_STOP -> not latched (only displayed as info)
|
||||
|
||||
5. Per-step configuration via UDT array Cfg[1..10]
|
||||
Each step stores:
|
||||
- Text: shown to operator
|
||||
- Timeout: step timeout
|
||||
- IsEndOfCycle: marks the “cycle end” step
|
||||
- ReqEnabled: HMI requested enable
|
||||
- Enabled: PLC effective enable used by sequencer
|
||||
- SafetyLocked: if TRUE, cannot be disabled
|
||||
- NextStep: optional jump target (0 means normal next)
|
||||
|
||||
The PLC NEVER trusts ReqEnabled directly.
|
||||
PLC computes Enabled every scan:
|
||||
- if SafetyLocked => Enabled := TRUE (and optionally ReqEnabled forced TRUE too)
|
||||
- else Enabled := ReqEnabled
|
||||
|
||||
6. Skip/Disable steps
|
||||
Instead of Step := Step + 1, we compute "next enabled step":
|
||||
- If operator disables a step, sequence jumps over it
|
||||
- A helper FC_NextEnabledStep finds the next enabled step
|
||||
- In AUTO mode we wrap 10->1, in INCR mode we can end at 0
|
||||
|
||||
Optional routing:
|
||||
- If Cfg[Step].NextStep <> 0 then jump to that step (if enabled).
|
||||
|
||||
------------------------------------------------------------
|
||||
2) PLC Data Types (copy into "PLC data types")
|
||||
------------------------------------------------------------
|
||||
|
||||
TYPE E_Mode : USINT (
|
||||
MODE_STOP := 0,
|
||||
MODE_AUTO := 1,
|
||||
MODE_INCR := 2
|
||||
);
|
||||
END_TYPE
|
||||
|
||||
TYPE E_StopCat : USINT (
|
||||
STOPCAT_NONE := 0,
|
||||
STOPCAT_IMMEDIATE := 1,
|
||||
STOPCAT_END_OF_STEP := 2,
|
||||
STOPCAT_END_OF_CYCLE := 3,
|
||||
STOPCAT_NO_STOP := 4
|
||||
);
|
||||
END_TYPE
|
||||
|
||||
TYPE UDT_StepCfg :
|
||||
STRUCT
|
||||
Text : STRING[80]; // Operator text for HMI
|
||||
Timeout : TIME; // Per-step timeout
|
||||
IsEndOfCycle : BOOL; // Marks end-of-cycle step (e.g., step 10)
|
||||
|
||||
ReqEnabled : BOOL; // From HMI/DB (operator request)
|
||||
Enabled : BOOL; // PLC effective enable (used by sequencer)
|
||||
SafetyLocked : BOOL; // If TRUE, PLC forces Enabled := TRUE always
|
||||
|
||||
NextStep : INT; // 0 = normal next enabled step, else jump to 1..10
|
||||
END_STRUCT
|
||||
END_TYPE
|
||||
|
||||
------------------------------------------------------------
|
||||
3) Helper FC: Next enabled step (skip disabled steps)
|
||||
------------------------------------------------------------
|
||||
|
||||
FUNCTION FC_NextEnabledStep : INT
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VAR_INPUT
|
||||
CurrentStep : INT;
|
||||
MaxStep : INT; // 10
|
||||
Wrap : BOOL; // TRUE in AUTO (10->1), FALSE in INCR (end->0)
|
||||
Cfg : ARRAY[1..10] OF UDT_StepCfg;
|
||||
END_VAR
|
||||
VAR
|
||||
s : INT;
|
||||
i : INT;
|
||||
END_VAR
|
||||
BEGIN
|
||||
s := CurrentStep;
|
||||
|
||||
FOR i := 1 TO MaxStep DO
|
||||
s := s + 1;
|
||||
|
||||
IF s > MaxStep THEN
|
||||
IF Wrap THEN
|
||||
s := 1;
|
||||
ELSE
|
||||
FC_NextEnabledStep := 0;
|
||||
RETURN;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
IF Cfg[s].Enabled THEN
|
||||
FC_NextEnabledStep := s;
|
||||
RETURN;
|
||||
END_IF;
|
||||
END_FOR;
|
||||
|
||||
FC_NextEnabledStep := 0; // none enabled
|
||||
END_FUNCTION
|
||||
|
||||
------------------------------------------------------------
|
||||
4) Main FB: Sequencer (AUTO/INCR + Pause/Stop + Stop categories)
|
||||
------------------------------------------------------------
|
||||
|
||||
FUNCTION_BLOCK FB_Seq10_Adv
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
|
||||
VAR_INPUT
|
||||
Enable : BOOL;
|
||||
Mode_Auto : BOOL;
|
||||
Mode_Incr : BOOL;
|
||||
|
||||
Cmd_Start : BOOL;
|
||||
Cmd_Stop : BOOL; // hard stop (safe outputs)
|
||||
Cmd_Pause : BOOL; // toggle pause (freeze)
|
||||
Cmd_ResetErr : BOOL;
|
||||
Cmd_Next : BOOL; // NEXT pulse in increment mode
|
||||
|
||||
StopReq : BOOL; // stop request flag
|
||||
StopCat : E_StopCat; // stop request category
|
||||
|
||||
// Example process inputs (replace with real ones)
|
||||
In_Ready : BOOL;
|
||||
In_ClampClosed : BOOL;
|
||||
In_ProcessDone : BOOL;
|
||||
In_EjectDone : BOOL;
|
||||
|
||||
// Step config from DB/HMI/recipe
|
||||
Cfg : ARRAY[1..10] OF UDT_StepCfg;
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
Step : INT; // 0..10
|
||||
Running : BOOL;
|
||||
Paused : BOOL;
|
||||
|
||||
ErrorActive : BOOL;
|
||||
ErrorCode : WORD;
|
||||
|
||||
HMI_StepText : STRING[80];
|
||||
HMI_StopInfo : STRING[80];
|
||||
|
||||
// Example outputs (replace)
|
||||
Out_ClampClose : BOOL;
|
||||
Out_ProcessOn : BOOL;
|
||||
Out_Eject : BOOL;
|
||||
END_VAR
|
||||
|
||||
VAR
|
||||
Mode : E_Mode;
|
||||
|
||||
rStart : R_TRIG;
|
||||
rNext : R_TRIG;
|
||||
rReset : R_TRIG;
|
||||
rPause : R_TRIG;
|
||||
|
||||
StepPrev : INT;
|
||||
StepEntry : BOOL;
|
||||
|
||||
tStep : TON;
|
||||
|
||||
AllowAdvance : BOOL;
|
||||
|
||||
StopLatched : BOOL;
|
||||
StopLatchedCat : E_StopCat;
|
||||
|
||||
PauseLatched : BOOL;
|
||||
Frozen_ClampClose: BOOL;
|
||||
Frozen_ProcessOn : BOOL;
|
||||
Frozen_Eject : BOOL;
|
||||
|
||||
Cmd_ClampClose : BOOL;
|
||||
Cmd_ProcessOn : BOOL;
|
||||
Cmd_Eject : BOOL;
|
||||
|
||||
i : INT;
|
||||
nxt : INT;
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
// --------- edges ----------
|
||||
rStart(CLK := Cmd_Start);
|
||||
rNext(CLK := Cmd_Next);
|
||||
rReset(CLK := Cmd_ResetErr);
|
||||
rPause(CLK := Cmd_Pause);
|
||||
|
||||
// --------- sanitize step config (prevent disabling safety steps) ----------
|
||||
// IMPORTANT: HMI should write ONLY ReqEnabled, not Enabled or SafetyLocked.
|
||||
FOR i := 1 TO 10 DO
|
||||
IF Cfg[i].SafetyLocked THEN
|
||||
Cfg[i].Enabled := TRUE;
|
||||
Cfg[i].ReqEnabled := TRUE; // reflect back to HMI (optional)
|
||||
ELSE
|
||||
Cfg[i].Enabled := Cfg[i].ReqEnabled;
|
||||
END_IF;
|
||||
END_FOR;
|
||||
|
||||
// --------- reset error ----------
|
||||
IF rReset.Q THEN
|
||||
ErrorActive := FALSE;
|
||||
ErrorCode := WORD#0;
|
||||
Step := 0;
|
||||
StopLatched := FALSE;
|
||||
StopLatchedCat := STOPCAT_NONE;
|
||||
PauseLatched := FALSE;
|
||||
END_IF;
|
||||
|
||||
// --------- mode selection ----------
|
||||
IF (NOT Enable) OR Cmd_Stop OR ErrorActive THEN
|
||||
Mode := MODE_STOP;
|
||||
ELSIF Mode_Auto THEN
|
||||
Mode := MODE_AUTO;
|
||||
ELSIF Mode_Incr THEN
|
||||
Mode := MODE_INCR;
|
||||
ELSE
|
||||
Mode := MODE_STOP;
|
||||
END_IF;
|
||||
|
||||
// --------- start ----------
|
||||
IF rStart.Q AND (NOT ErrorActive) THEN
|
||||
IF Step = 0 THEN
|
||||
// start at first enabled step
|
||||
IF Cfg[1].Enabled THEN
|
||||
Step := 1;
|
||||
ELSE
|
||||
Step := FC_NextEnabledStep(CurrentStep := 0, MaxStep := 10, Wrap := TRUE, Cfg := Cfg);
|
||||
END_IF;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
// --------- latch stop request (category-aware) ----------
|
||||
IF StopReq THEN
|
||||
CASE StopCat OF
|
||||
STOPCAT_IMMEDIATE, STOPCAT_END_OF_STEP, STOPCAT_END_OF_CYCLE:
|
||||
StopLatched := TRUE;
|
||||
StopLatchedCat := StopCat;
|
||||
STOPCAT_NO_STOP:
|
||||
// info only; do not latch stop
|
||||
ELSE
|
||||
// none
|
||||
END_CASE;
|
||||
END_IF;
|
||||
|
||||
// --------- pause toggle ----------
|
||||
IF rPause.Q THEN
|
||||
PauseLatched := NOT PauseLatched;
|
||||
|
||||
// capture outputs when entering pause
|
||||
IF PauseLatched THEN
|
||||
Frozen_ClampClose := Out_ClampClose;
|
||||
Frozen_ProcessOn := Out_ProcessOn;
|
||||
Frozen_Eject := Out_Eject;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
Paused := PauseLatched;
|
||||
|
||||
// --------- running ----------
|
||||
Running := (Mode <> MODE_STOP) AND (Step > 0) AND (NOT ErrorActive) AND (NOT Paused);
|
||||
|
||||
// --------- step entry ----------
|
||||
StepEntry := (Step <> StepPrev);
|
||||
StepPrev := Step;
|
||||
|
||||
// --------- HMI step text ----------
|
||||
IF (Step >= 1) AND (Step <= 10) THEN
|
||||
HMI_StepText := Cfg[Step].Text;
|
||||
ELSE
|
||||
HMI_StepText := 'IDLE';
|
||||
END_IF;
|
||||
|
||||
// --------- stop info ----------
|
||||
HMI_StopInfo := '';
|
||||
IF StopReq AND (StopCat = STOPCAT_NO_STOP) THEN
|
||||
HMI_StopInfo := 'INFO: stop request is NO_STOP (alarm/info only)';
|
||||
ELSIF StopLatched THEN
|
||||
CASE StopLatchedCat OF
|
||||
STOPCAT_IMMEDIATE: HMI_StopInfo := 'Stop requested: IMMEDIATE';
|
||||
STOPCAT_END_OF_STEP: HMI_StopInfo := 'Stop requested: END_OF_STEP';
|
||||
STOPCAT_END_OF_CYCLE: HMI_StopInfo := 'Stop requested: END_OF_CYCLE';
|
||||
ELSE
|
||||
HMI_StopInfo := 'Stop requested';
|
||||
END_CASE;
|
||||
END_IF;
|
||||
|
||||
// --------- if current step disabled -> jump immediately ----------
|
||||
IF (Step >= 1) AND (Step <= 10) THEN
|
||||
IF NOT Cfg[Step].Enabled THEN
|
||||
Step := FC_NextEnabledStep(CurrentStep := Step-1, MaxStep := 10, Wrap := (Mode = MODE_AUTO), Cfg := Cfg);
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
// --------- default commanded outputs ----------
|
||||
Cmd_ClampClose := FALSE;
|
||||
Cmd_ProcessOn := FALSE;
|
||||
Cmd_Eject := FALSE;
|
||||
|
||||
AllowAdvance := FALSE;
|
||||
|
||||
// --------- step timer (does not run while paused) ----------
|
||||
IF StepEntry THEN
|
||||
tStep(IN := FALSE, PT := Cfg[Step].Timeout);
|
||||
END_IF;
|
||||
|
||||
IF (Step >= 1) AND (Step <= 10) THEN
|
||||
tStep(IN := Running, PT := Cfg[Step].Timeout);
|
||||
ELSE
|
||||
tStep(IN := FALSE, PT := T#0S);
|
||||
END_IF;
|
||||
|
||||
// --------- step logic (demo steps, replace with your real logic) ----------
|
||||
CASE Step OF
|
||||
0:
|
||||
;
|
||||
|
||||
1: // WAIT READY
|
||||
IF In_Ready THEN AllowAdvance := TRUE; END_IF;
|
||||
|
||||
2: // CLOSE CLAMP
|
||||
Cmd_ClampClose := TRUE;
|
||||
IF In_ClampClosed THEN AllowAdvance := TRUE; END_IF;
|
||||
|
||||
3: // PROCESS
|
||||
Cmd_ProcessOn := TRUE;
|
||||
IF In_ProcessDone THEN AllowAdvance := TRUE; END_IF;
|
||||
|
||||
4: // EJECT
|
||||
Cmd_Eject := TRUE;
|
||||
IF In_EjectDone THEN AllowAdvance := TRUE; END_IF;
|
||||
|
||||
5,6,7,8,9:
|
||||
// demo pass-through steps
|
||||
AllowAdvance := TRUE;
|
||||
|
||||
10: // END OF CYCLE
|
||||
AllowAdvance := TRUE;
|
||||
|
||||
ELSE
|
||||
ErrorActive := TRUE;
|
||||
ErrorCode := WORD#16#9001; // invalid step
|
||||
END_CASE;
|
||||
|
||||
// --------- timeout -> error ----------
|
||||
IF tStep.Q AND Running THEN
|
||||
ErrorActive := TRUE;
|
||||
ErrorCode := WORD#16#8000 + WORD_TO_WORD(INT_TO_WORD(Step));
|
||||
Mode := MODE_STOP;
|
||||
END_IF;
|
||||
|
||||
// --------- stop category enforcement: immediate stop ----------
|
||||
IF StopLatched AND (StopLatchedCat = STOPCAT_IMMEDIATE) THEN
|
||||
Step := 0;
|
||||
StopLatched := FALSE;
|
||||
StopLatchedCat := STOPCAT_NONE;
|
||||
PauseLatched := FALSE;
|
||||
END_IF;
|
||||
|
||||
// --------- step advance ----------
|
||||
IF (NOT ErrorActive) AND (NOT Paused) THEN
|
||||
|
||||
// Evaluate "advance permission" depending on mode
|
||||
IF (Mode = MODE_AUTO AND AllowAdvance)
|
||||
OR (Mode = MODE_INCR AND AllowAdvance AND rNext.Q) THEN
|
||||
|
||||
// Handle stop-after conditions
|
||||
IF StopLatched AND (StopLatchedCat = STOPCAT_END_OF_STEP) THEN
|
||||
Step := 0;
|
||||
StopLatched := FALSE;
|
||||
StopLatchedCat := STOPCAT_NONE;
|
||||
|
||||
ELSIF StopLatched AND (StopLatchedCat = STOPCAT_END_OF_CYCLE) AND Cfg[Step].IsEndOfCycle THEN
|
||||
Step := 0;
|
||||
StopLatched := FALSE;
|
||||
StopLatchedCat := STOPCAT_NONE;
|
||||
|
||||
ELSE
|
||||
// Compute next step:
|
||||
// 1) optional jump if NextStep configured
|
||||
IF (Step >= 1) AND (Step <= 10) AND (Cfg[Step].NextStep <> 0) THEN
|
||||
nxt := Cfg[Step].NextStep;
|
||||
|
||||
IF (nxt >= 1) AND (nxt <= 10) AND Cfg[nxt].Enabled THEN
|
||||
Step := nxt;
|
||||
ELSE
|
||||
ErrorActive := TRUE;
|
||||
ErrorCode := WORD#16#9100; // invalid NextStep config
|
||||
END_IF;
|
||||
|
||||
ELSE
|
||||
// 2) normal: next enabled step
|
||||
nxt := FC_NextEnabledStep(
|
||||
CurrentStep := Step,
|
||||
MaxStep := 10,
|
||||
Wrap := (Mode = MODE_AUTO),
|
||||
Cfg := Cfg
|
||||
);
|
||||
Step := nxt;
|
||||
END_IF;
|
||||
|
||||
END_IF;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
// --------- output policy: STOP vs PAUSE vs NORMAL ----------
|
||||
IF (Mode = MODE_STOP) OR (Step = 0) OR ErrorActive THEN
|
||||
Out_ClampClose := FALSE;
|
||||
Out_ProcessOn := FALSE;
|
||||
Out_Eject := FALSE;
|
||||
|
||||
ELSIF Paused THEN
|
||||
Out_ClampClose := Frozen_ClampClose;
|
||||
Out_ProcessOn := Frozen_ProcessOn;
|
||||
Out_Eject := Frozen_Eject;
|
||||
|
||||
ELSE
|
||||
Out_ClampClose := Cmd_ClampClose;
|
||||
Out_ProcessOn := Cmd_ProcessOn;
|
||||
Out_Eject := Cmd_Eject;
|
||||
END_IF;
|
||||
|
||||
END_FUNCTION_BLOCK
|
||||
|
||||
------------------------------------------------------------
|
||||
5) Recommended usage in OB1
|
||||
------------------------------------------------------------
|
||||
|
||||
- Create an instance DB for FB_Seq10_Adv.
|
||||
- Fill Cfg[1..10] with texts/timeouts and safety locks.
|
||||
|
||||
Typical values:
|
||||
- Step 1: Text='Wait Ready', Timeout=T#10S, SafetyLocked=TRUE (if required)
|
||||
- Step 2: Text='Close Clamp', Timeout=T#5S, SafetyLocked=TRUE
|
||||
- Step 10: Text='Cycle End', Timeout=T#2S, IsEndOfCycle=TRUE
|
||||
|
||||
Operator can only toggle:
|
||||
- Cfg[i].ReqEnabled for optional steps (SafetyLocked=FALSE)
|
||||
|
||||
Run modes:
|
||||
- AUTO: Mode_Auto=TRUE
|
||||
- INCR: Mode_Incr=TRUE and use Cmd_Next pulses
|
||||
|
||||
Stop:
|
||||
- Cmd_Stop -> immediate safe stop
|
||||
- StopReq+StopCat:
|
||||
- END_OF_CYCLE for "stop after part"
|
||||
- END_OF_STEP for "stop after step"
|
||||
- IMMEDIATE for urgent stop
|
||||
- NO_STOP for warnings/info
|
||||
|
||||
Pause:
|
||||
- Cmd_Pause toggles pause/resume (outputs frozen + timer frozen)
|
||||
|
||||
------------------------------------------------------------
|
||||
6) What to customize next (common in production)
|
||||
------------------------------------------------------------
|
||||
|
||||
1) Split outputs into "Freeze on pause" and "Force safe on pause" groups.
|
||||
2) Add per-step "StopAllowed" (some steps must never stop mid-step).
|
||||
3) Add alarm integration with FIFO + timestamps (your previous alarm project).
|
||||
4) Add step entry actions (run once on step change):
|
||||
- reset internal flags
|
||||
- start motion commands
|
||||
- log step start time
|
||||
5) Add interlocks:
|
||||
- if safety chain open -> force STOPCAT_IMMEDIATE
|
||||
|
||||
END OF README
|
||||
Loading…
Reference in a new issue