PLC Book Part III — Advanced Instructions & Data Handling Chapter 12
Chapter 12 Part III · Advanced Instructions & Data Handling Advanced ⏱ 50 min read ✦ 5 PLC Programs

12

Sequencer and Shift Register Instructions

Chapter 11 taught the PLC to compute; this chapter teaches it to orchestrate. Sequencers descend from the brass cam-and-drum machines that once ran washing machines, jukeboxes, and traffic lights — the same idea, now stored in memory and stepped by a timer. Shift registers track parts moving down a conveyor by shifting a bit each time the line advances. FIFO and LIFO queues handle work orders, print jobs, and recipe steps in the order they arrived. By the end you’ll have the orchestration tools behind every batch sequencer and the tracking tools behind every moving line in the plant.

What you’ll be able to do after this chapter

Your goals for this chapter:

  • Trace the lineage from mechanical drum sequencers to modern software sequencer instructions.
  • Configure an SQO (sequencer output) instruction with a position pointer, length, file, and mask.
  • Use SQC (sequencer compare) to verify that the field state matches the expected pattern at each step, and raise an alarm if it doesn’t.
  • Combine SQO and SQC into a real industrial pattern where one drives outputs and the other verifies sensors.
  • Use BSL and BSR bit shift registers to track defects, parts, or events as they move through positions.
  • Use FFL/FFU for first-in-first-out word queues — print jobs, work orders, recipe steps.
  • Use LFL/LFU for last-in-first-out stacks — undo buffers, function call returns, recursive logic.
  • Recognise when sequencers, shift registers, or queues are the right tool — and when each is the wrong tool.

Key Concepts & Terms

Mechanical drum sequencerCam · Roller · Step SQO · Sequencer OutputSQC · Sequencer Compare Position pointerLengthMask Sequencer file (data table)Step presetReset Control register R6EN · DN · ER bits BSL · Bit Shift LeftBSR · Bit Shift Right Bit address (input)Unloaded bitUL · Unload bit Encoder pulse · Shift trigger FFL · FIFO LoadFFU · FIFO Unload LFL · LIFO LoadLFU · LIFO Unload Stack (LIFO)Queue (FIFO) Empty (EM) · Full (FU) Part trackingDefect trackingReject station
Section 12.1

Mechanical Sequencers

Long before microprocessors, factories needed machines that would perform a series of actions in a fixed order — fill, agitate, drain, rinse, spin. The solution was a mechanical drum sequencer: a slowly rotating cylinder studded with raised bumps (cams), with a row of switches whose levers (rollers) rode against the drum’s surface. As the drum turned, each cam pushed against its switch, closing a circuit and energising whatever output that switch controlled — a valve, a motor, a heater. After one full revolution the cycle was complete.

MECHANICAL DRUM SEQUENCER — THE ANCESTOR OF SQO As the drum rotates, each cam pushes its roller, energising one output. Each angular position = one step. drive rotates SW1 SW2 SW3 SW4 SW5 Step 1 Step 2 Step 3 Step 4 Step 5

Figure 12.1 — Mechanical drum sequencerA rotating drum carries cams (raised bumps) at specific angular positions. As the drum turns, each cam in turn pushes its switch closed, energising the output assigned to that switch. Each angular position corresponds to one “step” of the sequence — exactly the same model used by software SQO instructions today.

Why this history matters

The mechanical drum did three things, all of which an SQO instruction does today:

  • Stored a sequence pattern. The arrangement of cams on the drum encoded the recipe — which outputs to energise at which step. In software, the same pattern is stored as rows in a sequencer file (one row per step, with bits for each output).
  • Stepped through the pattern. The motor turned the drum at a fixed rate; each angular position became a step. In software, a timer or event-driven trigger advances the position pointer.
  • Drove physical outputs. The cam-and-roller pairs closed contacts that energised solenoids and motors. In software, the SQO instruction copies the bit pattern of the current step’s row to the output addresses.

The drum’s biggest limitation was inflexibility — to change the recipe you had to physically rebuild the drum by repositioning cams. PLCs eliminated that constraint: a new recipe is just new data in the sequencer file. The principle stayed; the mechanism became code.

Where you’ve already seen sequencers

If you’ve ever owned a washing machine with a click-click-click rotary timer dial, you’ve used a mechanical drum sequencer. Old jukeboxes, traffic lights, and stage-curtain controllers all started as cam-and-drum machines. The earliest PLCs explicitly marketed themselves as “drum replacement” — proving how central this pattern was to industry. Even today, many PLC vendors still call their highest-level batch instructions “drum” instructions in honour of this lineage.

Section 12.2

Sequencer Output Instruction (SQO)

The SQO (Sequencer Output) instruction is the software equivalent of the mechanical drum. It steps through a stored data table one row at a time, and on each step copies that row’s bit pattern into a destination — typically an output word that drives the field outputs.

The five SQO parameters

ParameterExampleWhat it does
File#N7:0The sequencer data table — one row per step. Each row is a bit pattern that will be copied to the destination at that step.
MaskFFFFh or 00FFhWhich bits of the destination the SQO is allowed to change. Bits set to 1 in the mask are written; bits set to 0 are left alone (so other logic can drive those bits).
DestinationO:2The output word (or any word) where the current step’s pattern is written.
ControlR6:0The control register that holds the position pointer, length, and status bits. Same family as the FAL control register from Chapter 11.
Length4How many steps are in the sequence (rows in the file, not counting row 0).

The control register’s status bits

The control register tracks the SQO’s progress and exposes useful status:

  • R6:0/ENEnable bit: true while the SQO’s rung is true.
  • R6:0/DNDone bit: pulses true for one scan when the SQO returns to step 1 (i.e. completes one full cycle).
  • R6:0/ERError bit: set if there’s a configuration problem (bad length, bad position, etc.).
  • R6:0.LENLength: the configured length value.
  • R6:0.POSPosition: the current step number (1, 2, 3 … LEN, then back to 1).

How SQO advances

SQO advances on each false-to-true transition of its rung. A common pattern is to drive the SQO from a self-clearing timer — TON with a preset of N seconds, with T4:0/DN as the SQO’s rung condition. Each time the timer’s DN bit pulses, the SQO advances one step. After the configured length, it wraps back to step 1.

Step 0 is special

Most SLC-style PLCs reserve step 0 of the sequencer file as the “reset” step. It contains the pattern that should be applied when the sequencer is reset (typically all zeros — all outputs off). Steps 1 through LEN are the actual operating steps. After step LEN, the SQO wraps back to step 1 (not step 0) and continues cycling. Step 0 is only loaded by an explicit reset operation, not by normal advance.

Variable step times

If every step needs the same dwell time, a single TON drives the SQO directly. But real industrial recipes rarely have equal step times — wash for 30 seconds, rinse for 90 seconds, spin for 300 seconds. The standard pattern: store each step’s preset time in a parallel data file (e.g. N7:100 through N7:103 for a 4-step sequence) and have the timer read its preset from N7:[100 + R6:0.POS - 1]. The timer’s preset changes with the step, so each step has its own duration. We’ll see this pattern in Worked Example 2.

Section 12.3

Sequencer Compare Instruction (SQC)

The SQC (Sequencer Compare) instruction is SQO’s mirror image. Where SQO writes a stored pattern to an output word at each step, SQC reads a field input word and compares it to a stored pattern. If they match, the SQC’s FD (Found) bit goes true; if they don’t match, FD stays false.

SQC has the same five parameters as SQO (file, mask, source, control, length) — but the “destination” of SQO is replaced by a “source” parameter that points to the input word being compared, and the comparison result is reported through the FD bit instead of being written somewhere.

The classic SQO + SQC pairing

SQO and SQC are designed to work together. The pattern is fundamental to verified industrial sequencing:

  1. SQO writes the expected output pattern for the current step (open valve A, start pump 1, energise heater, etc.).
  2. SQC reads the actual sensor pattern for the current step (valve A actually open? pump 1 actually running? heater actually on?).
  3. SQC’s FD bit is true if the sensors confirm what SQO commanded. If the sensors disagree (a valve failed to open, a pump didn’t start), FD goes false — and your alarm logic raises the alarm and halts the sequence.

This is how every safety-rated batch process verifies itself: SQO commands, SQC verifies. We’ll see exactly this pairing in Worked Example 2.

When SQC catches what your eyes miss

Imagine a valve has a stuck-open fault — its solenoid is energised, but the disc inside is mechanically jammed in the open position. The PLC tells the valve to close at step 5 of a sequence. The output bit goes off as commanded, but the valve’s position-feedback sensor still reads “open”. Without an SQC checking that step 5’s expected sensor pattern includes “valve closed”, the sequence carries on — and product flows where it shouldn’t. With the SQC pairing, FD goes false at step 5, the alarm fires, and the operator catches the failure before it spreads. SQC turns silent mechanical failures into loud, immediate alarms.

SQC’s mask: same idea as SQO’s

The SQC’s mask works just like SQO’s: bits set to 1 in the mask are compared; bits set to 0 are ignored. Use this when you only want to verify some inputs at each step (e.g. ignore the spare digital inputs that aren’t tied to anything yet).

Section 12.4

Bit Shift Registers (BSL and BSR)

Where sequencers walk through a stored pattern row by row, shift registers walk a single bit position by position. Each time the rung is triggered (typically by an encoder pulse from a moving conveyor), every bit in the register shifts one position. A new bit enters from one end; the bit at the other end falls out.

This is exactly the model you need to track parts moving along a conveyor. Each register bit represents one physical position on the line. As the conveyor advances by one position, the register shifts by one bit — keeping the register’s internal layout perfectly synchronised with what’s actually moving on the line.

BSL — Bit Shift Left

The BSL instruction shifts every bit toward higher positions (low → high). A new bit, taken from the configured Bit Address, enters at position 0. The bit previously at the highest position (length − 1) is unloaded into the UL bit of the control register and then discarded.

BSL file: #B3:10 control: R6:0 bit address: I:1/0 length: 16

That instruction creates a 16-bit shift register starting at B3:10. Each time the rung becomes true, every bit shifts up one position and the value of I:1/0 is loaded into bit 0. The bit that was at bit 15 ends up in R6:0/UL and then drops off. Use this when parts enter at one end of the conveyor (position 0) and leave at the other end (position 15).

BSR — Bit Shift Right

The BSR instruction is the mirror — bits shift toward lower positions (high → low). The new bit enters at the highest position (length − 1), and the bit at position 0 is unloaded into UL.

BSR file: #B3:20 control: R6:1 bit address: I:1/4 length: 16

Choose BSL or BSR to match the physical direction of your conveyor. If parts move left-to-right and your register’s “input” side is at low addresses, use BSL. If parts move right-to-left, or if your “newest” data should sit at the top of the register, use BSR.

BIT SHIFT REGISTER ON A CONVEYOR — BSL TRACKING PARTS Each register bit represents one position on the conveyor. Defective parts carry a “1” through the register. conveyor direction OK DEF OK OK DEF OK OK OK INSPECT EJECTOR B3:10/x: 0 1 0 0 1 0 0 0 /0 /1 /2 /3 /4 /5 /6 /7

Figure 12.2 — Bit shift register tracking defects on a conveyorThe inspection station sets a “1” in B3:10/0 whenever it detects a defect. Each conveyor advance shifts the bits left. When the “1” reaches B3:10/6 (above the ejector), the ejector fires and the defective part is rejected. The register’s bit positions stay perfectly synchronised with the parts on the line.

The shift trigger — encoder pulses, photo-eyes, or timers

The shift register only updates when its rung sees a false-to-true transition. Common triggers:

  • Encoder pulse from the conveyor drive — one pulse per conveyor advance position. The register stays mechanically synchronised with the conveyor regardless of speed.
  • Photo-eye at a known position — each part passing the eye triggers one shift. Robust if part spacing is known and consistent.
  • Periodic timer — a TON’s DN bit pulses every X seconds. Suitable when the conveyor moves at a known fixed speed.

One trigger pulse, one shift

Just like ADD-with-OSR from Chapter 11, the shift register needs a clean rising-edge pulse from its trigger. If the trigger holds true for multiple scans, the BSL/BSR only fires once on the rising edge — the instructions have built-in edge detection through the control register’s EN bit. You don’t need a separate OSR. But if you’re driving the trigger from a continuous signal (like a photo-eye that stays high while a part is in front of it), the BSL will fire once when the eye first goes high, then nothing until the next part arrives.

Section 12.5

Word Shift Operations — FIFO and LIFO

Bit shift registers move single bits one position per pulse. Word shift registers move whole 16-bit values — each “slot” holds an entire word, not a bit. They come in two flavours:

  • FIFO — First-In, First-Out. The first value loaded is the first value retrieved. Like a queue at a service counter: whoever arrived first is served first. Used for print job queues, customer order processing, recipe step scheduling, anywhere fairness matters.
  • LIFO — Last-In, First-Out. The last value loaded is the first retrieved. Like a stack of plates: take from the top of the pile. Used for undo buffers, function-call return addresses in the PLC’s own scan logic, depth-first traversal, and any “go back where you came from” pattern.

FFL and FFU — the FIFO pair

FIFO needs two paired instructions:

  • FFL — FIFO Load. Loads a source value into the next empty slot at the back of the queue. Configured with the source word, the FIFO file (an array), the control register, and the length.
  • FFU — FIFO Unload. Removes the value from the front of the queue and writes it to a destination word. All remaining values shift forward by one slot.

The shared control register tracks how many values are currently in the queue. R6:n/EM (empty) is true when the queue is empty; R6:n/FU (full) is true when the queue has reached its configured length and can’t accept more values. Always check these flags before loading or unloading.

LFL and LFU — the LIFO pair

LIFO works almost identically, but the unload instruction (LFU) returns the most recently loaded value rather than the oldest:

  • LFL — LIFO Load. Pushes a source value onto the top of the stack.
  • LFU — LIFO Unload. Pops the most recent value off the top of the stack and writes it to a destination.

Same EM/FU empty/full flags as FFL/FFU. The only behavioural difference between FIFO and LIFO is which stored value the unload returns — first-loaded for FIFO, last-loaded for LIFO.

When to use each

ScenarioChooseWhy
Customer orders, print jobs, work ticketsFIFOFairness — earliest arrival served first.
Recipe steps loaded ahead of time, executed in orderFIFOSteps must execute in the order they were queued.
Undo buffer (operator pressed UNDO)LIFOUndo the most recent action first.
Function-call returns / nested subroutinesLIFOReturn to the most recent caller first — classic “call stack”.
Tool magazine — reach for the tool you put down lastLIFOMechanically simpler — pull from the top of the stack.
Sample buffer — keep last N readingsBSR/BSL (bit) or shift arrayNeither FIFO nor LIFO unloads — the buffer just rolls over.

A queue is fair, a stack is fast

If you’ve ever stood in a deli line and watched someone walk up, get served immediately, and leave while you’re still waiting — that’s a stack (LIFO) and it feels unjust. Customers want a queue (FIFO). Now picture stacking dirty dishes by the sink — you wash the top one first, the one you put down most recently. That’s a stack (LIFO) and it feels natural. The same intuition applies in PLC programming: when fairness or order matters, FIFO; when “go back where you came from” matters, LIFO. Pick the wrong one and your logic will almost work, but in the cases where it doesn’t it will be very confusing.

Worked PLC Programs

Five Programs — From Traffic Lights to Print Job Queues

The five programs build progressively through the orchestration toolkit: SQO for a basic traffic-light cycle, SQO+SQC for a verified industrial wash cycle, BSL for tracking defects on a moving conveyor, BSR for a rolling 16-second alarm history, and FFL+FFU for a fair print-job queue.

01

PLC Program · SQO basic

Traffic Light Sequencer — Four-Step Cycle Driven by a TON

SQO / TON

The problem: a four-way intersection has a north–south traffic signal and an east–west traffic signal. The cycle has four phases: NS-green/EW-red, NS-yellow/EW-red, NS-red/EW-green, NS-red/EW-yellow. Each phase lasts 8 seconds. We need a sequencer that walks through the four phases continuously, with a timer driving each step transition.

Inputs & Outputs

INPUTS

I:1/0 — System enable (latch)

OUTPUTS (driven by SQO into O:2)

O:2/0 — NS Green

O:2/1 — NS Yellow

O:2/2 — NS Red

O:2/3 — EW Green

O:2/4 — EW Yellow

O:2/5 — EW Red

Sequencer File (data table at #N7:0)

StepBit pattern (binary, bits 5..0)NSEWHex
0 (reset)000000offoff0000h
1100001GreenRed0021h
2100010YellowRed0022h
3001100RedGreen000Ch
4010100RedYellow0014h

Ladder Diagram (Two Rungs)

L1 L2 000 — 8-second timer with self-reset; T4:0/DN pulses every 8 s — Enable I:1/0 XIO done T4:0/DN TON — 8-Second Step Timer T4:0 Preset 8000 Time-Base 1ms 001 — SQO advances one step every time T4:0/DN pulses — Step trigger T4:0/DN SQO — Sequencer Output File: #N7:0 Mask: 003Fh Destination: O:2 Control: R6:0 Length: 4 Pos: ?

Rung 0 is a self-resetting 8-second timer (the XIO of T4:0/DN resets it the scan after it times out). Rung 1’s SQO advances one step every time the timer’s DN pulses. The mask 003Fh (binary 111111) lets the SQO drive bits 0 through 5 of O:2 — exactly the six light outputs.

How it works, step by step

  1. System enable goes true. Rung 0’s timer starts running. R6:0 starts at position 1.
  2. SQO immediately writes step 1’s pattern (0021h) to O:2 — bits 0 (NS Green) and 5 (EW Red) go on. The intersection has NS-green/EW-red, exactly as designed.
  3. 8 seconds pass. T4:0/DN pulses true for one scan. The XIO of T4:0/DN on rung 0 opens, dropping the timer’s enable; the next scan T4:0/DN goes false again, the XIO closes, and the timer restarts. Meanwhile rung 1’s SQO sees a false-to-true transition on its rung condition, advances to position 2, and writes step 2’s pattern (0022h) — NS-yellow/EW-red.
  4. Another 8 seconds. Step 3: NS-red/EW-green.
  5. Another 8 seconds. Step 4: NS-red/EW-yellow.
  6. Another 8 seconds. R6:0/DN pulses true (one full cycle complete). The position pointer wraps back to 1, and the cycle starts over.
What we learned: SQO + a self-resetting TON is the canonical “step through a sequence at a fixed rate” pattern — exactly what mechanical drum sequencers did, but with the recipe stored as data instead of as physical cams. The mask (003Fh) limits the SQO to writing only the bits we care about, leaving the rest of O:2 free for other logic to control. R6:0/DN gives you a clean “cycle complete” pulse that you can use to count cycles, log to history, or trigger end-of-cycle actions.
02

PLC Program · SQO + SQC pair

Industrial Parts Washer — Sequencer with Sensor Verification

SQO / SQC

The problem: a parts-washing cabinet has four steps: pre-rinse, wash, post-rinse, dry. Each step opens different valves and runs different motors, and each step has a different duration (10 s / 60 s / 15 s / 30 s). Crucially, every step has a set of sensors that should report particular states — drain valve closed, fill valve open, cabinet door interlock made, etc. If the actual sensor states don’t match the expected pattern at any step, the cycle must halt and an alarm must fire. This is a textbook SQO + SQC verified-sequencer application.

Inputs & Outputs

INPUTS (read into I:1)

I:1/0 — START button

I:1/1 — Door closed limit switch

I:1/2 — Drain valve closed feedback

I:1/3 — Fill valve open feedback

I:1/4 — Pump running feedback

I:1/5 — Heater on feedback

I:1/6 — Dryer fan running feedback

OUTPUTS (driven by SQO into O:2)

O:2/0 — Fill valve solenoid

O:2/1 — Drain valve solenoid

O:2/2 — Wash pump motor

O:2/3 — Heater contactor

O:2/4 — Dryer fan motor

O:2/7 — ALARM lamp (alarm via SQC)

Two parallel sequencer files — one for outputs, one for expected sensors

StepPhaseDuration
(N7:100…)
SQO output
(N7:50…)
SQC expected
(N7:60…)
1Pre-rinse10 s0003h fill+drain007Eh door+drain+fill
2Wash60 s000Ch pump+heater0076h door+pump+heater
3Post-rinse15 s0003h fill+drain007Eh door+drain+fill
4Dry30 s0010h dryer fan0042h door+fan

Ladder Diagram (Three Rungs)

L1 L2 000 — Step timer reads its preset from N7:[100 + R6:0.POS – 1] — XIO done T4:0/DN TON — Variable-Preset Step Timer T4:0 Preset N7:[100+R6:0.POS-1] Time-Base 1ms 001 Step trigger T4:0/DN SQO — Drive Outputs File: #N7:50 Mask: 001Fh Dest: O:2 Control: R6:0 Length: 4 002 — SQC compares I:1 to expected pattern; if mismatch, R6:1/FD = 0 — alarm fires — SQC — Verify Inputs File: #N7:60 Mask: 007Fh Source: I:1 Control: R6:1 Length: 4 XIO FD R6:1/FD O:2/7 ALARM

Three rungs: variable-preset timer (rung 0), SQO drives the output pattern (rung 1), SQC verifies the input pattern and the XIO of FD energises the alarm if there’s a mismatch (rung 2). Both sequencers run in parallel from the same step pointer because they share R6:0.POS via the timer’s preset indirection.

Why two separate control registers (R6:0 and R6:1)?

SQO and SQC don’t share their position pointer automatically — each has its own control register. To keep them in sync, you can either (a) drive both from the same trigger so they advance together (T4:0/DN here advances both), or (b) explicitly copy R6:0.POS → R6:1.POS with a MOV every scan. The first method is cleaner; both are common in practice.

What we learned: the SQO + SQC pairing is the verified-sequencer pattern — SQO commands, SQC verifies, alarm raised on mismatch. Variable step durations come from indirect addressing on the timer’s preset (N7:[100 + R6:0.POS - 1]), so each step reads its own duration from a parallel data file. This pattern scales: a 12-step batch process uses the same three rungs, just with longer files and Length=12. The pattern’s biggest pedagogical lesson is that sequencing without verification is dangerous — output bits can go on without the field actually responding, and SQC catches exactly that class of failure.
03

PLC Program · BSL bit shift

Bottle Defect Tracker — Inspection-to-Reject Conveyor with BSL

BSL

The problem: a bottling line has eight conveyor positions between an inspection station (position 0) and a reject ejector (position 6). When the inspection station sees a defective bottle, that bottle’s position must be tracked through the conveyor so that, six positions later, the ejector kicks the right bottle off the line. The conveyor has an encoder pulse that fires once per advance position. BSL with length 8 makes the bookkeeping trivial: each encoder pulse shifts the register one position, and a “defect detected” sets a 1 into bit 0; six positions later, that 1 reaches bit 6 — and that bit drives the ejector.

Inputs & Outputs

INPUTS

I:1/0 — Inspection station defect-detected output (vision system)

I:1/1 — Conveyor encoder pulse (one rising edge per advance position)

OUTPUTS

B3:10/0..7 — 8-bit shift register (positions 0 to 7)

O:2/0 — Reject ejector solenoid

R6:0 — BSL control register

Ladder Diagram (Two Rungs)

L1 L2 000 — Encoder pulse triggers a shift; defect input loads into bit 0 — Encoder I:1/1 BSL — Bit Shift Left File: #B3:10 Control: R6:0 Bit Address: I:1/0 (defect detect) Length: 8 001 Bit at ejector B3:10/6 O:2/0 EJECT

Two rungs total. Rung 0’s BSL shifts the register one position on each encoder pulse, sampling I:1/0 (the defect signal) into bit 0. Rung 1 simply outputs whatever’s currently in B3:10/6 — when the defect bit reaches that position, the ejector fires.

A walk-through over 8 encoder pulses

PulseI:1/0 (defect?)Register B3:10 (bit 7..0)O:2/0 (eject)
start0000 0000off
1defect0000 0001off
2ok0000 0010off
3ok0000 0100off
4ok0000 1000off
5ok0001 0000off
6ok0010 0000off
7ok0100 0000ON ←
8ok1000 0000off

Notice the timing: at pulse 7 the defect bit reaches bit 6 — exactly the position above the ejector — and O:2/0 lights for one shift cycle. The defective bottle gets kicked off the line at the right moment, six conveyor positions after it was inspected. At pulse 8 the bit shifts again to bit 7 (off the inspection-to-reject path) and the ejector turns off.

What we learned: the BSL register’s position-by-position model matches a conveyor’s physical layout one-for-one. Use the encoder pulse (or photo-eye, or fixed-period timer) as the shift trigger so the register stays mechanically synchronised with the line. The bit at the inspection position becomes the input; the bit at the reject position becomes the ejector command. BSR is the same logic in the opposite direction — use it if your conveyor moves right-to-left or if you want the “newest” data to sit at the top of the register. The pattern generalises to any tracking application where you need to remember an event for N positions of motion: paint dryers, oven cure times, label applicators, anywhere “do something later, after a known delay measured in positions, not time”.
04

PLC Program · BSR bit shift right

Rolling Alarm History — Last 16 Seconds in a 16-Bit Register

BSR

The problem: a vibration alarm on a critical pump (I:1/0) needs to be logged with the last 16 seconds of history visible to operators on the HMI as a 16-bit “history bar”. Each second, the alarm’s current state is sampled and pushed into the top of a 16-bit register; one second later that bit is one position lower, and 16 seconds later it falls off the bottom and is forgotten. This is exactly what BSR is built for: new data enters at the high bit and ages downward toward the low bit.

Inputs & Outputs

INPUTS

I:1/0 — Vibration alarm (1 = alarm active)

OUTPUTS

B3:20/0..15 — 16-bit alarm history (bit 15 = newest, bit 0 = oldest)

T4:1 — 1-second sample timer

R6:1 — BSR control register

Ladder Diagram (Two Rungs)

L1 L2 000 — Self-resetting 1-second sample timer; T4:1/DN pulses every second — XIO done T4:1/DN TON — 1-Second Sample Tick T4:1 Preset 1000 Time-Base 1ms 001 Sample tick T4:1/DN BSR — Bit Shift Right File: #B3:20 Control: R6:1 Bit Address: I:1/0 (alarm state) Length: 16

Two rungs. Rung 0 generates a 1-second tick. Rung 1’s BSR samples the alarm state at each tick and pushes it into bit 15 (the high bit); existing bits all shift one position right, and the bit at position 0 (oldest, 16 seconds old) falls off into R6:1/UL and is discarded.

A walk-through over 18 sample ticks

Suppose the vibration alarm trips for a 3-second burst starting at tick 5, then again briefly at tick 12:

Tick (s)I:1/0B3:20 — bits 15..0 (newest left, oldest right)
0–400000 0000 0000 0000
511000 0000 0000 0000
611100 0000 0000 0000
711110 0000 0000 0000
800111 0000 0000 0000
9–1100000 1110 0000 0000 at tick 11
1211000 0111 0000 0000
1300100 00111 0000 000 (oldest 0 falls off)
1700000 0100 00111 0000

The HMI displays B3:20 as a 16-cell history bar where lit cells indicate “alarm was active at that second”. Operators can immediately see when the alarm fired and for how long — much more useful than just the current alarm state.

BSR vs. BSL — same physics, different geography

You could solve this exact problem with BSL too — just put “newest” at bit 0 instead of bit 15. The choice is purely about which end of the register feels like “the top” to your operators reading the HMI. BSR with newest-at-MSB reads naturally on most HMIs because the high bit is conventionally rendered on the left, so a left-to-right “newer to older” history bar matches how we read English. BSL with newest-at-LSB works fine if your HMI renders bits low-to-high on the left. There’s no “right” answer; pick the one that matches your visual conventions and stay consistent across the project.

What we learned: BSR is the natural fit for a “newest at top, oldest at bottom” rolling history. Pair it with a self-resetting timer at your sample period (1 s here, but could be 100 ms for fast events or 1 minute for slow ones) and you get a free, deterministic, fixed-size circular buffer with no manual index management. The same pattern applies to logging digital inputs, latch states, motor running indications, sensor presence — anything binary you want to remember for the last N samples. For multi-bit values like analog readings, you’d use a different mechanism (the COP/MOV pattern from Chapter 10 with a circular index) — BSR/BSL only handle single-bit history.
05

PLC Program · FFL + FFU FIFO

Print Job Queue — Fair First-In First-Out Scheduling

FFL / FFU

The problem: a network printer in a packaging cell receives print job IDs over a serial link as numeric job tokens (e.g. 47, 52, 53, 60). Multiple operators can queue jobs faster than the printer can produce them, so the PLC needs a queue that holds up to 16 jobs and feeds them to the printer one at a time, in arrival order. Each new job arrives in N7:200 with the SUBMIT bit (I:1/0) pulsed; each completed print pulses the printer-ready bit (I:1/1) and the next queued job is delivered to N7:201. Classic FFL / FFU queue.

Inputs & Outputs

INPUTS

I:1/0 — SUBMIT job (one-shot rising edge)

I:1/1 — PRINTER READY (rising edge = ready for next)

N7:200 — Incoming job ID (loaded by ladder before SUBMIT)

OUTPUTS

N7:300..N7:315 — FIFO queue array (16 slots)

N7:201 — Active job ID (output to printer)

R6:2 — FFL/FFU shared control register

O:2/0 — “QUEUE FULL” lamp

O:2/1 — “QUEUE EMPTY” lamp

Ladder Diagram (Four Rungs)

L1 L2 000 — SUBMIT loads N7:200 into the back of the queue (only if not full) — SUBMIT I:1/0 XIO full R6:2/FU FFL — Load to Back of Queue Source: N7:200 FIFO: #N7:300 Ctrl: R6:2 Len: 16 001 — PRINTER READY pops next job from front of queue into N7:201 (only if not empty) — PRT READY I:1/1 XIO empty R6:2/EM FFU — Unload from Front FIFO: #N7:300 Dest: N7:201 Ctrl: R6:2 002 Full R6:2/FU O:2/0 FULL 003 Empty R6:2/EM O:2/1 EMPTY

Four rungs: FFL guarded by /FU on rung 0, FFU guarded by /EM on rung 1, plus /FU and /EM directly driving status lamps. The control register R6:2 is shared between FFL and FFU — that’s the key requirement of the FIFO pair.

A walk-through over a busy queue period

EventQueue contents (front → back)EMFUN7:201 (active job)
start10(stale)
SUBMIT job 47[47]00(stale)
SUBMIT job 52[47, 52]00(stale)
SUBMIT job 53[47, 52, 53]00(stale)
PRINTER READY[52, 53]0047
SUBMIT job 60[52, 53, 60]0047
PRINTER READY[53, 60]0052
PRINTER READY[60]0053
PRINTER READY1060

Notice the order: jobs are printed 47 → 52 → 53 → 60, exactly the order they were submitted. That’s the FIFO guarantee. With LFL/LFU instead, jobs would print 60 → 53 → 52 → 47 — most recent first, original first job last (and grumpy). The FIFO contract is what makes the queue feel fair.

Always guard FFL with /FU and FFU with /EM

Edge cases that bite real production code:

  • FFL on a full queue silently drops the new value. The XIO of /FU on the FFL rung prevents that — the SUBMIT goes nowhere if the queue is full, and the operator should see the FULL lamp light to know why.
  • FFU on an empty queue produces undefined behaviour on most platforms — the destination might keep its previous value (worst case: a stale job ID gets re-printed) or get garbage. The XIO of /EM on the FFU rung prevents the unload entirely when the queue is empty.
  • Always pair /FU and /EM checks with operator-visible lamps so the human in the loop knows when the queue is at a limit.
What we learned: the FFL/FFU pair gives you a fair queue with built-in size tracking — no manual index management, no bounds checking. R6:2/EM tells you the queue is empty (don’t unload); R6:2/FU tells you it’s full (don’t load). Always guard FFL with the not-full check and FFU with the not-empty check. Swap FFL/FFU for LFL/LFU and the same four rungs become a stack instead of a queue — useful for undo buffers, “go back” logic, and any pattern where the most recent input should be served first. The whole family (FFL, FFU, LFL, LFU) shares the same control register and status bit conventions, so once you’ve learned one, you’ve learned all four.

Common Student Mistakes

Things to watch out for in this chapter:

  • Forgetting that SQO advances on rung false-to-true transitions, not on every scan. If your trigger holds true for many scans, the SQO still only advances once. Either gate it with a self-resetting timer (as in Programs 1 and 2) or accept the once-per-rising-edge behaviour.
  • SQO writing bits outside the mask. Bits set to 0 in the mask are untouched by SQO — but the corresponding bits in your sequencer file are also ignored. Setting a bit in the file but masking it out is a silent way to wonder why an output never turns on.
  • Confusing step 0 and step 1. Step 0 is the reset row, loaded only by an explicit reset. The cycle starts at step 1 and wraps from step LEN back to step 1, never touching step 0 in normal operation.
  • Running SQO and SQC out of step. They each have their own control register and don’t auto-sync. Either drive both from the same trigger, or copy R6:0.POS → R6:1.POS with a MOV every scan.
  • FFL on a full queue silently drops the new value. Always guard FFL with an XIO of R6:n/FU, and let the FULL lamp tell the operator why their submit didn’t take.
  • FFU on an empty queue produces undefined behaviour. The destination might hold a stale value (worst case: a previously-printed job re-prints). Always guard FFU with an XIO of R6:n/EM.
  • Encoder bounce on the BSL/BSR shift trigger. A noisy encoder pulse can register as multiple rising edges per actual position, causing extra shifts and misaligning the register from the conveyor. Either filter the encoder signal at the input, or feed it through a debounce timer before the BSL/BSR rung.
  • Wrong shift direction for the conveyor’s physical direction. If parts move left-to-right and you use BSR (which shifts toward the low bit), your “1” will move backwards through the register relative to the part it represents. Match the instruction to the geography.
  • Choosing FIFO when LIFO is needed (or vice versa). Customer orders, work tickets, and recipe steps want FIFO (fairness). Undo buffers, function-call returns, and “most recent first” logic want LIFO. The wrong choice almost works — except in the cases where it really matters.
  • Sequencer file dimensioning errors. The file’s row count must equal the SQO’s Length (plus row 0). Length=4 needs 5 rows (0 through 4). Length=10 needs 11 rows. An off-by-one error here gives you a “phantom step” with whatever uninitialised data lives at that address.

Quick Recap

The ten things to take away from Chapter 12:

  • Software sequencers descend directly from mechanical drum-and-cam machines — same idea, recipe stored as data instead of as physical bumps on a drum.
  • SQO walks through a sequencer file and writes each step’s bit pattern to a destination output, with a mask controlling which bits it’s allowed to touch.
  • SQC is SQO’s mirror: reads an input word and compares it to an expected pattern, raising the FD bit when they match.
  • The SQO + SQC pair is the verified-sequencer pattern: SQO commands, SQC verifies, alarm raised on mismatch.
  • Variable step durations come from indirect addressing on the timer’s preset, reading from a parallel data file using R6:0.POS as the index.
  • BSL shifts bits from low position toward high; the bit at position 0 comes from the configured Bit Address; the high bit is unloaded into UL.
  • BSR is the mirror: shifts from high toward low; new bits enter at the high position; the low bit is unloaded.
  • BSL/BSR shift triggers are typically encoder pulses, photo-eyes, or fixed-period timers — whichever keeps the register synchronised with the physical event you’re tracking.
  • FFL / FFU are the FIFO pair (queues, fairness); LFL / LFU are the LIFO pair (stacks, “most recent first”).
  • Always guard FFL with an XIO of /FU and FFU with an XIO of /EM. Pair both checks with operator-visible status lamps so the human in the loop knows when the queue is at a limit.

Review & Self-Assessment

Chapter 12 Review Questions

Try answering each question on your own first. Tap to reveal the answer when you’re done.

Q1What three things did a mechanical drum sequencer do, and how does each map to a software SQO instruction?+
A mechanical drum sequencer (1) stored a sequence pattern in the arrangement of cams on the drum — software SQO stores the same pattern as rows in a sequencer file. (2) Stepped through the pattern by rotating the drum at a fixed rate — software SQO advances its position pointer on each rising edge of its rung condition. (3) Drove physical outputs through cam-and-roller switches that closed contacts — software SQO copies the current step’s bit pattern to a destination output word. The drum’s biggest limitation was inflexibility (rebuilding the recipe meant repositioning physical cams); SQO eliminated that constraint by storing the recipe as data.
Q2Name the five SQO parameters and what each one does.+
File — the sequencer data table (e.g. #N7:0), one row per step. Mask — which destination bits the SQO is allowed to change (1 = write, 0 = leave alone). Destination — the output word the current step’s pattern is written to (typically O:2). Control — the R6:n control register that holds the position pointer, length, and status bits. Length — how many active steps in the sequence (rows 1 through LEN; row 0 is the reset row).
Q3What does the SQO mask 003Fh mean, and why use it instead of FFFFh?+
003Fh in binary is 0000 0000 0011 1111 — only bits 0 through 5 are set to 1. The SQO will write to those six bits of the destination and leave bits 6 through 15 untouched. With FFFFh (all bits set) the SQO would overwrite the entire 16-bit destination, including bits driven by other rungs of your program — corrupting their values every step. The mask isolates the SQO’s authority to just the bits it’s responsible for, so other logic can drive other bits of the same destination word safely.
Q4In the SQO + SQC verified-sequencer pattern, what catches a stuck-open valve fault?+
The SQC. The SQO sends the “close valve” command at step 5, the output bit goes off, but a mechanically jammed valve disc stays open and the position-feedback sensor still reads “open”. The SQC compares the actual sensor word to step 5’s expected pattern (which calls for “valve closed”), the patterns don’t match, the FD bit goes false, and the alarm rung lights — halting the sequence and alerting the operator. Without the SQC pairing, the failed valve would silently let product flow where it shouldn’t. SQC turns silent mechanical failures into immediate alarms.
Q5How do you implement variable step durations in an SQO-based sequencer where each step has a different time?+
Store each step’s preset time in a parallel data file (e.g. N7:100, N7:101, … one word per step), and configure the step timer’s preset to read indirectly from N7:[100 + R6:0.POS - 1]. The timer’s preset changes automatically as the SQO advances — step 1 reads N7:100, step 2 reads N7:101, and so on. This is exactly the pattern used in the parts-washer worked example to give pre-rinse 10 s, wash 60 s, post-rinse 15 s, and dry 30 s within a single shared sequencer.
Q6In a BSL register of length 16, where does a new bit enter, and where does the unloaded bit go?+
A new bit, taken from the value of the configured Bit Address, enters at position 0 (the lowest bit). All other bits shift up by one position. The bit that was at position 15 (the highest) is unloaded into R6:n/UL of the control register and then discarded. BSR is the mirror: new bits enter at the highest position, others shift down, and the bit at position 0 is unloaded.
Q7How does an encoder pulse keep a BSL register synchronised with parts moving on a conveyor?+
An encoder mounted to the conveyor drive emits one pulse per position the belt advances. By using that pulse as the BSL’s rung condition, you ensure the register shifts exactly when the conveyor advances by one part position — never faster, never slower, regardless of the belt’s speed. This couples the register’s logical state to the conveyor’s physical state perfectly. If a defect bit is loaded into position 0 when the inspection station detects a defective part, then six pulses later (six positions of conveyor travel later) that bit is at position 6 — exactly when the part is above the ejector. The trigger is the source of truth that keeps software and hardware aligned.
Q8When would you choose BSR over BSL, given that they’re functionally mirror images?+
Two main cases. (1) The conveyor’s physical direction — if parts move right-to-left through the position range that maps to your register, BSR keeps the bit moving in the same logical direction as the part. (2) The HMI display convention — if you want “newest at the top of the display, oldest at the bottom”, and your HMI renders the high bit on the left, BSR (which loads new data into the high bit) reads naturally as a left-to-right history bar. Pick whichever keeps the bit’s motion through the register intuitive for the people reading the code and watching the HMI. They’re functionally identical otherwise.
Q9What’s the difference between FIFO and LIFO, and give one example of where each is the right choice.+
FIFO (First-In, First-Out) serves stored items in arrival order — the value loaded earliest is unloaded first. Like a fair queue at a counter. Use FIFO for: customer orders, print jobs, work tickets, recipe steps loaded ahead of time, anywhere fairness or chronological order matters. LIFO (Last-In, First-Out) serves the most recently loaded item first. Like a stack of plates. Use LIFO for: undo buffers, function-call returns / nested subroutine handling, depth-first traversal, and tool magazines where you reach for the tool you put down most recently. The same four ladder rungs work for either — just swap FFL/FFU for LFL/LFU.
Q10Why must FFL be guarded by an XIO of /FU, and FFU by an XIO of /EM?+
FFL on a full queue (when /FU is true) silently drops the new value — the SUBMIT input pulses, but no slot is available, and nothing is recorded. The operator gets no feedback unless you’ve also made the FULL lamp visible. FFU on an empty queue (when /EM is true) produces undefined behaviour — the destination might keep its previous value (potentially re-printing a stale job) or get garbage. Both edge cases are silent failures that produce wrong results without raising any alarm. The XIO guards are simple, cheap, and turn silent failures into “the rung was just false” — combined with FULL/EMPTY status lamps, they keep both the queue’s behaviour and its limits transparent to the operator.
Q11A 5-step batch process needs to verify that, at each step, two specific door interlocks are closed. The other 14 bits of the input word are unused. How do you configure the SQC’s mask, and what’s the alternative?+
Set the SQC mask to a value where exactly the two interlock bits are 1 and all others are 0. If the interlocks are wired to I:1/0 and I:1/1, the mask is 0003h (binary 0000 0000 0000 0011). The SQC will compare only those two bits against the expected pattern and ignore the other 14. The alternative would be to leave the mask at FFFFh and pre-load the remaining 14 expected-pattern bits with whatever the field sends — but that requires you to know and store those values for every step (and they can’t change). The mask approach is cleaner and survives any future wiring changes to the unused bits.
Q12A bidirectional sortation conveyor sends parts left in one mode and right in the other, controlled by a “direction” output. How would you structure the shift register to track parts in both directions?+
Use both BSL and BSR sharing the same register file but with two control registers. Gate the BSL with an XIC of “direction = right” and the BSR with an XIC of “direction = left”, and feed both with the same encoder pulse. Only one of the two will execute on each pulse, based on which direction is currently active. This way the register’s contents always shift in the direction matching the physical motion. Be careful with the bit-address (input) sources — when shifting left, parts enter at position 0 (the right end); when shifting right, parts enter at position N-1 (the left end). Make sure the inspection sensor at each end feeds the appropriate input. This is an advanced pattern but illustrates that BSL and BSR can coexist in the same application when the physical hardware demands it.

Need help architecting a verified batch sequencer or a real-time part-tracking system?

Get one-on-one tutoring or design-review help from Dr Ahsan Rahman — Head of Electrical Engineering, with two decades of experience designing sequencer, queue, and conveyor-tracking logic for industrial automation.

Request Consultation →