10
Data Manipulation Instructions
Up until now, almost everything the PLC has done is at the level of single bits — coils, contacts, timers, counters. Real industrial work also needs to handle numbers: setpoints, recipe parameters, analog readings, scaled measurements, lookup-tables of configuration values. This chapter introduces the instructions that move numbers from one place to another (MOV, MVM, COP, FLL), compare them against limits (EQU, NEQ, LES, GRT, LIM), connect them to the outside world (BCD thumbwheels, 7-segment displays), and feed them into a closed-loop control calculation — your first taste of how PLCs run continuous processes rather than just discrete machinery.
What you’ll be able to do after this chapter
Your goals for this chapter:
- Explain how PLC data files are organised — integer (N), floating-point (F), binary (B) — and why the file type matters.
- Use MOV to transfer a single value, MVM to transfer selected bits with a mask, COP to transfer an array of words, and FLL to fill a region with a constant.
- Apply the comparator family — EQU, NEQ, LES, GRT, LEQ, GEQ, LIM — to drive outputs based on numerical conditions.
- Build a recipe-selection program that loads different parameter sets into the running tags based on operator selection.
- Read a BCD thumbwheel switch using FRD and write to a BCD 7-segment display using TOD.
- Distinguish open-loop from closed-loop control and identify the components of a feedback control loop.
- Implement a simple proportional controller using SUB and MUL — the core of every PID loop.
- Recognise where the dedicated PID instruction would replace your hand-built calculation.
Key Concepts & Terms
Data Manipulation Concepts
So far in this book we’ve worked almost entirely with bits — single 1-or-0 values that represent contact states, coil states, sensor states, lamp states. Bit-level logic gets you a long way; you can build entire conveyor lines, batch fills, and start-stop circuits without ever moving anything bigger than a single bit.
But the moment you need to store a setpoint, read an analog sensor, look up a recipe, or do arithmetic, single bits are no longer enough. You need numbers — values like 120.5 °C, or recipe number 7, or oven setpoint 360 seconds. Numbers in a PLC live in data files, and the file type tells the PLC how to interpret the bits inside.
Data file types
Every modern PLC organises its memory into files, each holding values of one specific type:
| File | Contains | Range / Format | Example address |
|---|---|---|---|
I · Input file | Live input image | Bits and words from input cards | I:1/3 (bit), I:3.0 (analog word) |
O · Output file | Live output image | Bits and words to output cards | O:2/0, O:4.0 |
B3 · Binary file | Internal bit storage | 16-bit words, accessed bit-by-bit | B3:0/0, B3:5 (whole word) |
T4 · Timer file | Timer instances | Each instance: PRE, ACC, EN/TT/DN bits | T4:0.ACC, T4:0/DN |
C5 · Counter file | Counter instances | Each instance: PRE, ACC, CU/CD/DN/OV/UN bits | C5:0.ACC, C5:0/DN |
N7 · Integer file | Signed 16-bit integers | −32 768 to +32 767 | N7:0, N7:25 |
F8 · Float file | 32-bit IEEE-754 floating-point | ±3.4 × 10³⁸ with ~7 digits precision | F8:0, F8:14 |
The file letter (N, F, B, T, C, I, O) tells the PLC how to interpret the bits. Mixing them up is a common beginner error: try to MOV from F8:0 (float) into N7:0 (integer) and you’ll truncate the decimal portion silently. Try to MOV from N7:0 into F8:0 and the integer becomes a float — usually fine, but you should know it’s happening.
Figure 10.1 — Data file interpretationThe same memory holds the same bits, but the file type chosen by the programmer determines whether those bits represent 16 separate flags, a signed integer, or a floating-point number. Picking the wrong file type silently misinterprets the data.
Once you have data in the right file, you have to do something with it. The two basic actions are moving data (copy a value from A to B) and comparing data (test whether one value is equal to / greater than / less than another). The next two sections cover each in turn.
Data Transfer (MOV) Operations
Data transfer instructions copy a value from a source register to a destination register. The source isn’t changed; only the destination receives the new value. Four instructions cover almost every transfer need:
MOV — single-word move
The workhorse. Copies one value from source to destination on each scan that the rung is true.
MOV source: N7:5 destination: N7:20
That rung copies whatever’s in N7:5 into N7:20 every scan the rung is true. If you want to do the move only once (when a button is pressed, for example), put a one-shot in the rung — otherwise the destination is overwritten every scan.
MVM — masked move
Copies selected bits from source to destination, leaving the other bits in the destination unchanged. The “mask” is a 16-bit pattern: where the mask is 1, the bit is copied; where the mask is 0, the destination bit is preserved.
MVM source: N7:5 mask: 0000 0000 1111 0000 dest: N7:20
That rung copies bits 4–7 from N7:5 into bits 4–7 of N7:20. Bits 0–3 and 8–15 of N7:20 are untouched. Useful when several different program sections each “own” different bits of a shared status word.
COP — file copy
Copies an array of words — N elements in a row. Useful for loading a recipe (10 parameters at once) or transferring a logged set of samples.
COP source: #N7:50 destination: #N7:100 length: 10
That rung copies N7:50–N7:59 into N7:100–N7:109. The # prefix tells the PLC “this is the start of an array, not a single word”.
FLL — file fill
Writes the same value into every word of an array. Useful for clearing a buffer or initialising an array of setpoints.
FLL source: 0 destination: #N7:100 length: 10
That rung writes 0 into N7:100–N7:109 — the same as 10 consecutive MOVs of zero, but in one instruction.
Why MOV every scan is usually fine
Most MOV rungs are conditional — gated by an XIC of “system enabled” or a one-shot. But sometimes you’ll see unconditional MOVs that fire every scan. That’s also acceptable when the source value is something that genuinely does change every scan (like a live analog reading) and the destination is meant to track it. The pattern to avoid is a MOV that fires every scan when the source changes only on a button press — that’s wasted CPU and a sign you forgot the gate.
Data Compare Instructions
Comparators are input-style instructions. They sit on the left side of a rung where you’d normally put XIC contacts. Their output is true (passing power) when the comparison they describe is true; false otherwise. The rung’s coil fires according to that result.
Seven comparators handle every numeric test you’ll need:
| Instruction | Reads | Output is TRUE when… | Typical use |
|---|---|---|---|
EQU — Equal | Source A, Source B | A = B | Recipe-number dispatch, finished-state detection |
NEQ — Not Equal | Source A, Source B | A ≠ B | Mismatch alarms, change detection |
LES — Less Than | Source A, Source B | A < B | Low-level alarms, lower thresholds |
GRT — Greater Than | Source A, Source B | A > B | High-level alarms, upper thresholds |
LEQ — Less or Equal | Source A, Source B | A ≤ B | “Stop when at or below” logic |
GEQ — Greater or Equal | Source A, Source B | A ≥ B | “Trigger at or above” logic |
LIM — Limit Test | Low, Test, High | Low ≤ Test ≤ High (or High ≤ Test ≤ Low) | “Inside operating window” tests |
The LIM instruction is special
LIM tests three values at once: a low limit, the test value, and a high limit. Its output is true when the test value is between the two limits. This is enormously more compact than wiring two separate comparators (LEQ + GEQ) in series — one LIM, three sources, done.
An interesting quirk: if the engineer programs Low > High (e.g., Low = 50, High = 10), LIM treats it as an inverted test — true when the test value is OUTSIDE the [10, 50] range. This is occasionally useful but is a frequent source of confusion, so most engineers stick to writing Low < High and using NEQ-style logic when they want “outside window”.
Comparators are not edge-triggered
A comparator’s output stays true as long as the comparison is true — many scans, possibly forever. If you want a one-time response when the condition first becomes true, follow the comparator with a one-shot. Otherwise downstream counters and timers may fire repeatedly.
Comparators with floats
Floating-point equality is tricky. A value computed as 0.1 + 0.2 doesn’t exactly equal 0.3 due to IEEE-754 rounding. Avoid EQU on floats; use a LIM with a small tolerance band instead. For example: “level is at setpoint” → LIM source A: SP−0.5 test: PV source B: SP+0.5.
Data Manipulation Programs — Recipes, Lookup Tables, and File Operations
Once you have the basic move and compare instructions in your toolkit, the patterns they enable are some of the most powerful in PLC programming. Three patterns cover the majority of real-world data-manipulation work.
Recipe selection
A machine that runs multiple products needs different setpoints for each one — different cook times, different temperatures, different mix ratios. Hard-coding 25 separate cases is unmaintainable. Better: store each product’s parameters as a contiguous block in memory (a “recipe”) and use COP to load the chosen recipe into the running tags.
The structure looks like this:
- Recipe storage:
N7:50–N7:59= recipe 1,N7:60–N7:69= recipe 2, etc. - Active recipe (running):
N7:100–N7:109— the parameters the program currently uses. - Selection: an EQU comparator on the operator’s selection number triggers a COP that copies the right recipe into the active block.
Adding a new recipe is now just adding 10 more words of data — no code changes. We’ll build this out in Worked Example 1.
Lookup tables
Some calculations are easier as a table than as math. The classic case is non-linear sensor calibration: a thermocouple’s reading-vs-temperature curve isn’t a straight line, but a 50-point table with linear interpolation between points captures the curve perfectly. The PLC indexes into the table using the raw reading and reads out the calibrated temperature. The MOV-with-indexed-address pattern (e.g. MOV N7:[N7:0] N7:50) makes this one rung.
File arithmetic and statistics
For batch operations across an entire array — “compute the average of these 100 samples”, “find the maximum”, “sort this list” — the FAL (File Arithmetic Logic), AVE, STD, and SRT instructions exist. They operate on whole arrays the way MOV operates on single words. We won’t dive deep into FAL in this chapter; the key idea is to recognise that any operation you can do on a single value, you can do on a whole array with one rung if your platform supports it.
Why this matters
The difference between a junior PLC programmer and a senior one is often visible right here. A junior writes 25 separate rungs for 25 separate recipes. A senior writes one COP rung dispatched by an EQU comparator, with the recipes stored as data the production team can edit without touching the program. Same machine behaviour, dramatically different maintainability. Whenever you find yourself copying-and-pasting rungs that differ only by their constants, ask: could those constants be data instead of code?
Numerical Data I/O Interfaces
Numbers don’t only live inside the PLC — they have to get in and out. Operators set values on physical interfaces; displays show values to the team on the floor. Most modern installations use HMIs and touch-screens, but two older but still-common interfaces are worth understanding: BCD thumbwheel switches (input) and BCD 7-segment displays (output).
BCD encoding — what it is
BCD stands for Binary Coded Decimal. Each decimal digit (0–9) is encoded as 4 bits — the binary representation of that digit. So the number “37” in BCD takes 8 bits: 0011 for the 3, then 0111 for the 7. The number “1024” in BCD takes 16 bits: 0001 0000 0010 0100.
BCD is wasteful compared to plain binary (you can’t use the patterns 1010–1111 in any digit position), but it has one huge practical advantage: each decimal digit lives in its own 4-bit nibble. That means a 4-digit BCD thumbwheel switch wires directly to the PLC: 4 wires per digit, 16 wires total, each thumbwheel switch turning gives you a clean 4-bit binary representation of that digit.
FRD and TOD instructions
BCD numbers in the PLC’s memory aren’t directly usable by math instructions — math expects plain binary integers. So the PLC has two conversion instructions:
- FRD — From BCD — Converts a BCD-encoded number (read from a thumbwheel input word) into a plain binary integer. The result is stored in an N7 file ready for use in math, comparisons, and recipe lookups.
- TOD — To BCD — Converts a plain binary integer back into BCD encoding ready to drive a 7-segment display module.
Where this still matters
Most new builds use HMI screens for everything, so BCD interfaces are less common than they once were. But:
- Legacy machinery in service for 20+ years often still has thumbwheel switches and 7-segment indicators, and you’ll need to read and write them.
- Simple panel-mount interfaces for setpoints (a single thumbwheel for “batch count target”) are still widely used because they are mechanically rugged and require no software on the operator side.
- Some safety-rated interfaces still mandate physical switches over touch-screens — and those switches typically come back into the PLC as BCD.
Modern alternative: scaled analog and HMI
For most new applications, you’ll skip BCD entirely. Setpoints come from an HMI tag (already a binary integer or float in PLC memory, no conversion needed); displays go to the same HMI as live values. The chapter on numerical I/O is here partly so you can read and maintain older machines, and partly because the BCD/binary distinction shows up in unexpected places — like when interfacing to certain VFD drives or weighing scales that report values in BCD over a fieldbus.
Introduction to Closed-Loop Control
Until now, our PLC programs have been mostly discrete: a switch turns on, a motor runs; a sensor blocks, a counter increments. The PLC observes inputs and decides outputs. There’s no continuous measurement of how well the machine is performing the task.
Now imagine controlling the temperature of a chemical reactor. You can turn the heater on or off — but if you simply leave it on, the reactor overheats. If you turn it off and on by a temperature limit switch, the temperature swings up and down dramatically. To hold the temperature steady at exactly 75 °C, you need closed-loop control: continuously measure the temperature, compare it to the desired setpoint, and adjust the heater output proportionally.
Open-loop vs closed-loop
The distinction is clear once you see it:
- Open-loop control: the controller commands the actuator and hopes for the best. There’s no feedback measurement of whether the goal was achieved. Example: a timed bake — turn on the oven for 30 minutes regardless of actual oven temperature.
- Closed-loop control: the controller measures the result, computes the error, and adjusts the actuator continuously to drive the error toward zero. Example: a thermostatically controlled oven — measure temperature, compare to setpoint, modulate heater power based on the difference.
Figure 10.2 — The closed-loop control structureSetpoint minus measured PV gives the error. The controller acts on the error to produce a control variable (CV). The actuator drives the process. The sensor reads the result and feeds it back. The loop runs continuously.
Components of a feedback loop
- Setpoint (SP) — the desired value, set by the operator. “I want the temperature to be 75 °C.”
- Process variable (PV) — the actual measured value, read from a sensor. “The temperature right now is 71.4 °C.”
- Error (E) — the difference:
E = SP − PV. “Error is +3.6 °C; we’re below setpoint.” - Control variable (CV) — what the controller commands the actuator to do. “Open the heater valve to 60 %.”
- Process — the physical thing being controlled (the reactor, the tank, the temperature, the flow rate).
The simplest controller — proportional only
A proportional (P) controller sets the actuator output proportional to the error: bigger error, bigger correction. The math is one line:
CV = Kp × (SP − PV)
Kp is the proportional gain, a number you tune. Larger gains make the controller respond faster but risk oscillation; smaller gains are stable but slow. A pure P-controller will leave a small steady-state offset (a non-zero error at equilibrium), which is why most real systems add an integral (I) term to drive that offset to zero, plus a derivative (D) term to anticipate rate of change. The combination is the famous PID controller.
Modern PLCs include a dedicated PID instruction that wraps all three terms, gain scheduling, output limiting, anti-windup protection, and tuning interfaces in one block. We’ll use the PID instruction in detail in later chapters; for this chapter we’ll build a P-only controller by hand using SUB and MUL — both to demystify what the PID block is doing under the hood and to give you a tool you can use today on simple loops.
Worked PLC Programs
Five Programs — From Recipe Selection to a Proportional Controller
The five programs build progressively: single-word MOVs dispatched by EQU, multi-bound checks with LIM, masked transfers with MVM, file-level COP for recipe blocks, and finally a complete proportional control loop using SUB and MUL — the foundation of every PID controller you’ll ever tune.
The problem: a packaging machine runs five different products. Each product has its own oven temperature setpoint. The operator selects the product number (1–5) on a thumbwheel, and the program loads the correct setpoint into the running oven temperature register. Today we’ll handle just one parameter (oven setpoint) to keep the example focused; in Worked Example 4 we’ll extend this to a 10-parameter recipe.
Inputs & Outputs
INPUTS
N7:0 — Product selector (1–5, from thumbwheel via FRD)
OUTPUTS
N7:50–N7:54 — Stored setpoints for products 1–5 (constants)
N7:100 — Active oven setpoint (used by the rest of the program)
Recipe Storage Map
| Address | Product | Oven Setpoint (°C) |
|---|---|---|
N7:50 | Product 1 — Standard | 180 |
N7:51 | Product 2 — Premium | 205 |
N7:52 | Product 3 — Light | 165 |
N7:53 | Product 4 — Crispy | 225 |
N7:54 | Product 5 — Frozen | 240 |
Ladder Diagram (Five Dispatch Rungs)
Five rungs, each with one EQU comparator and one MOV. Whichever EQU’s condition is true, that MOV fires and loads its recipe value into the active setpoint.
How it works
- Operator dials product 3 on the thumbwheel. The thumbwheel reads 3 through the FRD, landing in
N7:0. - Every scan, all five EQU comparators run. Only the rung 2 EQU (test “
N7:0 = 3“) is true. The other four are false. - Rung 2’s MOV fires. The value at
N7:50+2 = N7:52(165 °C) is copied intoN7:100. - The rest of the program reads
N7:100as the active oven setpoint and drives the heater logic accordingly. - Operator switches to product 5. Now only rung 4’s EQU is true;
N7:54(240 °C) gets MOVed intoN7:100. The change is instant — no special “recipe load” button needed.
The problem: a chemical reactor’s temperature must stay between 60 °C (low) and 80 °C (high). When it’s inside that window, a “PROCESS HEALTHY” lamp lights and the recipe sequencer is allowed to advance. Outside the window, the lamp drops and an “OUT OF RANGE” alarm fires. Two limits, one rung — perfect for LIM.
Inputs & Outputs
INPUT
F8:0 — Reactor temperature, °C (live, scaled from RTD)
OUTPUTS
O:2/0 — “PROCESS HEALTHY” green lamp
O:2/1 — “OUT OF RANGE” amber alarm lamp
Ladder Diagram (Two Rungs)
One LIM rung handles the in-range test. The alarm rung uses an XIO of the healthy lamp — a clean inverse, no second LIM needed.
How it works
- Temperature inside the window (62 °C, say). 60 ≤ 62 ≤ 80, so LIM is true. Rung 0’s output passes — the green “PROCESS HEALTHY” lamp lights.
- Rung 1’s XIO of the healthy lamp. Healthy is on, so XIO is false. The amber “OUT OF RANGE” lamp stays off.
- Temperature drops to 55 °C. 55 is less than the low limit (60), so LIM is false. The healthy lamp drops.
- Rung 1’s XIO is now true (healthy is off). The amber alarm lamp lights.
- Operator restores temperature to 70 °C. 60 ≤ 70 ≤ 80 → LIM true → healthy lamp returns → alarm drops.
Why one LIM beats two GEQ/LEQ
The alternative would be: GEQ F8:0 60 — branch — LEQ F8:0 80 in series. That works, but LIM is more compact (one block instead of two), reads more naturally (“is the value between 60 and 80?”), and the source-A and source-B values can be tags rather than constants — making it trivial to convert hard-coded limits into HMI-editable setpoints later.
SP − 0.5 ≤ PV ≤ SP + 0.5 via LIM is the right way to detect “at setpoint” with tolerance.
The problem: a packaging line collects fault bits from across the program into one 16-bit fault status word, B3:10. Bits 0–7 are process faults (high temperature, low pressure, jam, etc.) that the HMI should display. Bits 8–15 are diagnostic flags used internally by the program but not relevant to the operator. We need to copy only bits 0–7 of B3:10 to N7:200 (the HMI fault display register), without disturbing bits 8–15 of N7:200 — which the HMI uses for other purposes.
Inputs & Outputs
SOURCE
B3:10 — Aggregated fault word (bits 0–7 = process, 8–15 = diagnostic)
Mask: 0000 0000 1111 1111 = decimal 255
DESTINATION
N7:200 — HMI display register (bits 0–7 receive process faults; bits 8–15 unchanged)
Ladder Diagram (One Rung)
A single MVM rung does the whole job. The mask is a 16-bit constant entered at programming time.
Bit-by-bit walkthrough
| Bit position | Mask bit | Source (B3:10) | Dest before | Dest after | Effect |
|---|---|---|---|---|---|
0 (LSB) | 1 | 1 (jam fault) | 0 | 1 | copied from source |
1 | 1 | 0 | 1 | 0 | copied from source (overwrote) |
2–7 | 1 | various | various | = source | all process bits transferred |
8 | 0 | 1 (diag flag) | 1 | 1 | preserved (mask = 0) |
9–15 | 0 | various | various | = dest before | diagnostic bits not touched |
The problem: the same packaging machine from Worked Example 1 actually has 10 parameters per recipe, not just one — oven temperature, conveyor speed, fill volume, dwell time, label-applicator pressure, and so on. With five products, that’s 50 stored values. We could write 50 MOV rungs… or one COP rung per product. We’ll go with COP — and add an FLL rung that clears the active recipe to a known state on system start-up.
Memory Map
| Address Block | Contents | Length |
|---|---|---|
N7:50–N7:59 | Recipe 1 — Standard (10 parameters) | 10 |
N7:60–N7:69 | Recipe 2 — Premium | 10 |
N7:70–N7:79 | Recipe 3 — Light | 10 |
N7:80–N7:89 | Recipe 4 — Crispy | 10 |
N7:90–N7:99 | Recipe 5 — Frozen | 10 |
N7:100–N7:109 | Active recipe — what the program reads while running | 10 |
Inputs & Outputs
INPUTS
I:1/0 — “Load Recipe” pushbutton (with OSR)
I:1/1 — System start-up bit (true for first scan)
N7:0 — Selected recipe number (1–5)
OUTPUTS
N7:100–N7:109 — Active running recipe
B3:0/0 — Recipe-load OSR bit
Ladder Diagram (Six Rungs)
FLL clears the active block on first scan. Five COP rungs (gated by OSR + EQU on recipe number) each transfer 10 words from one recipe block to the active block.
How it works
- System powers up. Rung 0’s “first scan” XIC fires. FLL writes 0 into
N7:100–N7:109. The active recipe is in a known empty state. - Operator sets the recipe selector to 3 and presses LOAD. The button takes
I:1/0high. The OSR fires once and lightsB3:0/0for one scan. - For that one scan, all five COP rungs scan with B3:0/0 true — but only rung 3’s EQU (test “
N7:0 = 3“) is also true. The COP on rung 3 fires and transfersN7:70–N7:79(recipe 3) intoN7:100–N7:109in a single instruction. - Next scan, B3:0/0 is back to 0. No COP rungs fire. The active recipe stays at recipe 3’s values until the operator presses LOAD again.
- Operator selects recipe 5, presses LOAD. Same sequence — COP rung 5 fires once and overwrites the active block with recipe 5’s values.
Why use the OSR instead of the LOAD button directly?
If we put I:1/0 directly into each COP rung, the COP would fire every scan the button is held down — wasted cycles and an unnecessary memory write every scan. The OSR ensures the COP fires exactly once per button press regardless of how long the operator holds the button.
The problem: a holding tank is filled by a control valve and drained continuously by a downstream pump. We want to hold the tank’s level at a fixed setpoint — say 50 % full — by modulating the inflow valve. Higher level → close the valve more; lower level → open the valve more. We’ll build the simplest possible closed-loop controller: a P-only controller using just SUB and MUL. This is the same idea the PID instruction uses internally, just without the I and D terms.
Inputs & Outputs
INPUTS
F8:0 — Tank level, % (PV, from 4–20 mA level transmitter)
F8:1 — Setpoint, % (SP, from operator HMI)
F8:2 — Proportional gain Kp (tuneable)
OUTPUTS
F8:10 — Error (calculated)
F8:11 — Raw control output (calculated)
O:4.0 — Control valve, % open (CV, to 4–20 mA analog out)
Ladder Diagram (Three Rungs — the Heart of P-Control)
Three rungs implement the entire P-controller: subtract for error, multiply for gain, clamp and write the result to the analog output. (Rung 3 shown for the high-saturation case; a similar GRT-low rung handles negative outputs.)
How it works — a numerical walkthrough
Let’s say SP = 50.0 %, Kp = 2.5, and the tank starts empty (PV = 10.0 %):
| Time | PV (level %) | Error = SP − PV | CV_raw = Kp × E | Valve output | Effect |
|---|---|---|---|---|---|
| t = 0 | 10.0 | +40.0 | +100.0 | 100 % open (clamped) | Maximum fill |
| t = 30 s | 30.0 | +20.0 | +50.0 | 50 % open | Slowing fill |
| t = 60 s | 45.0 | +5.0 | +12.5 | 12.5 % open | Approaching SP |
| t = ∞ | ~48 | ~+2.0 | ~+5.0 | ~5 % open | Steady-state offset! |
Notice the steady-state offset at the bottom of the table. With pure proportional control, the controller needs a non-zero error to keep producing a non-zero output — and that non-zero output is necessary to balance the continuous drain on the tank. The result: PV settles a few percent below SP, never quite reaching it. This is a fundamental limit of pure P-control.
Where I and D come in
The I (integral) term accumulates the error over time and adds it to the output — it slowly increases the valve position to drive the residual error to zero, eliminating the steady-state offset. The D (derivative) term reacts to how fast the error is changing — it brakes the controller’s response if PV is approaching SP rapidly, preventing overshoot. Together with the P term we just built, you get the full PID controller — and modern PLCs wrap all three terms (plus output limits, anti-windup protection, gain scheduling, and tuning interfaces) into a single PID instruction. We’ll meet that instruction properly in a later chapter.
Common Student Mistakes
Things to watch out for in this chapter:
- Mixing file types in a MOV. A MOV from
F8:0(float) toN7:0(integer) silently truncates the decimal portion.120.7becomes120. Always check that source and destination file types match — or that the conversion is intentional. - Using EQU on floating-point values. Floating-point equality is unreliable due to rounding. Two values that should be equal (mathematically) frequently aren’t, due to IEEE-754 round-off. Use a LIM with a tolerance band instead.
- Forgetting that MOV fires every scan it’s enabled. If the source value is constant and you only want to load it once, gate the MOV with a one-shot. Otherwise the destination gets overwritten every scan — usually harmless but wasteful.
- Forgetting the
#prefix on COP/FLL addresses. Without it, the PLC interprets the address as a single word, not the start of an array. The COP would copy 1 word instead of 10. Different platforms vary; check the syntax for yours. - Off-by-one errors on COP length.
COP #N7:50 #N7:100 length 10copies exactly 10 elements (N7:50 to N7:59). It does not include N7:60. Length is a count, not an end address. - Using LIM with Low > High accidentally. When Low > High, LIM tests for “outside the range” instead of “inside” — a frequent source of inverted comparisons. If you find LIM behaving the opposite of what you expect, check whether your low and high values are reversed.
- Forgetting to clamp the output of a hand-built P-controller. Without LIM/GRT/LES rungs to limit the output to 0–100 % (or whatever the actuator accepts), large errors produce out-of-range values that confuse the analog output card or saturate the actuator unsafely.
- Tuning Kp by raising it until the loop oscillates. A common student method, occasionally appropriate, often catastrophic on real machinery. For mission-critical loops, follow a structured tuning method (Ziegler-Nichols, IMC, lambda) rather than the trial-and-error approach.
- Expecting a P-only controller to hit setpoint exactly. Pure P-control always leaves a steady-state offset. If “exactly at setpoint” is required, you need the I term — i.e., move to a PI or PID controller.
Quick Recap
The ten things to take away from Chapter 10:
- PLC memory is organised into files, each holding a specific data type — bits in B, integers in N, floats in F. The file letter tells the PLC how to interpret the bits.
- MOV copies one value from source to destination every scan its rung is true. Use a one-shot if you only want to copy once per event.
- MVM copies only the masked bits from source to destination, preserving the unmasked bits. Use it when several program sections own different bits of a shared status word.
- COP copies an array of N words in one instruction. FLL writes the same value into every element of an array.
- Comparators (EQU, NEQ, LES, GRT, LEQ, GEQ) sit on the input side of a rung and pass power when their condition is true.
- LIM tests three values at once (Low, Test, High) and is the cleanest way to ask “is this value inside an operating window?”
- Recipe selection — five COP rungs gated by EQU on a recipe number — is the standard pattern for multi-product machinery.
- BCD encoding stores each decimal digit in 4 bits. FRD converts BCD-from-thumbwheel to plain binary; TOD converts plain binary to BCD-for-display.
- Closed-loop control measures the process variable, computes error against the setpoint, and continuously adjusts the actuator. Key terms: SP (setpoint), PV (process variable), E (error), CV (control variable).
- A proportional controller is just
CV = Kp × (SP − PV)— three rungs of SUB, MUL, and a LIM clamp. Pure P always leaves a steady-state offset; integral and derivative terms (the I and D of PID) eliminate it.
Review & Self-Assessment
Chapter 10 Review Questions
Try answering each question on your own first. Tap to reveal the answer when you’re done.
Q1What is the difference between integer file N7 and floating-point file F8?+
Q2A MOV rung has source N7:5 and destination N7:20, gated by an XIC of an “Enable” bit. The Enable bit stays true for 100 scans. What happens to N7:20?+
Q3Explain in your own words what the mask in an MVM instruction does.+
0000 0000 1111 1111 copies only the lower 8 bits from source to destination; the upper 8 bits of the destination are not touched.Q4What does a COP instruction with source #N7:50, destination #N7:100, and length 10 actually do?+
N7:50 into 10 consecutive words starting at N7:100. So N7:50→N7:100, N7:51→N7:101, … N7:59→N7:109. The contents of N7:50 through N7:59 are unchanged (source isn’t modified); N7:100 through N7:109 are overwritten with the source values. The # prefix tells the PLC to treat the address as the start of an array.Q5Why is LIM more compact than wiring a GEQ and a LEQ in series?+
Q6Why should you avoid using EQU on floating-point values?+
0.1 + 0.2 and 0.3 — may not be equal at the bit level due to round-off. EQU does a bit-by-bit comparison and returns false even though the values are conceptually identical. The fix is to use a LIM with a small tolerance band instead: SP − 0.5 ≤ PV ≤ SP + 0.5 reliably detects “PV is at SP” within an acceptable margin.Q7An operator selects recipe number 4 from a thumbwheel. What sequence of events loads the corresponding 10-parameter recipe into the active running block?+
N7:0. (3) The operator presses LOAD. (4) The button input goes high; an OSR generates a single-scan pulse on a “load trigger” bit. (5) Five COP rungs scan; only the rung gated by EQU N7:0 = 4 sees both the trigger bit and a true comparator. (6) That COP fires, transferring the recipe-4 block (e.g. N7:80–N7:89) into the active block N7:100–N7:109. (7) The rest of the program reads from N7:100 onwards and runs with the new parameters.Q8In a closed-loop control system, what do SP, PV, E, and CV stand for?+
E = SP − PV. CV = Control Variable — what the controller commands the actuator to do (valve position, heater duty, motor speed, etc.). The controller’s job is to drive E toward zero by adjusting CV based on the current PV.Q9Write the equation for a pure proportional controller’s output, and explain what each term means.+
CV = Kp × (SP − PV) — i.e., CV = Kp × E. Kp is the proportional gain, a tuneable constant. SP − PV is the error. CV is the control output sent to the actuator. The output is directly proportional to the error: a bigger error produces a bigger correction, and when the error is zero the output is zero. This is the simplest possible feedback controller, implementable with one SUB and one MUL on any PLC.Q10Why does a pure P-controller leave a steady-state offset, and how is that offset eliminated?+
Q11A 4-digit BCD thumbwheel switch is set to “0245”. What does the corresponding raw 16-bit BCD word look like, and what binary integer does FRD produce from it?+
0000 0010 0100 0101 — each decimal digit (0, 2, 4, 5) encoded as 4 bits in its own nibble. The FRD instruction recognises this is BCD encoding and converts it to the plain binary integer 245 — which in 16-bit binary is 0000 0000 1111 0101. Notice the bit patterns are completely different even though both represent the same number — that’s why the conversion step is required before doing math on the value.Q12Compare and contrast open-loop and closed-loop control with one practical example of each.+
Need help architecting a recipe system or tuning a closed-loop controller?
Get one-on-one tutoring or design-review help from Dr Ahsan Rahman — Head of Electrical Engineering, with two decades of experience teaching PLC data architecture, recipe systems, and process-control loop design.