09
Program Control Instructions
Up to now, the PLC has scanned your ladder logic exactly the way you wrote it — top to bottom, left to right, every rung every scan. Welcome to Part III, where that changes. Program control instructions let you bypass rungs, jump backwards, call reusable subroutines, freeze entire sections of code, force I/O immediately without waiting for the scan, and run urgent code on a strict time schedule. Used well, they make complex programs cleaner and faster. Used carelessly, they break the predictable scan model that makes PLCs reliable. This chapter shows you both — when to reach for these tools and when to leave them alone.
What you’ll be able to do after this chapter
Your goals for this chapter:
- Explain how each program-control instruction modifies the normal top-to-bottom scan order.
- Build a Master Control Reset (MCR) zone that drops every output in a section of program when a safety condition is broken.
- Use JMP and LBL to skip rungs entirely — and explain how that’s different from MCR.
- Write a subroutine (JSR / SBR / RET) for reusable code such as alarm logging or fault analysis.
- Use Immediate Input (IIN) and Immediate Output (IOT) for fast safety responses that can’t wait for the next scan.
- Recognise when forcing I/O from the programming software is appropriate — and when it’s a serious safety hazard.
- Distinguish software interlocks from hardwired safety circuits, and explain why both are required for high-risk machinery.
- Configure a Selectable Timed Interrupt (STI) to sample data or run control loops at a fixed time interval.
- Use fault routines to handle runtime errors gracefully without losing the machine.
- Apply Temporary End (TND) and Suspend (SUS) for testing, debugging, and trapping intermittent faults.
Key Concepts & Terms
Program Control — An Overview
Every PLC scan you’ve seen so far follows the same rigid pattern: read all inputs, execute every rung in order, write all outputs, repeat. That predictability is the PLC’s superpower — every machine engineer can look at a ladder program and know exactly when each rung will run.
Program control instructions bend that rule on purpose. They give you tools to:
- Skip a section of rungs entirely (JMP / LBL).
- Force every output in a section to OFF while still letting the rungs scan (MCR).
- Call a reusable block of code from anywhere in the program (JSR / SBR / RET).
- Read or write an I/O point right now, mid-scan, without waiting for the I/O update phase (IIN / IOT).
- Schedule code to run at strict time intervals, independent of scan time (STI).
- Catch runtime errors with dedicated fault-handler routines.
- End the scan early for testing or freeze the CPU for diagnostics (TND / SUS).
Each instruction is a tool, and like any tool it has a right and a wrong way to be used. The chapter’s goal is to make you fluent with all of them, so you can pick the right one for any control problem — and just as importantly, recognise when you should leave them alone.
Figure 9.1 — Scan flow with program control instructionsNormal scan goes straight down. JMP skips rungs. MCR scans them but forces outputs OFF. JSR detours into a subroutine and returns to the next rung.
Master Control Reset (MCR)
An MCR zone is a section of program bracketed by two MCR instructions. The first MCR (at the top of the zone) sees the rung condition that controls the zone — typically your safety chain. The second MCR (at the bottom) closes the zone with an unconditional rung. Everything between them is “inside the zone”.
Two states matter:
- Zone enabled — the first MCR’s rung is true. Rungs inside the zone execute exactly as if the MCR pair didn’t exist. Your normal logic runs and drives outputs as designed.
- Zone disabled — the first MCR’s rung is false. All non-retentive outputs (OTE) inside the zone are forced to 0. The rungs are still scanned, but their OTE results are overridden. Latched outputs (OTL/OTU), timer accumulators (RTO), and counter accumulators retain their values — which is sometimes what you want, and sometimes a trap.
When to use MCR
Whenever a single condition — typically a safety interlock or a master “system enable” — should drive a whole section of outputs to a known-safe state. Light curtain breaks → MCR zone disables every motor in the cell. Safety relay drops → MCR zone disables every solenoid on a press. The advantage over wiring the safety bit into every rung is dramatic: you write it once, in the MCR rung, and it covers everything inside the zone.
Critical Limits
MCR is not a safety device.
- An MCR zone disables outputs through software. If the PLC processor itself fails, the MCR cannot help.
- For SIL- or PL-rated safety circuits, you must use hardwired safety relays in addition to (or instead of) MCR. See Section 9.7.
- MCR does not zero retentive accumulators (RTO timers, counters). If your safety logic must reset those too, add explicit RES rungs alongside the MCR.
- Never nest MCR zones inside each other — most platforms forbid it, and even when allowed it makes troubleshooting nearly impossible.
Jump (JMP) and Label (LBL)
JMP tells the scan to skip ahead to a matching LBL instruction. When the JMP rung is true, the rungs between JMP and LBL are not scanned at all. They don’t run; they’re invisible to the processor for that scan. When the JMP rung is false, scan continues normally and reaches the rungs between JMP and LBL one at a time.
Each JMP/LBL pair shares an integer label number (e.g., LBL 03). You can have many JMP/LBL pairs in a program, each with its own number. You can also have multiple JMP instructions targeting the same LBL — different conditions all funnel to the same skip target.
The critical difference between JMP and MCR:
| Behaviour | JMP / LBL | MCR zone |
|---|---|---|
| Are rungs scanned? | No (skipped entirely) | Yes, but outputs forced off |
| What happens to OTE outputs? | Hold their last state | Forced to 0 |
| What happens to OTL/OTU latches? | Hold their last state | Hold their last state |
| What happens to TON/TOF timers? | Frozen (their input rung never updates) | Reset (their input rung sees forced-off condition) |
| Best for | Optional code, speed optimisation, mode-specific logic | Master safety zone, “system enable” disabling many outputs at once |
Why “hold their last state” matters
Imagine a motor controlled by an OTE inside a JMP-skipped section. If the JMP becomes true while the motor is running, the motor keeps running — its OTE rung doesn’t get scanned, so the OTE keeps writing whatever value it last wrote. This is rarely what you want for safety. For safety zones use MCR; for “this code only runs sometimes” use JMP.
JMP/LBL is also used for backward jumps (jumping to an earlier LBL) on some platforms — but most engineers avoid this because it’s the ladder equivalent of a goto loop and can blow past the watchdog timer if the loop never exits.
Subroutines (JSR / SBR / RET)
A subroutine is a separate program file containing reusable code. It’s called from the main program with a JSR (Jump to Subroutine) instruction, executes from start to finish, then returns to the rung after the JSR. The same subroutine can be called from many places in the main program, or even from inside other subroutines.
Three instructions work together:
- JSR — placed in the main program. Names the subroutine file to call (e.g.,
JSR file:U3). Optionally lists input parameters and output destinations. - SBR — placed at the very first rung of the subroutine file. Receives the input parameters listed in the JSR.
- RET — placed at the end of the subroutine. Returns control to the rung after the JSR. Optionally returns output values to the caller.
When to write a subroutine
Whenever you find yourself copying the same logic into multiple places. The classic uses:
- Diagnostic and alarm logic that runs the same way for every motor, valve, or station.
- Scaling routines that convert raw analog values to engineering units — written once, called from every analog rung.
- Recipe selection where one subroutine handles “load recipe parameters” and is called whenever a new recipe is selected.
- Conditional logic that’s only relevant when a particular feature is enabled — wrap it in a subroutine and only call it then.
The big advantage
Test the subroutine once. Bug-fix it once. Improve it once. Every place that calls it gets the benefit. Compare with the alternative — copying the same 20 rungs into 15 different places — and a year later, finding a bug you have to track down 15 separate copies of. Subroutines are how you scale a program from “one machine” to “twenty machines on the same line”.
Subroutine pitfalls
Things to watch out for:
- Overuse: a subroutine called from one place adds complexity without saving anything. Inline that code instead.
- Side effects on shared bits: if two subroutines write to the same internal bit, the order of JSR calls determines the result — fragile and confusing.
- Parameter mistakes: passing the wrong word to a parameterised JSR causes silent corruption that’s hard to trace.
- Recursion: most platforms forbid a subroutine calling itself. Even when allowed, recursion can overflow the stack.
- Conditional subroutine calls inside a fault routine: if the subroutine itself can fault, you’re inside a fault from another fault — usually unrecoverable.
Immediate Input/Output Instructions (IIN / IOT)
Recall from Chapter 5 the three-phase scan: read all inputs into the input image, run all rungs, write the output image to all outputs. This means a typical input is read once per scan at the very beginning, and a typical output is written once per scan at the very end. For most applications, that’s plenty.
For some applications, that’s far too slow. An emergency-stop signal needs to disable outputs within milliseconds. A safety light curtain on a high-speed press cannot wait for the next scan to fire its stop relay. For these cases, two instructions break the normal scan rule:
- IIN — Immediate Input. When this instruction executes, the PLC stops, reads the named input directly from the I/O card, updates the input image table for that bit, and continues. Subsequent rungs see the freshly-read value, not the value from the start-of-scan image.
- IOT — Immediate Output. When this instruction executes, the PLC stops, writes the named output directly to the I/O card without waiting for the end-of-scan output update, and continues. The actual physical output changes state immediately.
Real-world impact
On a 20 ms scan, normal I/O updates can mean an input change isn’t reflected on an output until 40 ms later (read it next scan, output it the scan after). With IIN at the top of the program and IOT at the bottom of a critical rung, that delay drops to a fraction of a millisecond — fast enough for safety-critical bypasses.
Use IIN/IOT sparingly. Each instruction adds CPU overhead because it forces a hardware access mid-scan. Reserve them for genuinely time-critical signals — emergency stops, light curtains, safety mats, protective interlocks. Everything else is fine on the normal scan.
Forcing External I/O Addresses
“Forcing” is a debugging feature of the programming software, not a ladder instruction. It lets the engineer override the actual hardware state of any input or output bit. A forced bit reads or writes whatever value the engineer set, regardless of what the wire or the program says.
Two flavours:
- Force input ON / OFF — pretend the input is at the forced state. The CPU and your ladder logic see it as forced. Useful for testing rungs without having to physically actuate a switch or sensor.
- Force output ON / OFF — drive the physical output to the forced state regardless of the rung result. Useful for proving wiring, testing actuators, and simulating fault conditions.
Every modern PLC programming environment shows forced bits with a clear visual indicator — usually a yellow halo or a “F” badge in the online monitor. There’s also typically a “forces enabled” indicator on the CPU itself (a flashing yellow LED on most Allen-Bradley CPUs) so anyone walking past the panel can see that the program is running with forces active.
Why forces are dangerous
Forces stay in effect until explicitly cleared.
- If you force an output ON during commissioning and then leave the site without clearing the force, the output stays ON forever. You will have created a hidden, persistent override that no one looking at the ladder logic can see.
- Forces survive program downloads on most platforms.
- Forces can be lost on power cycle on some platforms — but not all. Always assume they persist.
- Always clear all forces before leaving site, before final hand-over, before publishing a program update. Make it a checklist item.
The legitimate uses of forcing are testing, diagnostic work, and short-term troubleshooting. The illegitimate use is “patching” a wiring or programming problem with a permanent force instead of fixing the root cause. Don’t do that.
Safety Circuitry — Why Software Alone Is Not Enough
Every PLC program you’ll ever write contains some logic that’s “safety-related” — a stop button, an interlock, a guard switch. The temptation is to handle all of it in ladder logic. After all, the PLC is reliable and the rungs are right there. But there’s a critical principle that every controls engineer must internalise:
A PLC is a single point of failure. If the CPU crashes, the watchdog locks up, or the program has a bug, every “safety” interlock in software is lost.
Real industrial safety circuits use hardwired protection that does not depend on the PLC at all. An emergency-stop button connects through a safety relay directly to the contactor coils that drive the motors. Press the E-stop and the motor contactors drop out — no PLC involvement, no software, no firmware. Even if the PLC is on fire, the motors stop.
Two-channel monitoring
Modern safety circuits use two independent channels through the safety relay. Both channels must agree, both must transition together when the E-stop is pressed, and both must reset together when the system is rearmed. If either channel fails — open wire, stuck contact, welded relay — the safety relay refuses to allow restart. This is the core of how SIL (Safety Integrity Level) and PL (Performance Level) ratings are achieved.
Where the PLC fits in the safety system
The PLC’s role in a properly engineered safety system is monitoring and indication, not protection. Bring the safety relay’s status contacts back to PLC inputs so the program knows whether the safety chain is enabled. Use those bits to drive HMI indicators, alarm logs, and software interlocks for non-safety functions. The actual disconnection of motor power happens in the hardwired safety circuit, not in the PLC program.
When MCR, JMP, and software interlocks are appropriate
For non-safety control logic — process interlocks, recipe-based bypasses, mode selection, optional features — software is fine. MCR zones are excellent for “system enable” type signals. JMP is excellent for mode-specific code. Just don’t use any of them as your only protection against a hazardous machine state. The hardwired safety relay is mandatory; the software is supplementary.
Selectable Timed Interrupts (STI)
Most code in a PLC runs once per scan, and the scan time varies based on how much logic is true and how complex the math is. For most control jobs that’s fine. For some jobs — closed-loop control, motion profiles, fast data sampling — it’s not.
A Selectable Timed Interrupt is a special subroutine that runs at a strict time interval set by the engineer, regardless of where the main scan happens to be. Configure an STI with a 50 ms period and the PLC will execute that subroutine every 50 ms — interrupting the main scan if necessary, completing the STI’s logic, then resuming the main scan exactly where it left off.
What STIs are good for
- PID control loops that need a fixed sample rate to stay tuned correctly.
- Motion control calculations that depend on consistent timing.
- Data logging at precise intervals for trending and analysis.
- Filtering noisy analog signals using algorithms that assume a known sample period.
- Communication polling where another device expects data at a fixed cadence.
STI cautions
STI rules to follow:
- Keep the STI subroutine short. Whatever runs in the STI runs at the STI rate, not the scan rate. Slow STI logic eats CPU time fast.
- Don’t share bits between main and STI without thinking. The STI can fire mid-rung in the main program. If both touch the same word, you can get torn reads.
- Set the STI period larger than the worst-case STI execution time. Otherwise the STI starts before the previous one finishes — instant overload.
- Never put a long communication or BSL/BSR shift in an STI. Those instructions can take many milliseconds; if they run inside a 10 ms STI, the CPU faults.
Fault Routines
Sometimes a PLC encounters something it can’t handle in normal logic — a math overflow, a divide-by-zero, an array index out of range, a watchdog timeout, a comms-card fault. Without intervention, the CPU faults and the entire program halts. Every output drops, every motor stops, the operator sees a flashing red LED. Recovery requires a manual fault-clear and often a restart.
A fault routine is a special subroutine that the PLC executes automatically the moment a runtime fault occurs. Inside the fault routine you can:
- Log the fault — record the fault code, the rung that caused it, the timestamp.
- Drive critical outputs to a safe state — close valves, turn off heaters, etc.
- Try to clear the fault programmatically (some can be cleared, some cannot).
- Decide whether to continue running or halt for operator attention.
Fault routines are typically configured in the controller properties (not as a normal subroutine call). The CPU knows to invoke them automatically when a fault is detected.
A practical example
A line uses an analog flow meter. One day, a wire breaks and the flow meter reports an out-of-range value. Without a fault routine, the next time the program tries a math operation on that value, it overflows — CPU faults, every motor stops, operator confusion. With a fault routine: detect the overflow, log “flow meter fault on AI 1.3”, set a substitute flow value, raise an alarm, continue running on the substitute. The operator gets a clear alarm, the production line keeps moving, and the maintenance team can repair the wire without an emergency.
Temporary End (TND)
The Temporary End instruction does exactly what its name says — it temporarily ends the program scan. When TND is true, the rungs after TND are not executed for that scan. The PLC jumps to the end-of-scan output update, sends outputs, and starts the next scan from rung 0 as normal.
TND is a development and testing tool, not a feature you’d typically leave in production code. Two common uses:
- Section-by-section testing. When developing a long program, place a TND temporarily after the section you’re working on. The rungs below don’t run, so you can test just the section above without the rest of the program interfering.
- Conditional bypass. Place a TND with an XIC of a “test mode” bit. When in test mode, only the rungs above the TND run; production rungs below are skipped. Toggle the bit off and the full program runs.
TND vs. JMP/LBL
TND ends the scan. JMP/LBL just skips a section. The difference matters: with TND, every rung after it is bypassed for the entire scan. With a JMP/LBL pair, you only skip the section between them, and rungs after the LBL still run normally. Use JMP/LBL for “skip this part”; use TND for “stop here entirely”.
Suspend (SUS)
The Suspend instruction is the diagnostic tool of last resort. When SUS is true, the PLC immediately halts execution, captures the entire CPU state to non-volatile memory, and stops. All outputs go to their failure-safe state. The CPU’s status LEDs change to indicate “suspended”. An engineer connecting with the programming software sees the captured state and can analyse exactly what was happening at the moment SUS fired.
Each SUS instruction has a suspend ID — an integer the engineer chose when writing the rung. When SUS halts the CPU, the suspend ID is recorded so you know which SUS instruction fired (you can have many in the program, each with a different ID).
When SUS is appropriate
SUS exists for catching intermittent faults that are too rare to reproduce on demand. Imagine a machine that mysteriously stops every two or three days for no apparent reason. You suspect a particular condition is causing it but can’t catch the moment in real time. Add a SUS rung that fires when that condition is detected. Next time it happens, the PLC freezes itself with the entire program state captured — every register, every bit, every counter and timer ACC. You connect the laptop, look at the snapshot, and find the cause.
SUS rules
Things to remember about SUS:
- SUS halts production. Never leave a SUS rung in production code unless you genuinely want the line to stop and freeze when the condition fires.
- Recovery requires a manual restart from the programming software or operator panel. SUS isn’t self-clearing.
- Document each SUS with a comment explaining what condition triggered it and what the engineer should look at when it fires. A future engineer who finds a halted PLC with no documentation is in for a long debugging session.
Worked PLC Programs
Five Programs — From an MCR Safety Zone to a Timed Sampling Subroutine
Each program below shows one of the program-control instructions used the right way: a real industrial requirement, a clean rung structure, and an explanation of the trade-offs. Pay attention to the safety notes — for these instructions, knowing when not to use them is as important as knowing how.
The problem: a robot cell contains four motorised axes, two solenoid grippers, and a conveyor. A light curtain across the cell entrance must, when broken, drop every one of those outputs to OFF. Rather than wiring an XIO of the light-curtain bit into seven separate rungs, we wrap the cell’s output rungs in an MCR zone driven by the light-curtain status. One rung at the top of the zone protects everything inside.
Inputs & Outputs
INPUTS
I:1/0 — Light_Curtain_OK (1 = beam intact)
I:1/1 — Cell_Enable selector
I:1/2 to I:1/5 — Axis position bits etc.
OUTPUTS
O:2/0–O:2/3 — Axis 1–4 motors
O:2/4, O:2/5 — Solenoid grippers
O:2/6 — Conveyor
All forced OFF when MCR zone is disabled.
Ladder Diagram (Five Rungs Shown)
The MCR pair (rungs 0 and 6) brackets all output rungs in between. The alarm horn (rung 7) sits outside the zone so it can fire when the zone is disabled.
How it works
- Light curtain intact, cell enabled. Rung 0’s MCR sees its rung true. Rungs inside the zone (1–5) execute as normal logic. Whatever drives Axis 1’s command bit (
I:1/2) drives the Axis 1 motor (O:2/0); same for the other axes, grippers, and conveyor. - Light curtain breaks (someone walks into the cell).
I:1/0goes to 0. Rung 0’s MCR rung is now false, the zone is disabled. Every OTE inside the zone is overridden to 0 — every motor, every solenoid, the conveyor. All physical outputs drop simultaneously. - Rung 7 (outside the zone) keeps running normally. Its XIO of the light-curtain bit fires, energising the alarm horn to alert the operator. This rung must be outside the MCR zone — if it were inside, it would also be forced off, and we’d lose the alarm exactly when we needed it.
- Operator clears the obstruction. Light curtain restores, MCR rung true again, zone re-enables. Outputs are not automatically re-energised — each rung’s logic must be true on its own merits before its output comes back. Latched outputs (OTL) hold their state through the disable; that’s a deliberate trade-off — see safety note below.
The problem: a packaging machine has two operating modes selected by a key switch — AUTO (full sequence: count, fill, cap, label) and MANUAL (operator drives each station individually with pushbuttons for setup and maintenance). In manual mode, the entire AUTO-sequence section of the program should be skipped — both to prevent it from interfering with manual commands and to save scan time.
Inputs & Outputs
INPUTS
I:1/0 — Mode switch (1 = AUTO, 0 = MANUAL)
I:1/1–I:1/4 — Manual jog buttons
I:1/5–I:1/8 — AUTO-sequence sensors
OUTPUTS
O:2/0–O:2/3 — Station solenoids
B3:0/x — Internal sequence bits (used by AUTO logic)
Ladder Diagram (Outline)
In MANUAL mode, the JMP at rung 1 fires (XIO of AUTO bit passes) and scan jumps directly to LBL 03 — bypassing the entire AUTO-sequence section.
How it works
- AUTO mode (key switch in AUTO position).
I:1/0= 1. Rung 0’s manual-jog logic still runs but is gated by an XIO of the AUTO bit, so manual buttons do nothing. Rung 1’s JMP rung is false (XIO of AUTO blocks). Scan continues into the AUTO sequence. AUTO sequence rungs run as designed and drive the outputs. - MANUAL mode (key switch in MAN position).
I:1/0= 0. Rung 0’s manual-jog logic now allows the operator to drive the outputs directly. Rung 1’s JMP rung is true (XIO passes). The PLC jumps directly to LBL 03 at rung 11, skipping every AUTO-sequence rung in between. Those rungs don’t run at all this scan, so AUTO-mode internal bits and stage flags don’t fight the operator’s manual commands. - Alarm and HMI rungs after LBL 03 run regardless of mode — they need to in both. Things like “report mode to HMI”, “log button presses”, “watchdog timer” must always run.
Why JMP and not MCR?
If we used MCR around the AUTO section, the rungs would still scan and any internal bits inside would be forced off. That would break the AUTO sequence the next time the operator switched back to AUTO — sequence stages would all start from scratch. With JMP, the AUTO sequence rungs simply don’t run while in MANUAL mode, but their internal bits keep their last values. When the operator switches back to AUTO, the sequence resumes from where it left off (or you can use a separate “restart” button to clear the stage bits — your choice).
The problem: a machine has six motors, and for each one we want the same diagnostic logic — check the auxiliary contactor feedback, compare it to the command bit, raise an alarm if they disagree for more than 2 seconds (start fault), log the fault number to the alarm queue. Rather than copying 8 rungs of diagnostic logic six times (48 rungs total, all near-identical), we write the diagnostic once as a subroutine and call it six times — passing the motor’s command bit, feedback bit, and a unique fault ID each time.
Inputs & Outputs (per motor)
JSR INPUTS (passed)
Command bit — the motor’s commanded state (output bit)
Feedback bit — auxiliary contact input
Fault ID — integer 1–6
JSR OUTPUTS (returned)
Fault flag — 1 if disagreement > 2 s
Internal: writes fault ID to alarm queue N7:50
Main Program Calls
Six near-identical JSR rungs call the same diagnostic subroutine with different parameters. The fault flags B3:5/0 to B3:5/5 reside in one word; if any are non-zero, the master alarm fires.
Inside the Subroutine (file U3)
SBR receives the parameters at the top; the diagnostic logic uses them; RET sends the result back to the caller.
How it works
- Main scan reaches rung 0. JSR fires. The PLC pushes its current rung index, jumps to the start of file U3, and binds the parameters in the JSR rung to the parameter slots in the SBR rung.
- The subroutine runs. Inside U3, the cmd bit and fb bit refer to motor 1’s actual addresses. The XOR detects disagreement; the TON times it. If the disagreement persists for 2 seconds, the fault flag is set and the fault ID (1) is logged.
- RET fires. The PLC pops the saved rung index and resumes the main scan at rung 1.
- Rung 1 fires the same JSR with motor 2’s parameters. Same code runs, but now cmd, fb, ID, and fault bits all point to motor 2. Same diagnostic logic, separate state.
- This repeats for motors 3–6. Six calls to the same 5-rung subroutine give us 30 rungs of effective diagnostic coverage with one piece of code to maintain.
The problem: a high-speed stamping press has a primary safety circuit (hardwired safety relay → contactor coil) that handles the actual motor cut-off. But the PLC also drives an auxiliary “press-armed” solenoid and a number of HMI indicators that should drop within 1 ms of an emergency-stop signal — far faster than the typical 15 ms scan would allow. We use IIN at the start of each scan to read the E-stop bit immediately, and IOT at the bottom of the safety-response rung to write the auxiliary outputs immediately, bypassing the normal scan latency.
Important context
IIN/IOT supplements hardware; it does NOT replace it.
- The actual motor power cutoff comes from the hardwired safety relay, not from this rung.
- If the PLC CPU itself fails, IIN/IOT fails too. Hardware safety must work even when the PLC is dead.
- This program improves response time of secondary actions — auxiliary solenoids, status indicators, soft holds — that benefit from being faster than scan rate but aren’t safety-rated by themselves.
Inputs & Outputs
INPUTS
I:1/0 — E-Stop circuit (NC, 1 = circuit healthy)
I:1/1 — Press position sensor
OUTPUTS
O:2/0 — Press-armed solenoid (auxiliary)
O:2/1 — HMI “fault” indicator
B3:0/0 — E-stop fault latch
Ladder Diagram (Four Rungs)
IIN at rung 0 reads the E-stop bit immediately. The fault latch and output rung run with the fresh value. IOT at rung 3 forces the output card to update before the scan completes.
How it works (timing breakdown)
- Without IIN/IOT: If the E-stop opens at the worst moment (just after the start-of-scan input update), the PLC won’t read the change until the next scan starts. With a 15 ms scan, that’s up to 15 ms of latency on the read, plus another ~15 ms of latency before the output card writes the result. Total: up to 30 ms before the press-armed solenoid drops.
- With IIN at rung 0: The very first thing the PLC does is re-read the E-stop input directly from the I/O card. The latency on the read drops to a fraction of a millisecond regardless of where the rest of the scan was.
- With IOT at rung 3: The instant the rung result is determined, the IOT writes the output card directly. The latency on the write drops to a fraction of a millisecond.
- Result: total worst-case latency from E-stop open to press-armed drop is now well under 1 ms — fast enough that the auxiliary solenoid effectively drops at the same instant as the hardwired safety relay.
The problem: a chemical reactor’s temperature must be sampled and logged exactly every 100 ms for later trend analysis and PID-loop tuning. The main program’s scan time fluctuates between 8 ms and 22 ms depending on alarm activity, so we cannot use the main scan to drive a fixed sample rate. Instead, we configure a Selectable Timed Interrupt with a 100 ms period, and write a small subroutine that reads the analog input, scales it to engineering units, and stores the value in a circular buffer.
Inputs & Outputs
INPUT (read in STI)
I:3.0 — Reactor RTD raw value (4–20 mA card)
STI WRITES
F8:0 — Reactor temperature in °C (display)
F8:10–F8:209 — 200-sample circular buffer (20 s of history at 100 ms)
N7:0 — Buffer write index (0–199)
STI Configuration
Where to set the period
STI configuration lives in the controller properties (or status file S:30 on Allen-Bradley SLC), not in the ladder logic itself. You set STI period = 100 ms and STI subroutine file = U4. After download, the CPU executes file U4 every 100 ms regardless of where the main scan happens to be.
STI Subroutine (file U4)
Four short rungs: scale, copy to circular buffer, increment index, wrap at 200. Total execution time well under the 100 ms STI period.
How it works
- STI period reaches 100 ms. CPU pauses the main scan wherever it is, jumps into file U4.
- Rung 0 — Scale. SCP reads
I:3.0raw count and converts to a calibrated temperature inF8:0(0.0 to 250.0 °C). The HMI continuously displays this value. - Rung 1 — Buffer write. COP copies the current
F8:0into the array slot at indexN7:0. After 100 ms the next sample lands in the next slot. - Rung 2 — Increment. ADD bumps the index by 1.
- Rung 3 — Wrap. If the index reaches 200, CLR resets it to 0. The buffer holds the last 200 samples — exactly 20 seconds of history at 100 ms sampling.
- Implicit RET at the end of file U4 returns control to the interrupted main scan — which resumes exactly where it was paused.
Why this needs an STI
If we put the same logic in the main program, samples would be taken at scan rate — 8 ms one cycle, 22 ms the next, 13 ms the one after. Trend analysis would be useless because the timestamps would be irregular. The STI guarantees a sample exactly every 100 ms regardless of scan time. PID loops, motion control, and any signal-processing math depend on this consistency.
Common Student Mistakes
Things to watch out for in this chapter:
- Treating MCR as a safety device. MCR is software, and any software interlock can fail when the PLC fails. Real safety requires hardwired safety relays. Use MCR for “drop these outputs together when the master condition is broken” — not as your only line of defence.
- Forgetting that JMP-skipped rungs hold their last state. If a motor was running when the JMP fired, it keeps running. Use MCR (which forces outputs off) when “skip and disable” is what you want, not “skip and continue”.
- Nesting MCR zones. Most platforms forbid this and the ones that allow it produce code that’s almost impossible to debug. Keep zones flat and non-overlapping.
- Calling a subroutine with the wrong parameter mapping. A misaligned parameter list silently corrupts data. Always test each JSR with its parameters before assuming the subroutine is reusable.
- Using IIN/IOT everywhere “to be fast”. Each immediate I/O instruction stops the CPU mid-scan to access the I/O card. Overuse adds latency to the rest of the program. Reserve them for genuinely time-critical signals.
- Leaving forces in production code. Forces persist until cleared and they don’t appear in the ladder. A forced output is invisible to anyone reading the program. Always clear forces before leaving site.
- Putting slow logic in an STI. The STI subroutine runs every period — if its execution time exceeds the period, the CPU faults. Keep STIs short and predictable; never put communication or BSL/BSR shifts in them.
- Sharing bits between STI and main scan without protection. The STI can fire mid-rung in the main program. Use atomic-update patterns (set a single bit at a known point in the STI, read it once at a known point in the main scan) to avoid torn reads.
- Forgetting the SUS instruction is still in production code. A leftover SUS rung from debugging will halt the line if its condition fires months later. Always remove SUS rungs before going to production.
Quick Recap
The ten things to take away from Chapter 9:
- Program control instructions bend the normal scan order. They give you tools to skip rungs, force outputs off, call subroutines, do urgent I/O, run timed code, handle faults, and pause execution.
- MCR zones force every OTE output inside the zone to OFF when the start-MCR rung is false. Excellent for system-enable safety logic, but not a substitute for hardwired safety relays.
- JMP/LBL skips a section of rungs entirely — they don’t run at all. Outputs in the skipped section hold their last state, so don’t use it for safety.
- JSR/SBR/RET subroutines turn repetitive logic into reusable functions. Pass parameters in, get results out, write the logic once, call it many times.
- IIN/IOT read or write a specific I/O point immediately, mid-scan. Drops latency from full-scan times to under 1 ms. Reserve for time-critical signals only.
- Forcing I/O overrides hardware state from the programming software. Useful for testing; dangerous if left in place. Always clear forces before leaving site.
- Hardwired safety using safety relays must protect any hazardous output. Software interlocks (MCR, JMP, ladder logic) are supplementary, not primary.
- Selectable Timed Interrupts run a subroutine on a strict time schedule regardless of main scan. Use for PID loops, fixed-rate sampling, motion math, and communication polling.
- Fault routines catch runtime errors automatically — math overflows, watchdog timeouts, hardware faults — and let you log, alarm, and recover gracefully.
- TND ends the scan early for testing. SUS halts the CPU and captures a snapshot for diagnosing intermittent faults. Both are development tools — remove from production code.
Review & Self-Assessment
Chapter 9 Review Questions
Try answering each question on your own first. Tap to reveal the answer when you’re done.
Q1What is the key behavioural difference between MCR and JMP/LBL?+
Q2Why is MCR not a substitute for hardwired safety circuits?+
Q3What three instructions together implement a subroutine, and what does each one do?+
Q4An OTE inside an MCR zone is currently energised. What happens to it the moment the zone is disabled?+
Q5A 20 ms scan PLC has an emergency-stop signal. What is the worst-case latency without immediate I/O? With IIN at the top of the program and IOT after the safety rung?+
Q6Why is forcing an output during commissioning considered dangerous if you forget to clear it?+
Q7What kind of code belongs inside a Selectable Timed Interrupt subroutine, and what kind doesn’t?+
Q8What is a fault routine, and how does it differ from a regular subroutine?+
Q9When would you use TND (Temporary End) instead of JMP/LBL?+
Q10What happens to internal bits and timer accumulators inside a JMP-skipped section while the JMP is true?+
Q11A subroutine writes to internal bit B3:0/0. The subroutine is called from three different places in the main program. What problem could this cause?+
Q12Describe an appropriate use case for the SUS (Suspend) instruction, and what makes it different from TND.+
Need help architecting a safety-rated control system or writing reusable subroutines?
Get one-on-one tutoring or design-review help from Dr Ahsan Rahman — Head of Electrical Engineering, with two decades of teaching advanced PLC architecture, functional safety, and program-control practices.