1. System Architecture Overview
The exhaust dyeing machine requires a flexible batch control system where the operator can compose an arbitrary sequence of process steps on the HMI before pressing start. Each step contains an arbitrary selection of unit operations drawn from a library of 48 function blocks, and every function selected for a given step must execute simultaneously. A single physical action (a function) can appear in multiple steps with different parameter sets, so the architecture must treat the 48 FBs as a library of types rather than a fixed list of 48 singletons.
The reference architecture decomposes the controller into four cooperating layers:
- Hardware abstraction FBs (FB100-FB147) – 48 reusable unit-operation blocks covering heating, cooling, water filling, drain, circulation, chemical dosing, color dosing, agitation, pH dosing, sampling, rinsing, and similar exhaust-dyeing primitives. Each is parameterised at call time, never hard-wired.
- Recipe DB (DB200) – a structured data block holding an array of N steps, each step containing an array of (FB-number, instance-pointer, parameter-set) tuples.
- Batch engine FB (FB200) – the sequencer. It walks the recipe array, raises the "StepActive" flag for the current step, dispatches calls to every FB whose index is listed in the current step, evaluates a per-step done-condition, and advances to the next step.
- HMI panel (WinCC flexible / TIA WinCC) – provides the recipe editor screen, the live run screen, the fault display, and the Continue button used after an interruption.
For an S7-300 with this scope, a CPU 315-2 PN/DP (6ES7315-2EH14-0AB0) with a 16 KB work memory is the minimum; a CPU 317-2 PN/DP (6ES7317-2EK14-0AB0) with 1 MB work memory is recommended if all 48 instance DBs are to be held in load memory. Programming can be done in STEP 7 V5.5 SP2 or in TIA Portal V16 with the S7-300 Add-On package.
2. S7-300 Hardware Selection and I/O Allocation
An exhaust dyeing machine typically uses the following I/O classes. Quantities below are reasonable for a 200-500 kg machine; scale them to your installation.
| Signal class | Typical count | Module example | Order number |
|---|---|---|---|
| Digital inputs (24 V DC) | 64 | SM 321 DI32x24VDC | 6ES7321-1BL00-0AA0 |
| Digital outputs (24 V DC, 0.5 A) | 32 | SM 322 DO32x24VDC/0.5A | 6ES7322-1BL00-0AA0 |
| Relay outputs (valves, heaters) | 16 | SM 322 DO16x230VAC/2A RLY | 6ES7322-1HH01-0AA0 |
| Analog inputs (PT100 / 4-20 mA) | 8 | SM 331 AI8xTC/4xRTD | 6ES7331-7PF11-0AB0 |
| Analog outputs (VFD speed, control valves) | 4 | SM 332 AO4x12Bit | 6ES7332-5HD01-0AB0 |
Wire RTD temperature sensors (bath, jacket, dosing tank) into the AI8 module. Drive VFDs for the circulation pump and the agitator from the AO module. Hard-wire the steam valve, drain valve, and inlet valves to relay outputs sized for inductive loads; for inductive DC valves add a free-wheeling diode (1N4007) directly at the coil.
3. Function Block Library (48 Unit Operations)
Each of the 48 unit operations is implemented as an FB with a uniform interface. This uniformity is the single most important architectural decision: the batch engine can dispatch any function by index without case-by-case glue logic.
Standard FB interface (SCL):
FUNCTION_BLOCK FB_Template
VAR_INPUT
iEnable : BOOL; // 1 = function is allowed to run
iStart : BOOL; // 1 = operator/HMI issues run command
iAbort : BOOL; // 1 = emergency or recipe abort
iParams : ARRAY[1..16] OF REAL; // parameter slot
iSetpoint : REAL; // primary setpoint (e.g. temperature, level)\i>
END_VAR
VAR_OUTPUT
oRunning : BOOL;
oDone : BOOL; // pulses for one cycle on completion
oError : BOOL;
oErrorId : WORD;
oActual : REAL;
END_VAR
VAR
State : INT; // 0=Idle,1=Ramp,2=Hold,3=Done,99=Fault
TonHold : TON; // holds for iParams[2] seconds
TonRamp : TON;
END_VAR
BEGIN
IF iAbort THEN State := 99; oError := TRUE; oErrorId := 16#F001; RETURN; END_IF;
IF NOT iEnable THEN State := 0; oRunning := FALSE; oDone := FALSE; RETURN; END_IF;
CASE State OF
0: // Idle
oRunning := FALSE; oDone := FALSE;
IF iStart THEN State := 1; END_IF;
1: // Ramp / approach setpoint
oRunning := TRUE;
IF Abs(oActual - iSetpoint) < iParams[1] THEN State := 2; END_IF;
2: // Hold
TonHold(IN := TRUE, PT := REAL_TO_TIME(iParams[2] * 1000));
IF TonHold.Q THEN TonHold(IN := FALSE); State := 3; END_IF;
3: // Done
oRunning := FALSE; oDone := TRUE;
IF NOT iStart THEN State := 0; oDone := FALSE; END_IF;
END_CASE;
END_FUNCTION_BLOCK
Derive the 48 production FBs by inheritance: each one keeps the same input/output shape and only changes the body. Examples for an exhaust dyeing machine:
| FB # | Name | Drives | Done condition |
|---|---|---|---|
| FB100 | HeatJacket | Steam valve Q1, PT100 bath | Bath ≥ iSetpoint for iParams[2] s |
| FB101 | CoolJacket | Cooling water valve Q2 | Bath ≤ iSetpoint for iParams[2] s |
| FB102 | FillWater | Inlet valve Q3, flow meter FI1 | Total volume ≥ iSetpoint (L) |
| FB103 | DrainTank | Drain valve Q4, level switch LSH | LSH = empty for 5 s |
| FB104 | Circulate | Circulation pump P1, VFD speed | Hold for iParams[2] s |
| FB105 | Agitate | Agitator VFD | Hold for iParams[2] s |
| FB106-FB115 | DoseChemical 1..10 | Peristaltic pump, contact meter | Delivered volume ≥ iSetpoint |
| FB116-FB135 | DoseDye 1..20 | Dye pump, flow integrator | Delivered volume ≥ iSetpoint |
| FB136 | HoldTemp | Jacket control loop | Hold for iParams[2] s within ±iParams[1] °C |
| FB137 | SampleValve | Sample valve Q5 | Hold for iParams[2] s |
| FB138 | Rinse | Inlet + drain (sequenced) | iParams[1] cycles done |
| FB139 | pHControl | Acid/base dosing pumps | pH within ±0.1 of setpoint for 30 s |
| FB140-FB147 | Custom / spare | Reserved | User-defined |
Error codes common to all FBs: 16#F001 = aborted, 16#F002 = sensor break, 16#F003 = over-temperature, 16#F004 = timeout, 16#F005 = external interlock open. The engine collects oErrorId in a centralized fault DB (DB210) for HMI display.
4. Recipe Data Structure
DB200 holds the recipe. Keep it structured so the HMI can browse and edit it symbolically. Use a UDT for the step record so every step has the same shape.
TYPE UDT_Step :
STRUCT
StepNo : INT; // 1..MAX_STEP
FnCount : INT; // how many FBs in this step
FnIndex : ARRAY[1..16] OF INT; // FB number 100..147
FnSetpoint : ARRAY[1..16] OF REAL; // primary setpoint
FnParams : ARRAY[1..16,1..4] OF REAL; // parameter slot
StepDoneCond : INT; // 0=AND, 1=OR, 2=ANY (majority)
MaxStepTime_s : INT; // 0 = no timeout
END_STRUCT
END_TYPE
DATA_BLOCK DB200 // Recipe
STRUCT
RecipeId : STRING[32];
NSteps : INT; // active step count
Step : ARRAY[1..64] OF UDT_Step;
RecipeCRC : DWORD; // integrity check
END_STRUCT
BEGIN
// initial values here if loading from a default
END_DATA_BLOCK
5. Batch Sequence Engine (FB200)
The engine is the heart of the system. It runs in OB1 (free cycle) or OB35 (100 ms cyclic interrupt for a deterministic tick). It uses a small state machine:
- S0 = Idle (recipe loaded, not started)
- S1 = Running step n
- S2 = Step n done, dwell for iParams[1] s
- S3 = All steps done
- S9 = Hold (pause)
- S99 = Fault
FUNCTION_BLOCK FB200_BatchEngine
VAR_INPUT
iStart : BOOL;
iStop : BOOL;
iReset : BOOL;
END_VAR
VAR_OUTPUT
oStepNo : INT;
oState : INT;
oFaultId : WORD;
oAllDone : BOOL;
END_VAR
VAR
State : INT;
CurStep : INT;
TmrDwell : TON;
TmrStep : TON;
TmrGlobal : TON;
i : INT;
ActiveMask: ARRAY[1..16] OF BOOL; // which FBs in current step are active
END_VAR
BEGIN
// Global abort
IF iStop THEN State := 0; CurStep := 0; oAllDone := FALSE; END_IF;
IF iReset THEN State := 0; CurStep := 0; oAllDone := FALSE; oFaultId := 0; RETURN; END_IF;
CASE State OF
0: // Idle
CurStep := 0; oStepNo := 0; oAllDone := FALSE;
IF iStart AND DB200.NSteps > 0 THEN
State := 1; CurStep := 1; ActiveMask := FALSE;
END_IF;
1: // Run current step
oStepNo := CurStep;
// Mark each FB listed in this step as enabled
FOR i := 1 TO DB200.Step[CurStep].FnCount DO
ActiveMask[i] := TRUE;
END_FOR;
// Per-step timeout
IF DB200.Step[CurStep].MaxStepTime_s > 0 THEN
TmrStep(IN := TRUE, PT := REAL_TO_TIME(DB200.Step[CurStep].MaxStepTime_s * 1000));
IF TmrStep.Q THEN State := 99; oFaultId := 16#F004; TmrStep(IN := FALSE); END_IF;
END_IF;
// Evaluate done condition (AND/OR/ANY)
IF StepComplete(DB200.Step[CurStep], ActiveMask) THEN
TmrStep(IN := FALSE);
State := 2;
FOR i := 1 TO 16 DO ActiveMask[i] := FALSE; END_FOR;
END_IF;
2: // Dwell between steps
TmrDwell(IN := TRUE, PT := REAL_TO_TIME(DB200.Step[CurStep].FnParams[1,1] * 1000));
IF TmrDwell.Q THEN
TmrDwell(IN := FALSE);
IF CurStep >= DB200.NSteps THEN
State := 3;
ELSE
CurStep := CurStep + 1;
State := 1;
END_IF;
END_IF;
3: // All done
oAllDone := TRUE;
IF NOT iStart THEN State := 0; oAllDone := FALSE; END_IF;
99: // Fault
// stays here until iReset
;
END_CASE;
END_FUNCTION_BLOCK
The dispatcher StepComplete(...) checks every FB instance whose index is listed in the step. The mapping of FB number to instance DB is held in DB220 (a 48-element array of INT containing instance-DB numbers). When the engine wants to call FB n in step k, it loads DB[n] via OPN DB[InstanceNo] and calls the FB with the parameter set from DB200.Step[k].FnParams. The cleanest way in STEP 7 V5.5 is to use indirect addressing with a CASE that has 48 arms; in TIA Portal you can use a generic FB_MultiInstance pattern with AT-variables.
6. Simultaneous Execution and Function Re-use
Simultaneous execution is handled by the dispatcher calling every listed FB every scan within OB1. Because OB1 runs faster than the slowest process time constant (typical 100 ms), all 48 functions see iEnable = TRUE on the same cycle and their state machines run in lockstep.
Function re-use across steps is solved with a one-to-one map between FB number and FB instance DB. A physical operation (e.g. "heat jacket") is one FB (FB100) with one instance DB (DB100). When the same FB number appears in step 1 and step 5 with different setpoints, the engine simply re-calls FB100 with the new parameters; FB100's state machine and oDone pulse are reset only on a rising edge of iStart, which the engine issues at the start of each step via a per-FB one-shot. This is what makes the source's requirement "function used in step 1 can be used again in step 5" achievable without duplicating the FB.
// One-shot pattern in SCL (inside engine, per FB per step transition)
IF newStep_started THEN
FB100_DB.iStart := TRUE; // rising edge -> FB state machine leaves Idle
ELSE
FB100_DB.iStart := FALSE;
END_IF;
7. Resumable Execution and State Persistence
The operator requirement "if a fault or power failure occurs, HMI shows it and a Continue button resumes from where it stopped" is implemented by combining three mechanisms:
- Retentive data blocks. Declare DB200 (recipe) and DB210 (engine state) as retentive in the CPU's hardware configuration. The PLC will preserve them across power-down because the S7-300's retentive area is backed by the MMC for CPU 31xC and above. See the S7-300 CPU 31xC technological functions manual for the exact retention boundaries.
- Periodic checkpoint. Every 5 s, the engine writes a small struct (CurStep, State, per-FB state) to a retentive DB (DB230). The HMI "Continue" button is enabled only when DB230.CheckpointValid = TRUE.
- Resume from checkpoint. On Continue, the engine reads DB230 and seeds CurStep and the per-FB states, then transitions directly to S1 (Run step) with the same parameter set that was active at the moment of the fault.
// Checkpoint write in OB35 (100 ms cyclic) – executed every 50 cycles (5 s)
IF "clk_5s" THEN
DB230.LastStep := FB200_BatchEngine.CurStep;
DB230.LastState := FB200_BatchEngine.State;
DB230.CheckpointValid := TRUE;
DB230.CheckpointCRC := CRC32(DB230);
END_IF;
For an S7-300 without a buffered CPU, fit a MMC 512 KB (6ES7953-8LM20-0AA0) and enable all DBs as retentive; without retention, resume cannot survive a power-off.
8. HMI Integration with WinCC
Target a 10-inch Comfort Panel (TP1200 Comfort, 6AV2124-1MC01-0AX0) or a PC runtime. TIA WinCC V16 supports symbol-based tag binding, so the recipe DB and engine DB are accessible as plain PLC tags on the panel without manual pointer configuration.
Recommended screens:
-
Recipe Edit – a table view bound to
DB200.Step[1..NSteps]with the FnIndex column displayed as a drop-down of the 48 FB numbers, FnSetpoint as a numeric field, and FnParams[1..4] as four numeric fields. Save the recipe by writing to DB200 only when the engine is in State 0. - Run – large numerals for oStepNo, oState, and a colour-coded bar showing ActiveMask[1..16] for the current step.
- Alarms – use the standard WinCC alarm logging on the oErrorId word. Map codes 0xF001-0xF00F to text strings in the alarm text library.
-
Continue – a button enabled by the tag
DB230.CheckpointValidand the permission tagOperator.Level ≥ 2. Its click event calls the FCFC_Resumein the PLC.
// FC_Resume (called by HMI Continue button)
IF DB230.CheckpointValid AND NOT FB200_BatchEngine.oAllDone THEN
FB200_BatchEngine.CurStep := DB230.LastStep;
FB200_BatchEngine.State := DB230.LastState;
DB230.CheckpointValid := FALSE; // consume
END_IF;
For legacy STEP 7 V5.5 + WinCC flexible 2008 SP5 the screen design is the same; the only difference is the HMI tag import procedure, which uses the "Connections / Tags" editor rather than the TIA Portal device view. The WinCC flexible 2008 SP5 migration guide documents the import workflow.
9. Error Handling and Fault Display
Centralise every FB's oErrorId in DB210:
DATA_BLOCK DB210
STRUCT
FaultActive : BOOL;
FaultId : WORD;
FaultSourceFB : INT; // 100..147
FaultStep : INT;
FaultTimeStamp: DATE_AND_TIME;
FaultMessage : STRING[80];
END_STRUCT
END_DATA_BLOCK
On every cycle, the engine scans DB210 and writes a single message to a panel alarm buffer. WinCC picks it up via the alarm log. The HMI's alarm screen must display FaultStep, FaultSourceFB, and the FaultTimeStamp so the operator can decide between manual reset and "Continue from where it stopped". The Continue button is the practical realization of the source's requirement that a power-failure or fault must be recoverable.
10. Commissioning and Verification
Commission in five passes:
- I/O check. With the PLC in Stop, force every output and verify the corresponding field device (valve opens, pump starts, VFD ramps). Verify every input by hand-actuating the sensor.
- FB single-step. With the engine disabled, set DB200.NSteps = 1, FnCount = 1, FnIndex[1] = 100. Cycle Start and confirm the bath reaches 60 °C and that oDone pulses.
- Library regression. For each of the 48 FBs, build a one-step recipe that exercises only that FB with a benign setpoint. Record pass/fail and the steady-state error. This regression catches parameter-mismatch bugs in the FBs before any customer recipe is loaded.
- Parallel execution. Build a recipe with one step containing FnCount = 6 (e.g. heat, fill, dose 1, dose 2, dose 3, agitate) and verify that all six FBs run concurrently and that the step only completes when the AND condition is satisfied.
- Resume test. With a long recipe running, open the door interlock (simulating a fault). Confirm the alarm appears on the HMI. Press Continue after the interlock is closed. Confirm execution resumes at the same step with the same parameters and that the time stamps in the production log are continuous across the fault.
For documentation, export the PLC project to a read-only TIA Portal file and the HMI project to a panel image; both go into the machine's technical file as required by the Machinery Directive 2006/42/EC and the operator's quality system.
11. Performance and Memory Budget
For the recommended CPU 317-2 PN/DP with 1 MB work memory:
| Block | Approx. footprint |
|---|---|
| 48 FBs (avg. 1.5 KB code each) | 72 KB |
| 48 instance DBs | ~25 KB |
| DB200 Recipe (64 steps × 16 fns) | ~90 KB |
| DB210 Faults + DB220 Dispatcher + DB230 Checkpoint | ~12 KB |
| FCs and the engine FB200 | ~20 KB |
| HMI tag database (TP1200) | ~5 MB on the panel (no PLC cost) |
OB1 cycle time stays under 30 ms on a CPU 317-2 PN/DP with this design. Watch the cycle-time monitor in HW Config; if it climbs above 100 ms, move the dispatch loop into OB35 and reduce the per-scan work in OB1 to engine + HMI only.
12. Common Pitfalls and Field-Notes
| Symptom | Likely cause | Fix |
|---|---|---|
| Function runs but never sets oDone | Done condition depends on a sensor wired to a different AI channel than the FB reads | Cross-check the AI assignment in HW Config against the FB's PEW address |
| Step never advances even though all FBs are done | AND/OR/ANY miscoded in StepComplete() | Insert a watch on ActiveMask[1..16] in the watch table |
| Continue button greyed out after power fail | DB230 not declared retentive | Mark DB230 retentive in PLC properties; verify by pulling the MMC and re-inserting |
| HMI shows the same recipe after editing | Recipe screen writes to a mirror tag instead of DB200 | Bind the table to the symbol "DB200.Step" directly, not a copy |
| Two FBs controlling the same output (e.g. both steam and auxiliary heater call Q1) | Two physical FBs were assigned the same hardware output by mistake | Use the dispatcher map DB220 to enforce one output per FB |
| VFD speed oscillates when batch runs | Agitator and circulator both write to the same AO | Reserve one AO per FB; document in the recipe schema |
Field-proven tip: always include a 4-7-9 second "drain & rinse" final step in the recipe schema. The exhaust dyeing chemistry produces loose dye after the bath; without that final step the next batch starts with contaminated water and fails the first color-dosing tolerance check.
How many steps can a single recipe contain on an S7-300 with this design?
A CPU 317-2 PN/DP with 1 MB work memory can hold 64 steps of up to 16 parallel functions each in DB200. A CPU 315-2 PN/DP (16 KB work memory) is limited to roughly 24 steps. Resize UDT_Step arrays in DB200 to match the chosen CPU's memory budget.
Can a function that runs in step 1 also be used in step 7 with a different setpoint?
Yes. Each FB has exactly one instance DB (e.g. FB100 HeatJacket uses DB100). The engine calls FB100 with the parameter set that is stored in the current step's row of DB200, so the same physical function is re-used with a new setpoint in every step where its index is listed.
How is the Continue button implemented after a fault or power failure?
The engine writes a checkpoint (current step, state, per-FB states) into retentive DB230 every 5 s. On power restoration or fault recovery, the HMI Continue button reads the checkpoint and re-seeds the engine. The CPU's retentive area plus the MMC backup make the checkpoint survive a power-down; without MMC-backed retentive DBs, resume is not possible.
What is the recommended STEP 7 / TIA Portal version for this architecture?
STEP 7 V5.5 SP2 with WinCC flexible 2008 SP5 (legacy path) or TIA Portal V16 with the S7-300 Add-On (recommended). Use TIA V18 if you need symbolic consistency between the PLC and the Comfort Panel; older TIA versions do not support the S7-300 Add-On cleanly.
Why use FB numbers 100-147 for the library?
Numbering above FB100 keeps the user space clear of the system FBs (FB0-FB39) and leaves FB0-FB99 free for application utility blocks such as FB200 (the engine) and FB1-FB9 (common helpers). The 48-license range 100-147 is a Siemens convention for non-system, application-level FBs and avoids collision with the firmware-installed PID, motion, and technology FBs.