50 PLC & Ladder Logic Exercises + 12 Worked Solutions
Fifty PLC practice problems, six complete ladder-logic solutions, and six Structured Text solutions with I/O contracts, acceptance tests, code, scan traces, grading criteria, and vendor-dialect notes.
PLC programming practice should produce evidence, not just code. For each exercise, define the inputs and outputs, write acceptance tests before the program, execute normal and abnormal scan sequences, and record whether the observed state matches the expected state. The fifty briefs below provide a progressive curriculum. Six receive complete ladder-logic solutions and six receive complete, vendor-neutral Structured Text solutions with test matrices and grading criteria.
This page owns the broad PLC programming exercises, ladder logic exercises with solutions, and Structured Text exercises with solutions task. The practical ladder examples article remains the pattern-and-application reference; this page is the problem, solution, acceptance-test, and grading owner. Use the ladder logic simulator or Structured Text lab when you want runnable, auto-graded browser scenarios. The learning simulator tests a logic model; it does not reproduce every compiler, firmware, electrical I/O, machine dynamic, or safety function.
The test-first PLC practice contract
Do not begin with a rung or an IF. Begin with a contract. A contract prevents a plausible-looking solution from quietly solving a different problem.
| Deliverable | What to write before coding | What counts as evidence |
|---|---|---|
| Problem boundary | Controlled process, starting state, ordinary stop behavior, exclusions | One paragraph another programmer can implement without guessing |
| I/O contract | Name, direction, type, true-state meaning, physical or simulated source | A table with no ambiguous names such as Sensor1 or Flag |
| State and memory | Which values persist across scans; initialization and reset policy | State diagram or memory table plus a restart case |
| Acceptance matrix | Initial state, stimulus, expected state/output, failure exposed | At least one normal, boundary, simultaneous, timeout, reset, and restart case |
| Implementation | One clear owner for each output; bounded loops; explicit priority | Compiling code in the selected target or a documented learning dialect |
| Scan trace | Sampled inputs, current state, timers, memory, outputs by invocation | Captured trace or a manually checked table, not only a green coil animation |
| Translation record | Compiler, version, task, library, time base, deviations | A short portability note for every vendor-specific change |
Use a logic simulator for fast iteration, but keep the validation boundary explicit. A browser model can expose Boolean, timer, counter, sequence, and fault-handling mistakes. It cannot prove safe stopping, wiring polarity, field-device behavior, motion, task jitter on a target CPU, retentivity after a real power loss, or compliance with a safety lifecycle.
A reusable 20-point grading rubric
| Area | 0 points | 1 point | 2 points |
|---|---|---|---|
| I/O semantics | Missing or ambiguous | Listed but some true states unclear | Every name, type, direction and true state is explicit |
| Normal behavior | Does not complete | Completes one path | All specified normal paths pass |
| Priority | Simultaneous inputs are accidental | Priority exists but is undocumented | Priority is stated and tested |
| Memory/reset | Hidden or unsafe restart state | Reset works in one case | Initialization, reset rejection and restart are tested |
| Timing | Magic delays or skipped timer calls | Nominal timing works | Entry, elapsed, exit, reset and timeout cases pass |
| Fault diagnosis | Output simply stops | Generic fault bit | First failed boundary/state and recovery preconditions are visible |
| Output ownership | Multiple unexplained writers | Mostly centralized | Each output has one reviewable owner |
| Edge cases | None | One boundary case | Held, one-scan, chatter, invalid and limit cases are covered as relevant |
| Portability | Assumes all PLCs match | Mentions a vendor | Dialect, task, library and target deviations are recorded |
| Safety boundary | Implies simulation proves machinery | Generic disclaimer | Ordinary control and independent safety validation are separated precisely |
Score 16–20 before advancing. A lower score is not failure; it identifies the next practice target.
Download the reusable PLC exercise grading sheet (CSV) to score one submission consistently, preserve reviewer comments, and choose the next exercise from evidence rather than intuition.
Fifty PLC programming exercises by difficulty
The catalogue is language-neutral. Implement each problem in ladder logic first if visual troubleshooting is your immediate goal, then translate selected problems to ST to expose priority, types, arrays, and state ownership. “Stop” in these briefs means an ordinary control request unless an independently engineered safety function is explicitly discussed.
Level 1: Boolean logic and scan memory (1–12)
| No. | Exercise brief | Acceptance focus |
|---|---|---|
| 1 | Start/stop motor request with seal-in memory | Start pulse latches; stop has priority; simultaneous start/stop stops |
| 2 | Conveyor enabled by guard status, material present, and start request | Every false permissive blocks the ordinary command |
| 3 | Alarm horn from temperature high, pressure high, or manual test | Every single cause and every combination produces the expected OR result |
| 4 | Heater demand with door inhibition and day/override selection | Parentheses and NOT semantics match a complete truth table |
| 5 | Interpret a physically normally closed stop input | Program tag describes healthy state; broken-wire assumption is documented |
| 6 | Cross-interlock two ordinary motor commands | Both outputs can never be true in any tested scan |
| 7 | Two-out-of-three sensor voting | Exactly zero/one/two/three true sensors are tested; no safety claim is made |
| 8 | Latched alarm with deliberate reset | Reset is rejected while the initiating condition remains active if specified |
| 9 | Rising-edge one-shot | Held input produces one pulse; a new low/high sequence produces another |
| 10 | Toggle a lamp on each accepted edge | Bounce and restart state are defined rather than accidental |
| 11 | Alarm horn acknowledge with lamp following process condition | Acknowledge silences sound but does not hide the active condition |
| 12 | Permissive chain plus isolated indicator-lamp test | Lamp test never writes actuator commands |
Level 2: Timers, counters, and event qualification (13–24)
| No. | Exercise brief | Acceptance focus |
|---|---|---|
| 13 | Warning beacon immediately, conveyor command after a five-second TON | Timer resets on aborted start; feedback and timeout paths are distinct |
| 14 | Fan run-on for sixty seconds after heater command clears | Reasserted heater during run-on returns to the defined state |
| 15 | Half-second beacon flasher using timer state | Timing does not depend on a single-scan equality comparison |
| 16 | Star-delta ordinary sequence with transition dead time | Star and delta commands are mutually exclusive; stop removes both |
| 17 | Stretch a short detection event to two seconds | New pulses during the active interval follow a documented retrigger policy |
| 18 | Count parts to a batch of twenty-four | Count only rising edges; reset and batch-done priority are tested |
| 19 | Occupancy count from independent entry and exit events | Underflow, simultaneous events, and maximum capacity are defined |
| 20 | Reject count and latch a batch quality fault at five | Batch boundary, reset, and the fifth event are unambiguous |
| 21 | Accumulate run hours and raise service due | Time base, retained storage, overflow, and reset authorization are documented |
| 22 | Communication heartbeat watchdog | Healthy pulse resets supervision; missing pulse latches a useful diagnosis |
| 23 | Symmetric input debounce | Both false-to-true and true-to-false require stable time |
| 24 | Measure cycle time between rising edges | First event, timer range, units, and slow-cycle threshold are tested |
Level 3: Sequences and state logic (25–34)
| No. | Exercise brief | Acceptance focus |
|---|---|---|
| 25 | Green-yellow-red traffic-light cycle | Exactly one lamp state is active; disable/re-enable policy is defined |
| 26 | Remember a pedestrian request for the next eligible phase | Requests are neither lost nor repeatedly served from one held input |
| 27 | Track a tall product from photo-eye to timed diverter | Multiple products and changed conveyor speed expose time-tracking limits |
| 28 | Fill, mix, and drain a batch | Every step has entry, transition, timeout, abort, and recovery behavior |
| 29 | Parking gate with vehicle-loop inhibition | Close command cannot occur while occupancy is present |
| 30 | Four-position reject shift register | One index edge advances once; rejected identity remains aligned |
| 31 | First-out alarm annunciator | First event is retained when later faults arrive in the same/next scans |
| 32 | Add per-step timeout and faulted-step record | The recorded step survives transition to fault and clears deliberately |
| 33 | Manual/automatic mode transfer | Output ownership and sequence state remain defined at every transfer point |
| 34 | Recipe-driven skipped sequence step | A skipped step cannot strand the state machine |
Level 4: Analog and data handling (35–43)
| No. | Exercise brief | Acceptance focus |
|---|---|---|
| 35 | Scale a 4–20 mA pressure signal to 0–10 bar | Endpoints, midpoint, type conversion, and clamping policy are verified |
| 36 | Detect under-range and over-range before using pressure | Faulted values cannot masquerade as valid process values |
| 37 | Tank-level pump control with 20/80 percent hysteresis | State holds inside the band and initializes predictably |
| 38 | PID flow-loop wrapper with manual/automatic mode | Output limits, update period, tracking and bumpless transfer are tested |
| 39 | Deadband a noisy display value | Small changes hold; a threshold-crossing update occurs once |
| 40 | Ramp a setpoint at two units per second | Rate uses measured/configured interval and works in both directions |
| 41 | Convert real kilograms to rounded integer grams | Negative values, halves, range limit, and overflow policy are defined |
| 42 | Totalize flow on a fixed time base | Units, integration period, retention, rollover, and reset are proven |
| 43 | Generate L/H/HH alarms with hysteresis and delay | Pickup, dropout, delay, latch, acknowledge, and bad-quality behavior differ clearly |
Level 5: Complete project briefs (44–50)
| No. | Mini-project | Minimum evidence package |
|---|---|---|
| 44 | Car wash: pre-soak, brush, rinse, dry, exit | I/O contract, state diagram, per-step tests, abort path, vehicle-departure rearm |
| 45 | Pedestrian crossing with request memory and minimum green | Timing table, request queue cases, exclusive lamps, disable/restart cases |
| 46 | Silo fill with purge precondition and run-on | Permissive matrix, fan/valve ownership, trip priority, first-out fault |
| 47 | Duty/standby pumps with alternation and failover | Lead memory, simultaneous faults, mid-run transfer, maintenance override policy |
| 48 | Occupied/setback HVAC zone with window lockout | Mode table, dead zone, analog limits, sensor-quality and manual mode tests |
| 49 | Three-floor elevator request sequence | Call queue, direction policy, door interlock, travel timeout, invalid sensor combination |
| 50 | Indexed bottling line with fill, cap, reject tracking | Product-state model, index trace, reject-bin limit, jam/fault recovery |
The seven project briefs deliberately stop short of giving a single “correct” program. Their purpose is architecture: split process state, commands, feedback, faults, modes, and recovery into reviewable responsibilities. For fully worked practice, continue with the six solutions below.
Six ladder logic exercises with solutions and answer tests
These solutions use compact, vendor-neutral ladder pseudocode. A vertical pair of rails is implied; | | means a true-when-bit-true contact, |/| means a true-when-bit-false contact, ( ) is a non-retentive coil, (L) and (U) are latch/unlatch operations, OSR is a rising-edge pulse, and TON/CTU describe common timer/counter behavior. Those labels are not a portability promise. Rockwell, Siemens, Mitsubishi, Omron, CODESYS-family, Schneider, and other platforms differ in instruction names, data structures, call rules, time bases, retentivity, prescan/startup behavior, and editing tools.
Treat each listing as an answer model, not as the only valid answer. A different rung arrangement is acceptable when it satisfies the same I/O contract, scan behavior, priority, fault response, and acceptance matrix. Ordinary Stop and interlock examples below are not emergency-stop or functional-safety designs.
Ladder solution 1: stop-dominant motor seal-in
Problem: A momentary start request should latch an ordinary motor run request while the process permissive is healthy. Stop or loss of the permissive must remove the request. If Start and Stop are both active in the same scan, Stop wins. Separate the internal request from the mapped motor output so command ownership stays visible.
| Tag | Direction/type | True-state meaning |
|---|---|---|
StartPB |
BOOL input |
Ordinary start button is pressed |
StopHealthy |
BOOL input |
Normal stop circuit permits running |
ProcessPermissive |
BOOL input |
Process conditions permit a start and continued run |
MotorRunRequest |
Internal BOOL |
Accepted run memory |
MotorOutput |
BOOL output |
Ordinary motor command sent to the mapped output layer |
Rung 1 — request memory; StopHealthy and ProcessPermissive remain outside the branch
|--| | StopHealthy --| | ProcessPermissive --+--| | StartPB --------( MotorRunRequest )--|
| |
| +--| | MotorRunRequest --|
Rung 2 — one final command owner
|--| | MotorRunRequest --| | StopHealthy --| | ProcessPermissive ----( MotorOutput )--|
| Test | Initial request | Stimulus | Expected answer |
|---|---|---|---|
| Normal start | 0 | Healthy 1, permissive 1, Start 1 | Request/output become 1 |
| Seal-in | 1 | Start returns to 0 | Request/output remain 1 |
| Stop | 1 | StopHealthy becomes 0 |
Request/output become 0 in the evaluated scan |
| Lost permissive | 1 | ProcessPermissive becomes 0 |
Request/output become 0 |
| Simultaneous start/stop | 0 or 1 | Start 1 and StopHealthy 0 |
Output 0; no restart memory survives |
| Restart | Documented | Runtime/power transition | Approved initialized or retained request; no assumed motion |
Grade it: award two points each for explicit true-state names, stop priority, one final output writer, a simultaneous-input test, and documented restart behavior. A green output during one normal start earns only part of the score.
Ladder solution 2: forward/reverse mutual interlock
Problem: Two ordinary direction requests control one motor. Forward and reverse commands must never be true together. A change of direction requires Stop first. This exercise teaches priority and cross-interlocking; real reversing starters also require the approved electrical/mechanical interlock, device ratings, stopping time, and safety design.
| Tag | Direction/type | True-state meaning |
|---|---|---|
ForwardPB, ReversePB |
BOOL inputs |
Requested ordinary direction |
StopHealthy, OverloadHealthy |
BOOL inputs |
Control and overload conditions permit running |
ForwardCmd, ReverseCmd |
BOOL outputs |
Commands to the direction interface |
Rung 1 — forward seal-in blocked by the reverse command
|--| | StopHealthy --| | OverloadHealthy --|/| ReverseCmd --+--| | ForwardPB --( ForwardCmd )--|
| |
| +--| | ForwardCmd -|
Rung 2 — reverse seal-in blocked by the forward command
|--| | StopHealthy --| | OverloadHealthy --|/| ForwardCmd --+--| | ReversePB --( ReverseCmd )--|
| |
| +--| | ReverseCmd -|
| Test | Starting state | Stimulus | Expected answer |
|---|---|---|---|
| Forward start | Both off | Forward pulse | Forward 1, Reverse 0 |
| Reverse rejected | Forward running | Reverse pulse | Forward remains 1, Reverse remains 0 |
| Valid reversal | Forward running | Stop, prove both off, then Reverse | Forward 0, Reverse 1 |
| Simultaneous from idle | Both off | Forward and Reverse together | Apply a documented priority or reject both; never permit both |
| Overload | Either direction running | Overload unhealthy | Both commands off |
| Invariant | All cases | Observe every scan | NOT (ForwardCmd AND ReverseCmd) always true |
The simultaneous-from-idle row is deliberately not resolved by the pseudocode alone: evaluation order and output-image semantics may allow one rung to win on one target. A production contract must say whether Forward has priority, Reverse has priority, or both requests are rejected, then implement and test that policy explicitly. Grade it only after the simultaneous case is deterministic and the cross-reference shows no other output writers.
Ladder solution 3: warning delay and missing-feedback timeout
Problem: When a run request is accepted, energize a warning beacon immediately. After five seconds, issue a conveyor command. If running feedback does not arrive within three additional seconds, remove the run memory and latch FailedToStart. Stop cancels the sequence immediately. Reset is accepted only while the request and feedback are both off.
| Tag | Direction/type | True-state meaning |
|---|---|---|
RunRequest, StopRequest, ResetPB |
BOOL inputs |
Ordinary run, stop, and fault-reset requests |
ConveyorFeedback |
BOOL input |
Contactor/drive running feedback is proven |
WarningDelay |
TON, 5 s |
Accepted run request has remained active for five seconds |
FeedbackTimeout |
TON, 3 s |
Command is present without feedback for three seconds |
WarningBeacon, ConveyorCmd, FailedToStart |
BOOL outputs/state |
Warning, command, and retained diagnosis |
|--| | RunRequest --|/| StopRequest --|/| FailedToStart --------( WarningBeacon )--|
|--| | WarningBeacon ------------------------[TON WarningDelay 5 s]--|
|--| | WarningDelay.Q --|/| StopRequest --|/| FailedToStart ----( ConveyorCmd )--|
|--| | ConveyorCmd --|/| ConveyorFeedback --[TON FeedbackTimeout 3 s]--|
|--| | FeedbackTimeout.Q -------------------------------(L) FailedToStart --|
|--| | ResetPB --|/| RunRequest --|/| ConveyorFeedback -(U) FailedToStart --|
| Test | Timeline | Expected answer |
|---|---|---|
| Normal | Run at 0 s; command at 5 s; feedback at 6 s | Beacon immediately, command after 5 s, no fault |
| Stop during warning | Stop at 2 s | Beacon off, timer resets, command never starts |
| Timeout | No feedback through 8 s | Fault latches; command is inhibited on the following evaluated logic according to target order |
| Stale feedback | Feedback already true before Run | Reject or diagnose according to the written stale-feedback policy |
| Invalid reset | Fault active while feedback or request remains true | Fault remains latched |
| Clean reset | Request 0, feedback 0, Reset pulse | Fault clears; no automatic restart |
The phrase “following evaluated logic” matters: if the fault-latch rung is physically below the command rung, the command may stay true until the next scan unless the target/runtime resolves it differently. Either place the final command after all fault-state updates or include the one-scan behavior in the specification. Grade it: require separate warning and feedback timers, a named timeout fault, stop cancellation, stale-feedback handling, and valid reset preconditions.
Ladder solution 4: one-shot batch counter with controlled reset
Problem: Count each product once even when a photo-eye remains blocked for several scans. Set BatchComplete at 24 products. A new-batch reset is accepted only when the conveyor is stopped. Define what happens to the accumulated count across a power cycle before choosing retentive memory.
| Tag | Direction/type | True-state meaning |
|---|---|---|
ProductEye |
BOOL input |
A product currently blocks the sensor |
ProductPulse |
One-scan state | Accepted rising edge of the eye |
BatchCounter |
CTU, preset 24 |
Number of accepted product edges |
NewBatchPB, ConveyorRunning |
BOOL inputs |
Reset request and ordinary running status |
BatchComplete |
BOOL output |
Count has reached the batch target |
|--| | ProductEye ------------------------[OSR ProductPulse]--|
|--| | ProductPulse ----------------------[CTU BatchCounter 24]--|
|--| | BatchCounter.Q --------------------( BatchComplete )--|
|--| | NewBatchPB --|/| ConveyorRunning --[RES BatchCounter]--|
| Test | Stimulus | Expected answer |
|---|---|---|
| Long obstruction | Eye true for ten scans | Count increases by one |
| Two products | True, false, true with an accepted low interval | Count increases by two |
| Chatter | Multiple fast transitions | Result follows the documented input-filter/qualification rule |
| Twenty-third | Initial count 22; one new edge | Accumulator 23; complete 0 |
| Twenty-fourth | Initial count 23; one new edge | Accumulator 24; complete 1 |
| Reset rejected | Conveyor running; Reset pressed | Count unchanged |
| Reset accepted | Conveyor stopped; Reset pressed | Count 0; complete 0 |
An edge instruction remembers prior input state, and a counter usually owns accumulator and status state. Do not assume their startup or reset behavior is identical across platforms. Grade it: require one count per accepted edge, exact 23/24 boundary tests, reset authorization, chatter policy, overflow/preset behavior, and a documented retentivity decision.
Ladder solution 5: tank fill with hysteresis and bad-signal inhibit
Problem: Open an ordinary fill valve when a valid tank level falls below 30%. Keep filling through the middle band and close at 80%. A bad analog signal or high-high condition closes the command. This is normal process control, not proof of independent overfill protection.
| Tag | Direction/type | True-state meaning |
|---|---|---|
LevelPct |
REAL input |
Validated tank level in percent |
LevelGood |
BOOL input |
Measurement is suitable for this control decision |
HighHigh |
BOOL input |
Separate high-high condition is active |
FillRequest |
Internal BOOL |
Hysteresis state between low and high thresholds |
FillValveCmd |
BOOL output |
Ordinary request to open the fill valve |
|--| | LevelGood --|/| HighHigh --[LT LevelPct 30.0] ----(L) FillRequest --|
|--[GE LevelPct 80.0] ------------------------------------(U) FillRequest --|
|--|/| LevelGood -----------------------------------------(U) FillRequest --|
|--| | HighHigh ------------------------------------------(U) FillRequest --|
|--| | FillRequest --| | LevelGood --|/| HighHigh --------( FillValveCmd )--|
| Test | Starting condition | Stimulus | Expected answer |
|---|---|---|---|
| Below low | Valid 25%, request 0 | One scan | Request/valve 1 |
| Middle band while filling | Valid 50%, request 1 | Hold | Request/valve remain 1 |
| Middle band while idle | Valid 50%, request 0 | Hold | Request/valve remain 0 |
| At high boundary | Valid 80% | Evaluate | Request/valve 0 under the specified GE boundary |
| Signal fault | Filling; LevelGood becomes 0 |
Evaluate | Request/valve 0; separate diagnosis expected |
| High-high | Filling; HighHigh becomes 1 |
Evaluate | Request/valve 0; normal reset does not imply safety reset |
Hysteresis is memory: the same 50% value produces a different command depending on whether the tank entered the band from below or above. That is intentional and must appear in the tests. Grade it: require named units, exact 30/80 inclusion rules, both middle-band histories, bad-quality behavior, single output ownership, and an explicit separation between ordinary control and independent protection.
Ladder solution 6: three-step fill, mix, drain sequence
Problem: Run a small batch through IDLE, FILL, MIX, and DRAIN. Start from Idle. Fill until HighLevel, mix for ten seconds, then drain until LowLevel. Stop or a process fault moves the sequence to a retained FAULT state with every process output off. Reset is accepted only with Stop active and the fault condition cleared.
| Tag | Direction/type | True-state meaning |
|---|---|---|
StartPB, StopPB, ResetPB |
BOOL inputs |
Ordinary sequence requests |
HighLevel, LowLevel, ProcessFault |
BOOL inputs |
Process transition and fault conditions |
StepIdle, StepFill, StepMix, StepDrain, StepFault |
Internal BOOL state |
Exactly one sequence state should be true |
MixTimer |
TON, 10 s |
Mix state has remained active for ten seconds |
FillValve, Mixer, DrainValve |
BOOL outputs |
Commands decoded from the active state |
Initialization (target-specific): establish StepIdle once when no valid state exists.
|--| | StepIdle --| | StartPB --|/| ProcessFault ----(L) StepFill --|
|--| | StepIdle --| | StartPB ------------------------(U) StepIdle --|
|--| | StepFill --| | HighLevel ----------------------(L) StepMix --|
|--| | StepFill --| | HighLevel ----------------------(U) StepFill --|
|--| | StepMix ------------------------[TON MixTimer 10 s]--|
|--| | StepMix --| | MixTimer.Q ----------------------(L) StepDrain --|
|--| | StepMix --| | MixTimer.Q ----------------------(U) StepMix --|
|--| | StepDrain --| | LowLevel ----------------------(L) StepIdle --|
|--| | StepDrain --| | LowLevel ----------------------(U) StepDrain --|
Fault transition: StopPB OR ProcessFault sets StepFault and clears Fill/Mix/Drain.
Valid ResetPB AND StopPB AND NOT ProcessFault clears StepFault and sets StepIdle.
|--| | StepFill --|/| StepFault -----------------------( FillValve )--|
|--| | StepMix --|/| StepFault ------------------------( Mixer )--|
|--| | StepDrain --|/| StepFault ----------------------( DrainValve )--|
| Test | Initial state | Stimulus | Expected answer |
|---|---|---|---|
| Normal batch | Idle, low level true | Start, then high, wait 10 s, then low | Fill → Mix → Drain → Idle; only matching output active |
| Stop in each active step | Fill/Mix/Drain | Stop | Fault state; all process outputs off |
| Process fault | Any active step | Fault true | Fault state with originating state recorded if required |
| Premature low level | Fill or Mix | Low level true | No early drain completion because current state does not authorize it |
| Timer reset | Mix interrupted before 10 s | Stop/reset/new batch | New Mix timing starts under documented timer-reset behavior |
| Reset rejected | Fault still true or Stop not active | Reset | Remains Fault |
| Unknown/multiple state | Isolated approved test | Corrupt state bits | Detect invalid state and move to the defined fault policy |
Bit-state sequences are easy to draw but permit zero or multiple active bits unless initialization, transition order, and invariant checks are explicit. An integer or enumerated state can simplify exclusivity on platforms where that form is appropriate. Grade it: require one active state, one output decoder, transition tests, per-step Stop/Fault cases, timer reset evidence, rejected reset, restart policy, and an invalid-state response.
To run related logic rather than only reading the answer, open the interactive ladder-logic practice path. Create a free account only when you want saved progress or catalog access; scenario availability varies by tier. Keep the acceptance matrices above and re-run them in the exact vendor environment before using any translated program on equipment.
Structured Text solution 1: stop-dominant motor request
Problem and I/O contract
Create ordinary run-request memory. A one-scan StartEdge may set the request only while PermissivesHealthy is true. StopRequest or a lost permissive clears it. Stop must win when start and stop are true in the same invocation. Compose the ordinary motor command once from the resulting memory and permissive state. This is not an emergency-stop or safety function.
| Name | Type/direction | True-state meaning |
|---|---|---|
StartEdge |
BOOL input |
One accepted ordinary start event |
StopRequest |
BOOL input |
Ordinary stop is requested |
PermissivesHealthy |
BOOL input |
All ordinary process permissions are currently satisfied |
RunRequest |
Persistent BOOL |
Run memory retained between invocations |
MotorCommand |
BOOL output |
Ordinary run request sent toward the selected output interface |
| Case | Initial memory | Inputs | Expected memory/command |
|---|---|---|---|
| Start | 0 | Start 1, Stop 0, Healthy 1 | 1 / 1 |
| Held physical button | 1 | Edge generator returns Start 0 | Remains 1 / 1 |
| Simultaneous | 0 or 1 | Start 1, Stop 1, Healthy 1 | 0 / 0 |
| Lost permissive | 1 | Healthy 0 | 0 / 0 |
| Stop clears | 1 | Stop 1 | 0 / 0 |
| Restart policy | Documented initial memory | All requests 0 after runtime restart | Matches approved initialization; no surprise motion |
(* Ordinary control example; not a safety function. *)
IF StopRequest OR NOT PermissivesHealthy THEN
RunRequest := FALSE;
ELSIF StartEdge THEN
RunRequest := TRUE;
END_IF;
MotorCommand := RunRequest AND PermissivesHealthy;
The IF branch encodes priority: stop and lost permissive are evaluated before start. The output is assigned once after memory is resolved. If another routine also writes the same output tag, the exercise is incomplete until that ownership conflict is removed or intentionally documented and tested.
Grade it: two points each for explicit true-state names, stop priority, one output owner, the simultaneous-input test, and a documented restart state. Then translate the same contract to the target's supported edge instruction and project initialization rules.
Structured Text solution 2: warning, TON, command, and feedback timeout
Problem and acceptance matrix
When RunRequest is true, energize an ordinary warning indication immediately. After five seconds, issue ConveyorCommand. If ConveyorFeedback does not become true within four additional seconds, clear the sequence request and latch StartTimeoutFault. A stop request clears the sequence without waiting. The code assumes a common IEC-style TON interface; confirm the target library and skipped-call behavior.
| Case | Stimulus | Expected observation |
|---|---|---|
| Normal start | Request true; feedback true two seconds after command | Warning at once, command after 5 s, no fault |
| Abort during warning | Stop before 5 s | Warning, command, and timer enable clear |
| Timeout | Feedback remains false for 4 s after command | Command clears and timeout fault latches |
| Feedback already true | Feedback true before new request | Apply the approved stale-feedback policy; do not assume normal start |
| Reset rejected | Fault active while request or feedback remains true | Fault stays latched |
| Clean reset | Request false, feedback false, reset edge true | Fault clears; sequence remains idle |
VAR
WarningDelay : TON;
FeedbackDelay : TON;
END_VAR
IF StopRequest THEN
RunRequest := FALSE;
END_IF;
WarningDelay(IN := RunRequest AND NOT StartTimeoutFault, PT := T#5s);
ConveyorCommand := RunRequest AND WarningDelay.Q AND NOT StartTimeoutFault;
WarningBeacon := RunRequest AND NOT StartTimeoutFault;
FeedbackDelay(
IN := ConveyorCommand AND NOT ConveyorFeedback,
PT := T#4s
);
IF FeedbackDelay.Q THEN
StartTimeoutFault := TRUE;
RunRequest := FALSE;
END_IF;
IF ResetEdge AND NOT RunRequest AND NOT ConveyorFeedback THEN
StartTimeoutFault := FALSE;
END_IF;
This compact solution intentionally exposes a design question: what should happen when feedback is already true before a new command? Installed systems often need a distinct discrepancy fault because “feedback on while command off” may indicate a welded contact, drive mode mismatch, mapping error, or stale signal. Add that requirement before field use; do not silently treat existing feedback as successful starting.
Grade it: confirm timers are invoked consistently, stop removes the request, the timeout identifies feedback rather than merely “motor fault,” reset has preconditions, and the target timer/time representation is recorded.
Structured Text solution 3: analog scaling with diagnostic bands
Problem, units, and edge cases
Map a normalized current value in milliamps to pressure. The nominal transmitter range is 4–20 mA for 0–10 bar. Treat below 3.6 mA as under-range and above 20.5 mA as over-range. While invalid, keep the last valid displayed pressure and set a quality code; do not replace a bad measurement with an apparently valid zero. A real input module may supply counts and module diagnostic bits instead of milliamps, so translate the interface using its manual.
| Input | Expected quality | Expected pressure behavior |
|---|---|---|
| 3.5 mA | UNDER_RANGE |
Hold last valid value |
| 3.6 mA | Policy boundary | Document inclusive/exclusive decision |
| 4.0 mA | VALID |
0.0 bar |
| 12.0 mA | VALID |
5.0 bar |
| 20.0 mA | VALID |
10.0 bar |
| 20.5 mA | Policy boundary | Document inclusive/exclusive decision |
| 20.6 mA | OVER_RANGE |
Hold last valid value |
TYPE SignalQuality : (VALID, UNDER_RANGE, OVER_RANGE); END_TYPE
IF Current_mA < 3.6 THEN
PressureQuality := UNDER_RANGE;
ELSIF Current_mA > 20.5 THEN
PressureQuality := OVER_RANGE;
ELSE
PressureQuality := VALID;
Pressure_bar := (Current_mA - 4.0) * (10.0 / 16.0);
Pressure_bar := LIMIT(0.0, Pressure_bar, 10.0);
END_IF;
PressureValid := PressureQuality = VALID;
The diagnostic thresholds and clamp serve different purposes. The quality test decides whether the measurement may be used. The clamp protects the displayed engineering value within the accepted diagnostic window, where a current slightly below 4 mA or above 20 mA could otherwise yield a small negative or greater-than-span value. Whether that is correct depends on the transmitter, module, alarm philosophy, and process requirement.
Grade it: require named units, real-number arithmetic, exact endpoints and midpoint, threshold boundary tests, separate quality, and a documented bad-value policy. Bonus: translate module counts to milliamps using the exact hardware range and compare module diagnostics with the calculated band.
Structured Text solution 4: bounded array statistics
Problem and test data
Given a fixed array of eight valid REAL samples, calculate minimum, maximum, and arithmetic mean during one invocation. The exercise teaches array bounds, initialization, loop limits, and accumulator types. For a production task, measure execution time and decide whether the data can change while being read.
| Dataset | Expected minimum | Expected maximum | Expected mean |
|---|---|---|---|
2, 4, 6, 8, 10, 12, 14, 16 |
2 | 16 | 9 |
5, 5, 5, 5, 5, 5, 5, 5 |
5 | 5 | 5 |
-4, -2, 0, 2, 4, 6, 8, 10 |
-4 | 10 | 3 |
100, 1, 1, 1, 1, 1, 1, 1 |
1 | 100 | 13.375 |
VAR
Samples : ARRAY[0..7] OF REAL;
Index : INT;
Sum : LREAL;
Minimum : REAL;
Maximum : REAL;
Mean : LREAL;
END_VAR
Minimum := Samples[0];
Maximum := Samples[0];
Sum := 0.0;
FOR Index := 0 TO 7 DO
IF Samples[Index] < Minimum THEN
Minimum := Samples[Index];
END_IF;
IF Samples[Index] > Maximum THEN
Maximum := Samples[Index];
END_IF;
Sum := Sum + REAL_TO_LREAL(Samples[Index]);
END_FOR;
Mean := Sum / 8.0;
Initializing minimum to zero would fail for an all-positive dataset if the required result is the minimum sample, and initializing maximum to zero would fail for an all-negative dataset. Taking the first element makes the assumption explicit: the array must contain at least one element. Some environments allow lower/upper-bound introspection; others use project constants or different conversion functions. Keep the acceptance matrix and translate the implementation.
Grade it: verify the loop cannot exceed the array, minimum/maximum start from actual data, accumulator precision is deliberate, division is non-integer, and worst-case task time is acceptable. Bonus: add per-sample quality and exclude invalid values without dividing by zero when none are valid.
Structured Text solution 5: CASE state machine with fault recovery
State contract
Control an ordinary motor sequence with five states: IDLE, STARTING, RUNNING, STOPPING, and FAULT. Start requires healthy permissives. Starting waits for feedback with a timeout. Running faults if feedback disappears without a stop request. Stopping waits for feedback to clear with a timeout. Reset is accepted only while feedback is off and permissives are healthy.
| Current state | Normal transition | Abnormal transition | Output ownership |
|---|---|---|---|
IDLE |
Start edge → STARTING |
None; unhealthy permissive rejects start | Command off |
STARTING |
Feedback → RUNNING |
Stop → STOPPING; timeout → FAULT |
Command on |
RUNNING |
Stop/lost permissive → STOPPING |
Unexpected feedback loss → FAULT |
Command on while valid |
STOPPING |
Feedback off → IDLE |
Stop timeout → FAULT |
Command off |
FAULT |
Valid reset → IDLE |
Invalid reset remains FAULT |
Command off; fault on |
StartTimer(IN := State = STARTING, PT := T#3s);
StopTimer(IN := State = STOPPING, PT := T#3s);
MotorCommand := FALSE;
FaultActive := FALSE;
CASE State OF
IDLE:
IF StartEdge AND PermissivesHealthy AND NOT MotorFeedback THEN
State := STARTING;
END_IF;
STARTING:
MotorCommand := TRUE;
IF StopRequest OR NOT PermissivesHealthy THEN
State := STOPPING;
ELSIF MotorFeedback THEN
State := RUNNING;
ELSIF StartTimer.Q THEN
FaultCode := 10; (* feedback failed to appear *)
State := FAULT;
END_IF;
RUNNING:
MotorCommand := TRUE;
IF StopRequest OR NOT PermissivesHealthy THEN
State := STOPPING;
ELSIF NOT MotorFeedback THEN
FaultCode := 20; (* feedback lost unexpectedly *)
State := FAULT;
END_IF;
STOPPING:
IF NOT MotorFeedback THEN
State := IDLE;
ELSIF StopTimer.Q THEN
FaultCode := 30; (* feedback failed to clear *)
State := FAULT;
END_IF;
FAULT:
FaultActive := TRUE;
IF ResetEdge AND NOT MotorFeedback AND PermissivesHealthy THEN
FaultCode := 0;
State := IDLE;
END_IF;
ELSE
FaultCode := 99; (* invalid state representation *)
State := FAULT;
END_CASE;
The listing is intentionally vendor-neutral and uses an illustrative enum and timer call. Translate declarations and constants to the selected target. Also notice the one-invocation boundary: writing State := STARTING in the idle branch does not retroactively execute the starting branch during that same CASE evaluation. The next invocation selects it.
Required state-machine tests
| Test | Starting condition | Stimulus | Expected evidence |
|---|---|---|---|
| Normal start | Idle, healthy, feedback off | Start edge then feedback before timeout | Starting then Running; command on |
| Stop during start | Starting | Stop true | Stopping; command off |
| Start timeout | Starting | Feedback stays off | Fault 10; command off |
| Feedback lost | Running | Feedback false, no stop | Fault 20 |
| Stop timeout | Stopping | Feedback stays true | Fault 30 |
| Reset rejected | Fault, feedback true | Reset edge | Remains faulted |
| Invalid state | Isolated approved test | Inject invalid representation if target permits | Fault 99 policy |
| Restart | Every relevant state | Controlled runtime/power transition | Approved initial/retained state and no unintended command |
Grade it: every state owns outputs, transition priority is explicit, normal and abnormal feedback have different diagnoses, reset is conditional, unknown state has a policy, and restart is tested on the actual target.
Structured Text solution 6: reusable function block with two instances
Why instance testing matters
A function block combines logic with instance memory. Calling one type twice should produce two independent state histories. The test therefore needs Pump_A and Pump_B, different inputs, and traces that prove one instance's timer or fault does not alter the other.
FUNCTION_BLOCK FB_PumpMonitor
VAR_INPUT
StartRequest : BOOL;
Feedback : BOOL;
ResetEdge : BOOL;
END_VAR
VAR_OUTPUT
Command : BOOL;
Fault : BOOL;
END_VAR
VAR
StartDelay : TON;
END_VAR
Command := StartRequest AND NOT Fault;
StartDelay(IN := Command AND NOT Feedback, PT := T#3s);
IF StartDelay.Q THEN
Fault := TRUE;
END_IF;
IF ResetEdge AND NOT StartRequest AND NOT Feedback THEN
Fault := FALSE;
END_IF;
END_FUNCTION_BLOCK
VAR
Pump_A : FB_PumpMonitor;
Pump_B : FB_PumpMonitor;
END_VAR
Pump_A(
StartRequest := PumpA_Start,
Feedback := PumpA_Feedback,
ResetEdge := PumpA_Reset
);
Pump_B(
StartRequest := PumpB_Start,
Feedback := PumpB_Feedback,
ResetEdge := PumpB_Reset
);
PumpA_Command := Pump_A.Command;
PumpB_Command := Pump_B.Command;
PumpA_Fault := Pump_A.Fault;
PumpB_Fault := Pump_B.Fault;
| Instance test | Pump A | Pump B | Expected isolation |
|---|---|---|---|
| A normal, B idle | Starts and receives feedback | No request | Only A command changes |
| A times out, B normal | Feedback missing | Feedback appears | A faults; B keeps running |
| Reset A | Valid reset sequence | Running | A clears; B memory is unchanged |
| Simultaneous start | Feedback delayed differently | Feedback delayed differently | Each timer reflects its own elapsed history |
| Call skipped | Deliberately omit one call in an isolated test | Called normally | Record target timer/FB behavior; B remains independent |
This exercise deliberately keeps the block small. A production block may also separate request, command, mapped output, feedback, availability, active diagnosis, latched first-out diagnosis, mode, and maintenance inhibit. More fields do not automatically mean better design: every interface member needs a clear owner, true-state meaning, and acceptance case.
Grade it: create two real instances, prove independent memory, test a timeout and valid reset for each, centralize physical output mapping outside the reusable logic if required by the architecture, and record the target's FB/timer invocation semantics.
Vendor translation checklist: ST is portable in intent, not automatically in source
The IEC standard provides a common language foundation, but an exercise can still behave differently after a careless copy/paste. Preserve the problem and acceptance tests while translating these surfaces.
| Surface | Questions to answer on the selected platform |
|---|---|
| Program organization | Is this a program, routine, function, function block, method, or organization block? |
| Task execution | Which cyclic/event task calls it, at what period and priority, with what watchdog? |
| I/O update | When are physical inputs sampled and outputs updated relative to program execution? |
| Timer/counter | What type, call syntax, time representation, reset rule, skipped-call behavior, and retentivity apply? |
| Edge detection | Which built-in trigger is supported, or where is previous-state memory stored? |
| Types/conversions | Which integer widths, overflow rules, enum representation, literal syntax, and explicit conversions apply? |
| Arrays/loops | What are declared bounds; can they be inspected; can the loop counter pass the terminal value safely? |
| Initialization | Which values initialize on download, warm restart, cold restart, power cycle, or online change? |
| Output ownership | Can cross-reference prove every command has one intended writer? |
| Diagnostics | Which trace, watch, force, log, and task-time tools provide evidence without altering behavior? |
| IEC-style concept | CODESYS/TwinCAT family | Siemens SCL | Rockwell Logix ST |
|---|---|---|---|
IF, CASE, bounded FOR |
Common syntax with product/library details | SCL implementation with block/task context | Logix ST syntax and instruction set |
| Timer instance | Library FB instance | IEC timer or selected instruction/data context | Timer instruction and tag/control data per Logix documentation |
| FB instance memory | Declared POU instance | Instance data according to block architecture | AOI/instruction/routine architecture differs; translate design, not name alone |
| Trace and timing | Runtime/IDE tools and task settings | TIA/CPU diagnostic and trace facilities | Logix task, trend, trace and cross-reference facilities |
The table is a routing aid, not a compatibility claim. Use the exact software release and controller documentation. Compile warnings, implicit conversions, changed time bases, or altered reset behavior are deviations that belong in the exercise record.
How to practise troubleshooting instead of memorizing solutions
After a solution passes, inject a defect. Troubleshooting practice is more transferable when the learner must locate the first failed boundary rather than guess a component.
| Injected defect | Evidence to inspect first | Misleading shortcut to avoid |
|---|---|---|
| Start input never changes | Raw input/tag and true-state definition | Rewriting the latch before proving the sampled request |
| Command true, feedback absent | Command, mapped output, device status, feedback input, timeout | Calling it “bad code” or “bad motor” without separating boundaries |
| Timer never completes | Enable, preset, elapsed, task invocation, reset conditions | Increasing the preset randomly |
| Sequence stuck | Current state, transition inputs, timeout, first-out record | Forcing the next state without understanding the failed transition |
| Analog value implausible | Raw counts, module range, units, scaling endpoints, quality | Retuning downstream control to compensate for wrong scaling |
| One FB instance affects another | Instance declaration, parameter mapping, shared/global writers | Assuming “same block” means shared internal state |
Use this diagnosis order: request → permissive → state → command → mapped output → feedback → timeout/quality → recovery. It gives an AI answer engine or human reviewer a compact, citable model while still directing the practitioner to the evidence required on the actual system.
For a deeper fault workflow, use the PLC troubleshooting guide. For runnable fault injection, use the PLC troubleshooting simulator.
A four-week PLC exercise plan
| Week | Daily focus | Exit evidence |
|---|---|---|
| 1 | Exercises 1–12; repeat selected logic in ladder and ST | Truth tables, edge traces, stop priority, documented restart memory |
| 2 | Exercises 13–24 | Timer/counter matrices, units, boundary and reset cases |
| 3 | Exercises 25–34 plus solved state-machine exercise | State diagrams, transition coverage, per-step timeouts and fault codes |
| 4 | Exercises 35–43 and one project from 44–50 | Analog-quality tests, one complete evidence pack, portability record |
Spend more time on failed tests than on typing. A useful daily session can be forty-five minutes: ten minutes defining the case, twenty minutes implementing, ten minutes tracing, and five minutes recording what changed. Redo one old exercise from memory each week; retrieval exposes gaps that rereading hides.
Frequently asked questions
What are the best PLC programming exercises for beginners?
Start with a stop-dominant start/stop request, AND/OR/NOT combinations, mutual exclusion, a rising-edge pulse, and one alarm with acknowledgement. Each is small enough for a complete truth table or short scan trace. Do not advance only because a coil turns green; require explicit input semantics, simultaneous-condition priority, reset behavior, and a documented restart state.
Where can I find PLC programming exercises with solutions?
This page includes fifty progressive briefs, six complete ladder-logic answers, and six complete Structured Text solution contracts. The solved sets cover Boolean memory, mutual exclusion, timers and feedback timeout, counters, tank hysteresis, state sequences, analog scaling and quality, bounded arrays, a CASE state machine, and function-block instances. The examples library contains additional worked machine patterns, while the interactive labs provide executable grading.
Where can I find ladder logic exercises with answers?
Use the six ladder solutions on this page as answer models: each has a problem statement, explicit I/O list, vendor-neutral rung representation, normal and abnormal acceptance cases, and grading criteria. Do the problem from the contract before revealing the listing, then compare behavior rather than rung appearance. The practical ladder examples article is better when you want more application patterns instead of a graded exercise sequence.
Are these Structured Text exercises compatible with CODESYS?
The algorithms use common IEC-style ST, so CODESYS is a relevant target, but the listings are not a promise of unchanged compilation. Confirm declarations, timer library, edge triggers, namespaces, task assignment, initialization, target-specific types, and supported language extensions in the exact CODESYS release and device description. Preserve and rerun the acceptance cases after translation.
Can I use these as Siemens SCL exercises?
Yes, as problem and test specifications. Translate them into the selected Siemens block and data architecture, use the supported TIA Portal and CPU instructions, define optimized/non-optimized access where relevant, and verify task/OB context, timer behavior, initialization, I/O mapping, diagnostics, and target execution. Record changes instead of treating SCL and every other ST implementation as textually identical.
Can I use these as Allen-Bradley or Logix Structured Text examples?
Use the same behavior contracts and test matrices, then implement them with the exact Logix Designer release, controller family, tasks, tags, routines, instructions, and timer/control data that Rockwell documents. Verify assignment order, instruction execution, prescan/restart behavior, retentivity, produced/consumed or mapped data, and physical I/O separately.
Should I learn ladder logic or Structured Text first?
Choose the language that matches the work you must do, then learn both. Ladder is highly readable for discrete interlocks and common plant troubleshooting. ST is strong for calculations, arrays, data handling, and explicit state logic. Reimplementing the same acceptance contract in both languages teaches the control behavior rather than tying the concept to syntax.
How do I know whether my PLC exercise solution is correct?
Correctness is evidence that the implementation satisfies the stated contract on the selected execution environment. Run normal, boundary, simultaneous, timeout, reset-rejection, and restart cases; trace inputs, current state, memory, timers, commands, feedback, and fault code. Passing one nominal demonstration is necessary but insufficient.
How many PLC exercises should I complete before applying for work?
There is no defensible universal number. A smaller portfolio with complete evidence is stronger than dozens of unexplained screenshots. Aim to explain the I/O contract, state model, failure you found, tests you ran, target limitations, and safe commissioning boundary for several distinct patterns: logic, timing, sequencing, analog, diagnostics, and one integrated project.
Can a browser PLC simulator replace a real PLC for these exercises?
It can accelerate logic learning and make repeatable fault cases inexpensive. It cannot replace compiler-specific validation, representative hardware, electrical checks, I/O timing, device dynamics, network behavior, task-load measurement, retentivity testing, safe commissioning, or functional-safety verification. Use simulation as one evidence layer, not the final authority.
Where can I run Structured Text exercises online?
The interactive Structured Text exercise lab provides browser-based scenarios, scan feedback, and grading without installing an engineering suite. Start with the free scenarios, then decide whether the deeper practice library addresses your learning goal. Revalidate any pattern in the exact vendor environment before applying it to equipment.
Primary sources, review scope, and limitations
This page was materially reviewed on 30 August 2026. The sources below establish the current IEC publication record and route readers to primary vendor documentation for syntax, statements, timers, tasks, programming guidance, and target-specific execution.
- IEC 61131-3:2025 Edition 4 publication record
- PLCopen-hosted IEC 61131-3:2025 table of contents
- PLCopen coding guidelines for IEC 61131-3
- CODESYS Structured Text editor
- CODESYS
IFstatement - CODESYS
CASEstatement - CODESYS
FORstatement and overflow caution - Rockwell Automation Logix Designer Structured Text syntax
- Rockwell Automation Structured Text instruction execution
- Rockwell Automation Logix 5000 Structured Text programming manual
- Rockwell Automation timer and counter instructions
- Siemens programming guideline for S7-1200 and S7-1500
- Siemens programming style guide for TIA Portal
- Beckhoff TwinCAT 3 PLC quickstart and IEC language support
- Beckhoff Structured Text operators and target-dependent overflow note
- Beckhoff state-machine, timer, and trigger sample
- Schneider Electric Machine Expert Structured Text editor
- Schneider Electric Machine Expert online Structured Text editing
- Rockwell Automation Studio 5000 Output Energize execution and overwrite warnings
- Omron Sysmac Studio Version 1 Operation Manual, including Ladder Diagram programming
Limitations: the code is an educational, vendor-neutral expression of each stated behavior. It was not compiled unchanged on every listed platform, does not specify field wiring or a safety lifecycle, and does not certify scan time, device dynamics, or physical-machine response. Treat numerical thresholds and timings as exercise data, not universal engineering values. Validate the translated program, exact hardware, software release, I/O, network, drive/actuator behavior, hazardous-energy controls, and safety functions under the approved project process.
Next: open the interactive ladder-logic simulator, run the Structured Text lab, review the Structured Text programming guide, or choose a worked PLC example.


