11
Math Instructions
Chapter 10 gave the PLC the ability to move and compare numbers; this chapter teaches it to compute with them. Add a part to a running total, subtract a tare weight, multiply length by width to get area, divide a sum by a count to get an average, scale a 4–20 mA analog signal into engineering units, even apply the same calculation across a 100-element array in one rung. By the end, you’ll have the math toolkit to build totalizers, calibration routines, ratio controllers, and the arithmetic backbone of every PID loop in the plant.
What you’ll be able to do after this chapter
Your goals for this chapter:
- Explain the structure of any math instruction — Source A, Source B, Destination — and read its math status bits (Z, V, C, S).
- Use ADD for running totals, totalizers, and incremental updates.
- Use SUB for difference calculations like net weight, error, and elapsed time.
- Use MUL for unit conversions, area and volume calculations, and scale factors.
- Use DIV safely — knowing how to detect and handle divide-by-zero.
- Compress complex multi-step math into a single CPT rung.
- Use MOD for remainder/modulo logic, and SCP to map analog inputs into engineering units.
- Apply file arithmetic instructions (FAL, AVE, STD, SRT) across whole arrays in one operation.
- Recognise integer overflow, float precision loss, and order-of-operations pitfalls before they corrupt your data.
Key Concepts & Terms
Math Instructions Overview
Every math instruction in a PLC follows the same three-piece structure: take Source A, combine it with Source B using some operation, and put the result in the Destination. Whether you’re adding, subtracting, multiplying, or dividing, the rung looks identical from the outside — only the operation symbol changes.
The four math status bits
After every math operation, the PLC updates four bits in the processor’s status word that tell you what happened during the calculation. You can use these bits as inputs to other rungs to detect arithmetic problems before they corrupt your data:
| Bit | Name | Set when… | Typical use |
|---|---|---|---|
S:0/0 | C — Carry | Result generated a carry-out (or borrow-out for subtraction) | Multi-precision arithmetic; rare in normal applications |
S:0/1 | V — Overflow | Result is too big to fit in the destination’s data type | Always check for integer overflow before trusting a math result |
S:0/2 | Z — Zero | Result is exactly zero | “Zero remaining” detection in countdowns and DIV remainder checks |
S:0/3 | S — Sign | Result is negative | Detecting underflow or unexpected negative results |
Figure 11.1 — Math instruction anatomySource A and Source B can each be either a register address or a constant. The Destination must always be a writable address. Status bits Z, V, S, C update after every operation.
Choosing data types — integer vs floating-point
Picking the right destination matters. The two main choices are:
- Integer destination (N7) — fast, exact for whole numbers, but limited to ±32 767 in 16-bit form. Any decimal portion is truncated. Choose this when the value will always be a whole number — counts, recipe IDs, indices.
- Floating-point destination (F8) — IEEE-754 32-bit floats. Range up to ±3.4 × 10³⁸ with about 7 digits of precision. Slower than integer math but mandatory for any value with a decimal portion or large dynamic range — temperatures, weights, calibrated readings, ratios.
A common rookie error
Mixing integer and float in one expression.
- Storing a divide result like
10 ÷ 3into an integer destination gives 3, not 3.333… — the decimal part is silently truncated. - Multiplying two large integers can overflow even when the values look small, e.g.
30 000 × 5 = 150 000overflows a 16-bit integer. - If your math involves any fractional values, any large dynamic range, or any divide operation, default to F8 destinations. You can always cast back to N7 later if you need an integer.
Addition (ADD)
The ADD instruction takes Source A, adds Source B to it, and stores the sum in the Destination:
ADD source A: N7:0 source B: N7:1 dest: N7:10
Reads as: N7:10 = N7:0 + N7:1, computed every scan the rung is true.
The “increment by 1” pattern
The most common ADD use is incrementing a value by a constant — typically 1 — when an event occurs. This is how you build a totalizer:
ADD source A: N7:50 source B: 1 dest: N7:50
The destination is the same as Source A, so each scan the rung is true, the value at N7:50 grows by 1. This rung must be gated by a one-shot — otherwise it’ll add 1 every scan as long as the trigger is held, racing past the actual count. We’ll see this pattern in Worked Example 1.
ADD vs. counter — when to use which
If you want to count discrete events, the CTU counter from Chapter 8 is purpose-built and includes preset comparison and DN bit. Use it. Use ADD for cumulative quantities that aren’t simple +1 events — kg dispensed, litres pumped, kWh consumed — where you’re adding the amount from each event to a running total, not just incrementing a counter.
Subtraction (SUB)
The SUB instruction computes destination = source A − source B:
SUB source A: N7:0 source B: N7:1 dest: N7:10
The order matters — Source A minus Source B, not the other way around. Reversing them changes the sign of the result.
Three classic uses
- Net weight = gross weight − tare weight. Every scale and batch-fill uses this calculation. We’ll build it in Worked Example 2.
- Error = setpoint − process variable. The cornerstone of every closed-loop controller (you saw this in Chapter 10 with the proportional tank-level loop).
- Elapsed time = end time − start time. Measuring how long an event took, useful for cycle-time analysis and PID tuning data.
Watch the sign bit
If Source B is greater than Source A, the result is negative. With an integer destination, that’s fine if the destination is signed (the default for N7) — you’ll just see a negative number. With an unsigned destination, a negative result wraps around to a very large positive number. The S (sign) status bit is set whenever the result is negative; you can use that bit as an alarm, an interlock, or just a flag for diagnostics.
Multiplication (MUL)
The MUL instruction computes destination = source A × source B:
MUL source A: F8:0 source B: F8:1 dest: F8:10
Where MUL shows up in industry
- Unit conversions — kg to lb, m to ft, °C to °F (with an offset). Each conversion is one MUL by a constant factor (and possibly an ADD).
- Area and volume calculations — length × width for area, length × width × height for volume, π × r² × height for cylindrical tanks.
- Ratio calculations — desired flow × ratio = matched flow (for blending two streams in a recipe).
- Scaling factors — raw count × calibration constant = engineering value.
- Proportional control — Kp × error = correction (the heart of every P, PI, and PID controller).
Integer overflow is real and easy to trigger
Multiplying two integers can overflow surprisingly fast.
- 16-bit integer range is ±32 767. The product of two values larger than ~180 already exceeds 32 767.
- 30 000 × 5 = 150 000 → overflow. The destination wraps and shows nonsense.
- The V (overflow) status bit is set on overflow — but only if you check it. The math result itself is corrupted silently.
- For multiplication, default to F8 destinations unless you’ve proved both inputs are tiny. The performance cost is negligible; the safety gain is huge.
A simple safety habit
If a calculation involves multiplying any sensor reading by a calibration constant, store the result in a float register. The 30 % overhead of float math is invisible on modern PLCs; the cost of an undetected integer overflow can be a wrecked product run, a tripped alarm at 3 a.m., or worse. When in doubt, use F8.
Division (DIV)
The DIV instruction computes destination = source A ÷ source B:
DIV source A: F8:0 source B: F8:1 dest: F8:10
Two universal hazards
DIV has two pitfalls that bite every PLC programmer eventually:
- Integer truncation. Integer DIV throws away the remainder.
10 ÷ 3stored in N7 returns 3, not 3.333… If you need the fractional part, use a float destination — or use MOD (Section 11.6) to capture the remainder separately. - Divide by zero. If Source B reaches 0, the operation is undefined. On most platforms this triggers a major fault and halts the CPU. Always guard your DIV rungs with an XIO that prevents execution when the divisor is 0.
The divide-by-zero guard pattern
Place a NEQ comparator in front of every DIV instruction:
NEQ N7:1, 0 ──┤├──── DIV src A: N7:0 src B: N7:1 dest: N7:10
The DIV only executes when the divisor is non-zero. If the divisor is zero, the rung is false, the DIV is skipped, and the previous result in N7:10 is preserved. Pair this with an alarm flag if zero divisor signals a real problem (e.g., a sensor is reading zero when it shouldn’t).
A real industry story
A flowmeter on a dosing pump reads zero when the line is shut down for maintenance. The control program calculates “fluid concentration = mass ÷ volume”. When the pump restarts, the flowmeter takes 200 ms to come back online and reads 0 in the meantime. The DIV sees the zero, the CPU faults, every output drops, and the entire batch is scrapped. One NEQ guard would have prevented the entire incident. Always guard your DIV rungs.
Other Word-Level Math (CPT, MOD, SCP)
Beyond the basic four, three additional word-level instructions cover compound expressions, modular arithmetic, and analog scaling.
CPT — Compute
The CPT instruction lets you write a multi-operation expression as a single rung — like a calculator. Where you’d otherwise need three or four separate ADD/SUB/MUL/DIV rungs, CPT does it all at once with proper order of operations.
CPT expression: (F8:0 * F8:0 * 0.025) + (F8:0 * 1.8) – 32 dest: F8:10
That single rung evaluates a quadratic — useful for non-linear sensor calibration, polynomial corrections, and any compound formula. CPT respects standard math precedence (×, ÷ before +, −) and parentheses, so you can write expressions exactly as you’d write them on paper. The trade-off: CPT is slower than the equivalent chain of basic instructions (typically 1.5× to 2× the scan time per rung), so for performance-critical code the chain may still win — but for clarity, CPT is unmatched.
MOD — Modulo (remainder)
The MOD instruction returns the remainder of an integer division. Where DIV with integer destination computes the quotient (and discards the remainder), MOD computes the remainder (and discards the quotient):
MOD source A: 17 source B: 5 dest: N7:10 → N7:10 = 2 (because 17 = 3 × 5 + 2)
Use cases:
- “Every Nth event” — when
counter MOD N == 0, fire an event. Good for periodic sampling, every 10th part inspection, etc. - Wrap-around array index —
(index + 1) MOD array_sizewraps the index back to 0 when it exceeds the array size. We used this pattern in Chapter 10’s STI sampling buffer. - Remainder check — for “is this number divisible by N”, just check
X MOD N == 0.
SCP — Scale with Parameters
The SCP instruction performs the most common analog math job: linearly mapping a value from one range to another. Give it the input minimum, input maximum, output minimum, output maximum, and a source value — it does the linear interpolation in one rung.
SCP input: I:3.0 in min: 4000 in max: 20000 out min: 0.0 out max: 100.0 dest: F8:0
That rung scales a 4–20 mA analog input (which the I/O card reports as raw counts 4 000–20 000) into a 0–100 % engineering value stored in F8:0. The SCP saves you from writing the equivalent expression by hand:
F8:0 = ((I:3.0 − 4000) × (100.0 − 0.0) / (20000 − 4000)) + 0.0
Both calculations produce the same result, but SCP reads naturally and is harder to get wrong.
Figure 11.2 — SCP linear scalingThe input range (4 000 – 20 000 raw counts) maps proportionally onto the output range (0.0 – 100.0 °C). Any input value lands at the same percentage of the output range — 8 000 raw is 25 % of the input range, so it maps to 25 % of the output, which is 25.0 °C.
File Arithmetic Operations
The instructions you’ve seen so far operate on single words at a time. To run a calculation across an array of values — apply a calibration to 100 stored samples, sum the elements of a recipe, average the last 50 readings — single-word instructions would need a loop or 100 separate rungs. Modern PLCs offer dedicated file arithmetic instructions that work across whole arrays in one rung.
FAL — File Arithmetic Logic
The FAL instruction is the most general. It applies an arithmetic expression to elements of one or more arrays, storing the results in another array. You configure it with:
- Control register — tracks position, length, and done bit (much like a counter or timer instance).
- Length — how many elements to process.
- Mode — All processes every element on a single scan; Numeric processes a configurable number of elements per scan; Incremental processes one element per rung-true transition.
- Expression — the math to apply, written CPT-style with
#prefixes for array sources/destinations.
Example: scale every value in a recipe block by a calibration factor:
FAL control: R6:0 length: 10 mode: All expression: #N7:50 * F8:99 dest: #N7:100
That rung multiplies each of N7:50…N7:59 by the calibration constant in F8:99 and stores the results in N7:100…N7:109 — the equivalent of 10 separate MUL rungs in one instruction. We’ll build this out in Worked Example 6.
AVE, STD, SRT — statistical operations
Three more file-level instructions handle common statistics directly:
- AVE — Average. Takes the mean of N consecutive elements and stores it in a destination word. Useful for smoothing noisy sensor readings.
- STD — Standard Deviation. Computes the population standard deviation of N elements. Useful for process-quality monitoring (high σ = inconsistent process).
- SRT — Sort. Sorts an array in ascending order. Useful for ranking, median calculations, and outlier detection.
When file arithmetic earns its keep
You have a temperature sensor logged into a 100-element circular buffer (like the STI sampling routine from Chapter 10). You want to display the running 100-sample average to smooth out noise. One AVE rung reads the array and computes the mean every scan. The alternative — sum 100 ADDs and one DIV — is technically equivalent but takes 100 rungs and dozens of times more scan time. For anything that operates on an array, look at the file instructions before writing a manual loop.
Worked PLC Programs
Six Programs — From a Production Totalizer to File-Level Arithmetic
The six programs build progressively through the math toolkit: ADD for a totalizer, SUB for net weight, MUL for cylindrical volume, DIV for an average (with a divide-by-zero guard), CPT for compact polynomial calibration, and FAL for applying a single calculation across an entire recipe array.
The problem: a packaging line drops bagged product onto a check-weigher at the end of the conveyor. Each bag’s weight is reported by the weigher in F8:0 (kg). A photo-eye at the check-weigher discharge confirms each bag has been weighed and is leaving the station — that’s the trigger to add the weight to the running shift total. We want to maintain a running shift total in F8:50 that operators can read from the HMI, plus a separate day total in F8:51.
Inputs & Outputs
INPUTS
I:1/0 — Bag-leaving photo-eye (rising edge = one bag completed)
F8:0 — Latest bag weight, kg (from check-weigher)
I:1/1 — Shift-end pushbutton (operator presses to roll shift total to day total)
OUTPUTS
F8:50 — Running shift total, kg
F8:51 — Running day total, kg
B3:0/0 — One-shot bit for bag photo-eye
B3:0/1 — One-shot bit for shift-end button
Ladder Diagram (Three Rungs)
Three rungs: per-bag ADD (rung 0), shift-to-day roll-up on shift-end (rung 1), shift-clear after roll-up (rung 2). All gated by one-shots so the holds-and-bounces of buttons can’t trigger duplicate adds.
How it works
- Each bag passes the check-weigher photo-eye. The weigher has already deposited the latest bag’s weight into
F8:0. The photo-eye drivesI:1/0high. The OSR pulsesB3:0/0for exactly one scan. - For that one scan, the ADD on rung 0 fires.
F8:50 = F8:50 + F8:0. If the shift total was 124.7 kg and the bag weighed 5.0 kg, F8:50 is now 129.7 kg. - Bag continues away from the photo-eye.
I:1/0goes low again, but the OSR has already done its job — the next time the photo-eye triggers a different bag,B3:0/0will pulse again. Without the OSR, the ADD would fire every scan the bag was in front of the eye, multiplying the bag’s weight by however many scans it took to pass — a serious totaliser corruption. - End of shift. Operator presses the shift-end button.
I:1/1goes high,B3:0/1pulses for one scan. Rung 1’s ADD adds the shift total (e.g. 8 425 kg) to the day total. Rung 2’s MOV resets the shift total to 0.0. - Shift starts again. Bags resume passing the photo-eye. Each new bag adds to the (now zero) shift total. The day total continues to grow throughout the day; the shift total resets every shift-end press.
The problem: a batch-fill scale weighs an empty container, then keeps weighing as material is added. The operator wants to see the net weight of the material — gross weight minus tare weight. Pressing TARE captures the current gross weight into a stored tare value; from then on, the displayed net weight is the live gross minus the stored tare. This is exactly how every retail and laboratory scale works internally.
Inputs & Outputs
INPUTS
F8:0 — Live gross weight, kg (from load cell)
I:1/0 — TARE pushbutton (one-shot triggers tare capture)
OUTPUTS
F8:1 — Stored tare weight, kg
F8:10 — Net weight, kg (continuously displayed on HMI)
B3:0/0 — Tare-button OSR bit
O:2/0 — “TARE CAPTURED” indicator lamp
Ladder Diagram (Three Rungs)
Rung 0 captures the tare on a button press. Rung 1’s SUB runs every scan to keep the net weight live. Rung 2 lights the indicator whenever a tare is in effect.
A worked example with numbers
| Step | F8:0 (gross) | F8:1 (tare) | F8:10 (net) | Lamp |
|---|---|---|---|---|
| Empty bucket placed on scale | 1.20 kg | 0.00 | 1.20 | off |
| Operator presses TARE | 1.20 kg | 1.20 | 0.00 | on |
| Material added — 0.5 kg | 1.70 kg | 1.20 | 0.50 | on |
| Material added — 1.0 kg total | 2.20 kg | 1.20 | 1.00 | on |
| Operator removes bucket | 0.00 kg | 1.20 | −1.20 | on |
The problem: a vertical cylindrical storage tank has a level transmitter reporting current liquid height in metres. The operator wants the HMI to display the actual volume of stored liquid in litres. The tank’s internal radius is fixed at 1.50 m, so volume = π × r² × h. We need to compute that with three MUL operations chained together. Storing the result in litres requires multiplying the cubic-metre result by 1 000 — one more MUL.
Inputs & Outputs
INPUTS & CONSTANTS
F8:0 — Liquid height, m (from level transmitter)
F8:90 — π = 3.14159 (constant)
F8:91 — Radius squared = 2.25 m² (pre-computed: 1.50²)
OUTPUTS
F8:10 — Volume in m³ (intermediate)
F8:11 — Volume in litres (HMI display)
Ladder Diagram (Three Rungs)
Three MULs cascade: π·r² → ×height → ×1000. Each rung’s destination becomes the next rung’s source. All sources and destinations are F8 floats.
A numerical walk-through
Suppose the tank is 4.20 m tall and currently filled to 2.80 m:
| Step | Calculation | Result |
|---|---|---|
| Rung 0 — base area | π × r² = 3.14159 × 2.25 | F8:5 = 7.069 m² |
| Rung 1 — m³ | base area × height = 7.069 × 2.80 | F8:10 = 19.79 m³ |
| Rung 2 — litres | m³ × 1000 = 19.79 × 1000 | F8:11 = 19 794 L |
Why split it across three rungs?
You could put all three MULs in a single CPT instruction (we’ll see that pattern in Worked Example 5). Splitting across three rungs has two advantages here: (1) each intermediate value is visible on the HMI for diagnostics — if the volume looks wrong, you can see whether the base area is wrong or the height is wrong; (2) the constant base area in F8:5 only needs to be computed once, but here it gets computed every scan with the same inputs producing the same result — which is wasted but harmless. For pure performance, gate rung 0 with a “first scan” XIC to compute the base area once at startup.
The problem: the production totalizer from Worked Example 1 already gives us the cumulative shift weight. We also keep a separate counter that increments once per bag. We want to display the average bag weight for the shift on the HMI: average = shift total ÷ bag count. The catch: at the start of every shift, the counter is 0 — and we need to make sure DIV never runs with a zero divisor or the CPU faults.
Inputs & Outputs
INPUTS
F8:50 — Shift total weight, kg (from Program 1)
C5:0.ACC — Bag counter accumulator (from a CTU on the bag photo-eye)
OUTPUTS
F8:60 — Bag count cast to float (intermediate)
F8:61 — Average bag weight, kg (HMI display)
O:2/0 — “AVG VALID” lamp (off until first bag)
Ladder Diagram (Three Rungs)
Rung 0 casts the integer counter to float. Rung 1 runs the DIV only when the divisor is non-zero. Rung 2 indicates whether the displayed average is meaningful.
How it works
- Start of shift — counter resets to zero.
C5:0.ACCis 0; rung 0 copies it intoF8:60as 0.0. Rung 1’s NEQ comparator sees 0.0 = 0.0 (the comparison is FALSE for “not equal”), so the rung is false and the DIV does NOT execute.F8:61retains its previous value (or 0 from initial scan). Rung 2’s NEQ is also false, so the “AVG VALID” lamp stays off. - First bag passes — counter goes to 1.
F8:60 = 1.0. Now NEQ sees 1.0 ≠ 0.0, which is TRUE. The DIV fires. If the shift total is 5.0 kg from this single bag, F8:61 = 5.0 / 1.0 = 5.0 kg average. Lamp lights. - Subsequent bags add up. Counter at 100, shift total at 487.3 kg → average = 487.3 ÷ 100 = 4.873 kg. The HMI updates live as each bag passes.
- Without the NEQ guard: on the very first scan after counter reset, the DIV would attempt 0.0 ÷ 0.0, the CPU would fault, every output would drop, and the line would stop. One NEQ comparator prevents the entire failure mode.
The problem: a thermistor temperature sensor has a non-linear response. The manufacturer provides a calibration polynomial:
T (°C) = a × R² + b × R + c
where R is the resistance reading (in kΩ) and a, b, c are calibration constants supplied with the sensor. With ADD/SUB/MUL chained together this would be 4 or 5 separate rungs, each holding an intermediate value. With CPT, it’s one rung that reads exactly like the calibration sheet.
Inputs & Outputs
INPUTS & CALIBRATION CONSTANTS
F8:0 — Sensor resistance R, kΩ (from analog input, scaled)
F8:80 — Coefficient a = -0.025
F8:81 — Coefficient b = 4.50
F8:82 — Coefficient c = -110.0
OUTPUT
F8:10 — Calibrated temperature, °C (HMI display, used by control loop)
Ladder Diagram (One Rung)
One CPT rung, three lines of expression. CPT respects standard math precedence — multiplications happen first, then the additions sum the three terms.
A numerical walk-through
With the calibration constants above (a = -0.025, b = 4.50, c = -110.0) and a measured resistance of R = 32.0 kΩ:
| Term | Calculation | Result |
|---|---|---|
| a × R² | −0.025 × 32 × 32 = −0.025 × 1024 | −25.6 |
| b × R | 4.50 × 32 | +144.0 |
| c | (constant) | −110.0 |
| Sum (T in °C) | −25.6 + 144.0 − 110.0 | F8:10 = 8.4 °C |
Compare with the equivalent ADD/MUL chain
Without CPT, the same calculation needs 4 rungs and 3 intermediate registers:
Rung 0: MUL F8:0 × F8:0 → F8:5 (R²)
Rung 1: MUL F8:80 × F8:5 → F8:6 (a × R²)
Rung 2: MUL F8:81 × F8:0 → F8:7 (b × R)
Rung 3: ADD F8:6 + F8:7 → F8:8 (a × R² + b × R)
Rung 4: ADD F8:8 + F8:82 → F8:10 (final temperature)
Both produce the same answer. CPT gets there in one rung that reads like the formula on the calibration sheet; the chained version requires keeping mental track of three intermediate registers and four rungs of arithmetic. For non-linear calibrations, polynomial fits, and any compound formula, CPT is dramatically clearer.
When NOT to use CPT
Two cases. (1) Performance-critical loops. CPT is roughly 1.5×–2× slower per execution than the equivalent chain. If the rung runs every scan in a tight control loop (PID, motion), the chain may be worth the extra rungs for the speed gain. (2) When you want diagnostic visibility. The chain stores intermediate values in named registers — useful when troubleshooting because you can watch each step on the HMI. CPT computes everything internally and only the final result is visible. For sensor calibration where the formula matters but the intermediate steps don’t, CPT wins. For diagnostic work where you want to see exactly which step went wrong, the chain wins.
The problem: the active recipe (10 parameters in N7:100–N7:109, loaded via the COP pattern from Chapter 10) was calibrated against an old material. A new material requires every parameter to be scaled by a calibration factor of 1.08 (8 % more of every ingredient). We need the calibrated values placed into a new array N7:110–N7:119 ready for the recipe sequencer to consume. With single MULs this would be 10 rungs. With FAL, it’s one rung that processes all 10 elements.
Inputs & Outputs
SOURCES
#N7:100 — Source array (10 elements, base recipe)
F8:99 — Calibration factor (1.08)
I:1/0 — “Apply Calibration” pushbutton (with OSR)
DESTINATIONS
#N7:110 — Destination array (10 elements, calibrated recipe)
R6:0 — FAL control register (position, length, done)
B3:0/0 — OSR bit
Source Array (before)
| Address | Parameter | Base value |
|---|---|---|
N7:100 | Oven temperature (°C) | 180 |
N7:101 | Conveyor speed (mm/s) | 250 |
N7:102 | Fill volume (mL) | 500 |
N7:103 | Dwell time (s) | 30 |
N7:104 | Label-applicator pressure (kPa) | 120 |
N7:105–N7:109 | (other parameters) | … |
Ladder Diagram (One Rung)
A single FAL rung. The expression #N7:100 * F8:99 means “for each element starting at N7:100, multiply by F8:99”. Length=10 sets the array size; Mode=All processes the whole array on the scan the rung becomes true.
How it works
- Operator presses APPLY CALIBRATION. The OSR pulses
B3:0/0for one scan. The FAL sees a true rung condition and begins. - FAL processes all 10 elements at once (Mode = All). Internally:
N7:110 = N7:100 × F8:99N7:111 = N7:101 × F8:99
… and so on throughN7:119 = N7:109 × F8:99. - The control register R6:0 tracks the operation:
R6:0/ENgoes true when FAL starts,R6:0/DNgoes true when all elements are processed,R6:0.LENshows 10,R6:0.POSshows 10 (final position). - Next scan, the rung is false again. R6:0/DN remains true until the rung becomes true again, signalling the calibration is complete.
Result Array (after one FAL)
| Address | Calculation | Calibrated value |
|---|---|---|
N7:110 | 180 × 1.08 | 194 (truncated from 194.4) |
N7:111 | 250 × 1.08 | 270 |
N7:112 | 500 × 1.08 | 540 |
N7:113 | 30 × 1.08 | 32 (truncated from 32.4) |
N7:114 | 120 × 1.08 | 129 (truncated from 129.6) |
N7:115–N7:119 | … × 1.08 | (other parameters scaled) |
Mode matters
FAL has three modes. Mode = All (used here) processes every element on the scan that the rung becomes true — fast but uses CPU time proportional to array length. Mode = Numeric processes a fixed number of elements per scan (e.g. 5 elements per scan for 2 scans to finish a 10-element array) — useful for spreading large arrays across multiple scans to keep scan time predictable. Mode = Incremental processes one element per false-to-true transition of the rung — useful when you want to step through an array under operator control. For a 10-element recipe calibration like this, “All” is the right choice.
Common Student Mistakes
Things to watch out for in this chapter:
- Putting math in an integer destination when the result has a fractional part. Integer math truncates silently.
10 ÷ 3stored in N7 returns 3, not 3.333… If the calculation can produce a fraction, target F8. - Multiplying integers without checking for overflow. 30 000 × 5 = 150 000 overflows the 16-bit integer limit and corrupts the destination. The V status bit catches this only if you check it. Default to F8 for any MUL with non-tiny inputs.
- Forgetting the divide-by-zero guard. A DIV rung with a zero divisor faults the CPU on most platforms. Always front-end DIV with a NEQ that ensures the divisor is non-zero.
- Using ADD without a one-shot for incremental updates. If the rung’s input bit holds high for multiple scans, ADD fires every scan and inflates the destination. The OSR ensures the ADD fires exactly once per event.
- Checking the V (overflow) bit after the wrong rung. The math status bits reflect the most recent math instruction. If you have multiple math rungs in a row, V reflects the last one only. Test the V bit immediately after the rung you care about, not three rungs later.
- Comparing floating-point results with EQU. Float arithmetic introduces tiny rounding errors. Two floats that “should” be equal often aren’t at the bit level. Use a LIM with a small tolerance band instead.
- Using CPT for performance-critical code. CPT is roughly 1.5×–2× slower per execution than the equivalent chained instructions. For tight control loops, the chain of basic math may be the better choice.
- Hiding intermediate values inside CPT when you need diagnostics. CPT only exposes the final result. If you need to see every intermediate step on the HMI for troubleshooting, the chain of separate rungs is preferable.
- FAL with Mode = All on a very large array in a fast scan. Processing 1 000 elements with Mode = All on a 10 ms scan can blow past the watchdog timer. Use Mode = Numeric to spread big arrays across multiple scans.
- Confusing MOD with DIV. DIV gives the quotient; MOD gives the remainder.
17 DIV 5 = 3with remainder 2;17 MOD 5 = 2directly. They are different instructions for different jobs.
Quick Recap
The ten things to take away from Chapter 11:
- Every math instruction has the same shape: Source A · Source B · Destination. Sources can be addresses or constants; the destination must always be a writable address.
- The four math status bits — Z (zero), V (overflow), S (sign), C (carry) — update after every operation. The V bit is the one you’ll check most often for safety.
- ADD with one-shot is the standard pattern for totalizers, counters of cumulative quantities, and incremental updates.
- SUB handles tare-net calculations, error terms in control loops, and elapsed-time differences. Order matters: A − B, not B − A.
- MUL handles unit conversions, area/volume calculations, and gain multiplications. Always default to F8 destinations to avoid silent integer overflow.
- DIV needs a divide-by-zero guard. Front-end every DIV rung with a NEQ comparator on the divisor.
- CPT packs compound expressions into a single rung. Use it for sensor calibration, polynomial fits, and any compound formula where structure matters more than intermediate values.
- MOD returns the remainder of an integer division. Useful for “every Nth event”, wrap-around array indices, and divisibility tests.
- SCP linearly scales a value from one range to another in one rung. The mainstay of analog input scaling (raw counts → engineering units).
- FAL applies an expression across an entire array in one rung. AVE, STD, SRT handle averages, standard deviations, and sorts on whole arrays directly.
Review & Self-Assessment
Chapter 11 Review Questions
Try answering each question on your own first. Tap to reveal the answer when you’re done.
Q1Name the three components every math instruction has, and explain what each one is.+
N7:5) or a constant value. The destination is where the result is stored — it must always be a writable register address, never a constant. The operation (+, −, ×, ÷) is determined by which math instruction you choose; the structure is otherwise identical across all four.Q2What is the V (overflow) status bit and why does it matter?+
Q3Why must an ADD rung that increments a counter by 1 be gated by a one-shot?+
Q4Why is a divide-by-zero guard essential before every DIV instruction?+
NEQ divisor, 0 ──┤├── DIV …. The DIV only executes when the divisor is non-zero; if the divisor is zero, the rung is false, the DIV is skipped, and the CPU keeps running normally.Q5What’s the practical difference between integer and floating-point destinations, and when would you choose each?+
Q6What does the CPT instruction do, and what’s its main advantage over chained ADD/SUB/MUL/DIV rungs?+
(F8:80 × F8:0² ) + (F8:81 × F8:0) + F8:82 is one rung that reads like the formula on the calibration sheet, instead of 4–5 separate rungs juggling intermediate values. The trade-off is that CPT is slightly slower (~1.5×–2×) and hides intermediate values that might be useful for diagnostics.Q7How does MOD differ from DIV, and give an example of where you’d use MOD.+
17 DIV 5 = 3 (with the remainder 2 thrown away), while 17 MOD 5 = 2 directly. A practical use case: a wrap-around array index that should reset to 0 when it reaches the array length. Compute (index + 1) MOD array_length — the result is always in the range [0, length − 1], regardless of how many times you’ve incremented the index. We used this exact pattern in Chapter 10’s STI sampling buffer.Q8What does SCP do, and what are its five parameters?+
Q9A FAL instruction has length 10 and Mode = All. What happens when its rung becomes true?+
Q10Why is using EQU on floating-point values risky, and what should you use instead?+
0.1 + 0.2 and 0.3 — frequently aren’t equal at the bit level due to round-off. EQU does a bit-by-bit comparison and returns false when the values differ even by an unmeasurably tiny amount. Use a LIM (limit test) with a small tolerance band instead: LIM target − 0.001, value, target + 0.001 reliably detects “value is close enough to target”. This is the same advice from Chapter 10, and it applies any time you compare floats for equality.Q11A line is dispensing fluid into 1 000 g batches. The flow meter reports total mass and a counter tracks the number of completed batches. The HMI should display the average mass per batch. Sketch the rung(s) needed.+
MOV C5:0.ACC → F8:60 — cast the integer counter accumulator to a float so the DIV produces a meaningful float result. Rung 1: NEQ F8:60, 0.0 ──┤├── DIV F8:50 (total mass) ÷ F8:60 (batch count) → F8:61 (average). The NEQ guard ensures the DIV only fires when at least one batch has completed. The float destinations preserve fractional results so the average displays as e.g. 998.7 g rather than the integer 998. An optional third rung with the same NEQ can drive an “AVG VALID” lamp so operators know whether the displayed value is meaningful yet.Q12When would you reach for FAL instead of writing many separate MUL/ADD rungs?+
Need help architecting recipe-scaling logic, sensor calibration, or analog scaling?
Get one-on-one tutoring or design-review help from Dr Ahsan Rahman — Head of Electrical Engineering, with two decades of experience teaching PLC math, signal scaling, and process-control programming.