PLC Programming SAPLC ProgrammingSOUTH AFRICA

exercises · South Africa

PLC batch mixing program with a simple recipe

A PLC batch mixing program: fill two ingredients by level probe, mix on a timer, drain to empty, count batches — a full state machine in ladder and ST.

Difficulty: advanced · 60–90 minutes

This is a build-along exercise, not a reading page. You get a short job card of the kind a contractor actually receives, an I/O table to wire against, and a worked solution to check yourself with once your own version runs — plus the test sequence that proves it, because a program you haven't tried to break is a program you haven't tested. Sketch first, build second, test third. Same order as on site.

Open the simulator and build along →

The job card

Job card: a Durban factory blends a two-part degreaser in a 1200-litre tank, and the current 'recipe' is a laminated sheet and a kitchen timer. The sequence to automate: open valve A until the mid-level probe covers (that is the measured dose of base), then valve B until the high probe covers (the solvent dose), mix for 90 seconds, then drain until the empty probe uncovers, and that is one batch. Production runs four batches per shift, so count completed batches and light the done lamp at four; the supervisor's reset starts the next shift's count. Stop must freeze the batch mid-state — a half-mixed batch that loses its place gets dumped, and the solvent isn't cheap.

Read it the way a foreman hands it to you. Every requirement on that card is a test case: when you think the program is done, walk the card line by line and force each condition in the watch table. Any line without a matching test you actually ran means you're not done yet. That habit — card in one hand, watch table in the other — is what separates a programmer who commissions clean from one who gets the call-back at month end.

I/O assignment

Wire your simulator project to this table exactly. Half the value of an exercise like this is tag discipline: name the points the same way the table does and the solution steps further down will read straight onto your rungs without translation.

TagTypeAddressPurpose
StartPBDI%I0.0Batch start / resume pushbutton, normally open, momentary.
StopPBDI%I0.1Stop pushbutton, normally closed, wired fail-safe. Freezes the sequence.
LevelMidDI%I0.2Mid-level probe at the ingredient-A dose point. TRUE when covered.
LevelHighDI%I0.3High-level probe at the ingredient-B dose point. TRUE when covered.
LevelEmptyDI%I0.4Bottom probe just above the drain. TRUE while liquid remains in the tank.
ValveADO%Q0.0Ingredient A (base) inlet valve, open while energised.
ValveBDO%Q0.1Ingredient B (solvent) inlet valve.
MixerMotorDO%Q0.2Mixer drive contactor, 2.2 kW agitator.
DrainValveDO%Q0.3Tank drain valve to the filling line.
ShiftDoneLampDO%Q0.4Lamp at four completed batches; supervisor resets for the next shift.

A note on the Type column: DI is a digital input, DO a digital output, AI and AO are analogue in and out, and M is an internal memory bit that never leaves the CPU. The addresses use IEC notation (%I, %Q, %M). If your head is in Allen-Bradley land, map %I0.0 to I:0/0 and carry on — the logic doesn't change, only the spelling of the addresses.

Think before you build

Don't open the ladder editor yet. The notes below are the design decisions that determine whether your program works first time or fights you for an hour. Read them, then sketch the rung shapes on paper. Pencil and the back of a delivery note is fine — most working programs start exactly there.

  • Five states: IDLE, FILL_A, FILL_B, MIX, DRAIN. The level probes are the transition conditions for the fills, the TON for the mix, the empty probe for the drain. Dosing by level probe works because the tank geometry fixes the volume each probe represents — note that assumption, it dies the day someone fits a different tank.
  • A Running permission bit (seal-in, same as the silo exercise) gates every output while the state variable holds its place. Stop closes both inlet valves, stops the mixer and the drain, and the batch waits exactly where it was — that is what protects the half-mixed batch.
  • The mix timer must freeze with the stop, not reset. Use the Running bit in the TON's IN so elapsed time holds during a pause; a mix that restarts from zero after every interruption over-shears the product, and one that skips the remainder under-mixes it.
  • Never let ValveA or ValveB share a state with DrainValve. Decoding all three from the state variable makes filling-while-draining structurally impossible, which on this tank is the difference between a batch and a floor full of degreaser.

Step-by-step solution

Build one rung at a time and test after every rung. Never write the whole program and then test the lot — when five rungs go in untested and the machine misbehaves, you're debugging five suspects instead of one. The steps below follow that order. In the pseudo-rungs, ] [ is a normally-open examine, ]/[ is normally-closed, and ( ) is the output coil.

Rung 1: running permission

Seal-in: (StartPB OR Running) AND StopPB. Outputs AND this bit; the state machine below ignores it for transitions that depend only on probes already reached. Start doubles as resume — pressing it after a stop picks the batch up exactly where the state variable says it is.

// ──┬──[ ]StartPB──┬──[ ]StopPB──( )Running
//   └──[ ]Running──┘

Rungs 2-6: the batch state machine

IDLE moves to FILL_A on a start edge with the tank empty (careful: the tag name reads backwards — LevelEmpty is TRUE while liquid still covers the bottom probe, so truly empty means NOT LevelEmpty; read your probe sense twice). FILL_A to FILL_B when LevelMid covers. FILL_B to MIX at LevelHigh. MIX to DRAIN on the 90-second timer. DRAIN back to IDLE when LevelEmpty uncovers, counting the batch on that transition.

// (State=IDLE) AND rStart.Q AND NOT LevelEmpty ── MOVE FILL_A -> State
// (State=FILL_A) AND LevelMid ── MOVE FILL_B -> State
// (State=FILL_B) AND LevelHigh ── MOVE MIX -> State
// (State=MIX) AND tMix.Q ── MOVE DRAIN -> State
// (State=DRAIN) AND NOT LevelEmpty ── MOVE IDLE -> State, count batch

Rung 7: the pausable mix timer

TON tMix with IN of Running AND (State=MIX), PT of T#90s. With Running in the IN leg, a stop mid-mix freezes the elapsed time at, say, 37 seconds, and resume finishes the remaining 53. Confirm on your platform that TON holds ET when IN drops — most do not; if yours resets, accumulate with a retentive timer (TONR/RTO equivalent) instead. That check is part of the exercise.

// Running AND (State=MIX) ──[TONR tMix, PT := T#90s]

Rungs 8-11: outputs decoded from state

ValveA on Running AND State=FILL_A; ValveB on Running AND State=FILL_B; MixerMotor on Running AND State=MIX; DrainValve on Running AND State=DRAIN. The CTU on the DRAIN-to-IDLE transition counts completed batches, PV 4, with the supervisor's reset on R; ShiftDoneLamp follows the counter's Q.

// Running AND (State=FILL_A) ──( )ValveA
// Running AND (State=FILL_B) ──( )ValveB
// Running AND (State=MIX)    ──( )MixerMotor
// Running AND (State=DRAIN)  ──( )DrainValve
// batch-complete edge ──[CTU cBatches, PV := 4] ── Q ──( )ShiftDoneLamp

Test the pause in every state

Run a clean batch end to end and verify the order: A covers mid, B covers high, 90 s of mixer, drain to empty, count = 1. Then stop and resume in each state: mid-FILL_A (valve must close and reopen on resume, level continuing from where it was), mid-MIX (elapsed time must hold — watch tMix.ET through the pause), mid-DRAIN. Run four batches and confirm the lamp at exactly four, with batch five blocked until reset. Finally force LevelHigh TRUE during FILL_A: the state machine must not skip FILL_B's dose — walk through why your transitions do or do not protect against a lying probe.

The structured text version

The same logic in IEC 61131-3 structured text — each output written as a boolean equation you can read aloud.

(* Two-ingredient batch mixer, IEC 61131-3 ST *)
VAR CONSTANT IDLE := 0; FILL_A := 1; FILL_B := 2; MIX := 3; DRAIN := 4; END_VAR
Running := (StartPB OR Running) AND StopPB;
rStart(CLK := StartPB);
tMix(IN := Running AND (State = MIX), PT := T#90s); (* must be retentive-capable *)
CASE State OF
  IDLE:   IF rStart.Q AND NOT LevelEmpty THEN State := FILL_A; END_IF;
  FILL_A: IF LevelMid THEN State := FILL_B; END_IF;
  FILL_B: IF LevelHigh THEN State := MIX; END_IF;
  MIX:    IF tMix.Q THEN State := DRAIN; tMix(IN := FALSE, PT := T#90s); END_IF;
  DRAIN:  IF NOT LevelEmpty THEN State := IDLE; BatchCount := BatchCount + 1; END_IF;
END_CASE;
ValveA        := Running AND (State = FILL_A);
ValveB        := Running AND (State = FILL_B);
MixerMotor    := Running AND (State = MIX);
DrainValve    := Running AND (State = DRAIN);
ShiftDoneLamp := (BatchCount >= 4);

Ladder wins this argument when an electrician has to fault-find your program at 02:00 with a multimeter mindset — the rung looks like the circuit diagram it replaced, and that familiarity is worth real money on a breakdown. ST starts winning when the pattern repeats: ten pumps with the same interlock shape is one ST function called ten times, where ladder hands you ten near-identical rungs to keep in sync by hand forever. Learn both. Build the exercise in ladder first, then write the ST version and confirm the two behave identically in the simulator. That translation skill — same logic, two languages — is exactly what technical interviews and commissioning work both test.

Common mistakes

Every mistake below comes from a real program: either one of ours from years back, or one we were called in to fix. Check your build against the list before you call the exercise done.

  • Dosing ingredient B from the same probe logic as A without noticing B's dose is the DIFFERENCE between high and mid probes. Move the mid probe one day and ingredient A's dose changes while B's changes in the opposite direction — document which probe owns which dose.
  • A mix timer that resets on every pause. Three brief stops during the mix and the batch has been agitated for four minutes instead of ninety seconds; with shear-sensitive product that is a dumped batch that passed every logic test.
  • Counting batches on the DRAIN state level instead of the transition edge. The counter increments every scan during the drain — thousands per batch — and the done lamp lights mid-way through batch one. Transitions are events; states are conditions.
  • Trusting the probes unconditionally. A scaled-up empty probe reads covered forever and the drain state never exits; a fouled high probe overfills with solvent. A per-state watchdog timer (no transition within N minutes raises a fault) is cheap and catches every one of these.

Most of these share one root cause: the rung shape doesn't match the intent, so the program passes the obvious test and fails the edge case. That's why the solution steps force the edge cases deliberately instead of stopping at "it starts and it stops". Steal that habit for every program you write from here on.

Take it further

Got it working first time? Good — now make it earn its keep. Each extension below changes the spec the way a real client does: after you've finished. Treat each one as a fresh job card, and re-test the whole program afterwards, not just the new part. Regressions hide in the rungs you didn't touch.

  • Add per-state watchdog timeouts feeding a fault state with a beacon — then bring in the first-out annunciator exercise so the operator sees WHICH state stalled, not just that something did.
  • Make the recipe adjustable: mix time and batch target from HMI tags with clamps, then a second recipe (different mix time, skip ingredient B) selected by a switch — the moment recipes multiply you will feel why ISA-88 separates recipe from equipment logic.
  • Replace level-probe dosing with a flowmeter pulse count per ingredient (CTU against a dose setpoint) and compare repeatability — probes dose volume by geometry, pulses dose it by measurement.

If you build even one extension, screenshot the finished rungs and keep them somewhere organised. A folder of working, tested exercise solutions is the start of a portfolio — and hiring engineers ask candidates to explain a rung far more often than they ask to see certificates.

Run this in the simulator

The sandbox on the free tier lets you build the core rungs of this advanced exercise yourself — no card details, no install, signed up and on a rung inside two minutes. The watch table is the part that matters here: force the inputs, watch the outputs, and run the test sequence from the solution steps against a live scan cycle instead of imagining it. To be straight about what's paid: the guided version of this exercise — graded checkpoints, feedback on every submission, plus the fault-injection variants that break your program the way a real plant does — sits in the curriculum on the Basic tier at USD 12 per month and Pro at USD 29 per month, alongside the wiring track, sensor school and cert packs. Training centres and engineering departments wanting this in a lab should look at the Teams tier (USD 199 per seat per year, minimum 5 seats); the training-centres page carries the institutional details and the contact form. If you're an individual learning the trade, prove the core rungs in the free sandbox first and decide whether the graded track is worth the money. And once this one runs clean, line up the next exercise a notch harder — the step up is where the skill gets built.

Start in the free sandbox →

Reference

ISA-88 batch control standard covers the background theory behind this exercise, and it's worth twenty minutes of your time after the build — theory sticks better once your hands have done the work. The languages used here are defined by the IEC 61131-3 standard from iec.ch, and your CPU vendor's manual remains the canonical source for how a specific controller executes them.

What we don't claim

This site is not SAQA-registered, not MerSETA-accredited, and not an NQF-registered qualification provider. Our completion certificates are course-level only — they describe what you covered, not an NQF Level X qualification. The CCST cert from ISA is the portable industry credential we recommend; we are not an ISA cert delivery partner either, but our cert packs are CCST-aligned. The exercise on this page is practice material written by working programmers: finishing it proves the skill to yourself and to the simulator's progress tracking, not to a regulator.

By PLC Programming SA · Last updated 2026-06-12