Learn PLCs free
Evidence-led guide5,519 words

PLC Arrays, Data Handling and Math Instructions

Build safe PLC array and data-handling logic with bounded indexes, deterministic loops, copy/fill instructions, numeric type guards, scan traces and vendor-specific implementation notes.

PPI
PLC Programming IO Editorial Team
Sourced guidance with documented review and correction standards

Review status: Vendor-neutral method reviewed against IEC 61131-3:2025 and current official Rockwell Studio 5000, Siemens STEP 7 V20, CODESYS, Schneider EcoStruxure Machine Expert and Beckhoff TwinCAT array documentation; exact declaration syntax, type promotion, conversion, bounds checking, fault response, copy atomicity, overlap behavior, task preemption, execution time and safety suitability require target CPU, firmware, compiler and project verification

Direct answer: treat an array operation as a bounded data transaction

A PLC array is an indexed collection of elements that share a declared type. Safe array logic proves four things before it reads or writes an element: the array owner, the valid lower and upper bounds, the meaning of each element, and the maximum work the controller can perform in one task invocation. A correct value at the wrong index is still a control defect.

For a fixed eight-sample buffer, declare the bounds explicitly, reject or diagnose any index outside them, use a wider accumulator than the individual samples where necessary, guard division by the valid-sample count, and measure the worst-case execution time. If the array can be modified by another task, I/O update or communication service while it is processed, define whether the calculation needs a consistent snapshot and use the target platform's supported synchronization or staging method.

Data task Safe default Evidence required before release
read or write one element validate the runtime index before access low, high, just-below and just-above boundary tests
loop across every element derive loop limits from the declared contract inclusive bound trace and measured worst-case task time
sum or average values use a suitable accumulator and count only accepted values overflow analysis, invalid-value policy and zero-count test
move one value verify source/destination types and conversion negative, maximum, fractional and invalid cases as applicable
copy a block prove length units, source/destination extents and overlap behavior byte/element count, sentinel values around the destination and snapshot requirement
fill an array write only the intended elements and control when it executes first/last element, adjacent data and one-shot/command behavior
search or compare define not-found, duplicate and quality behavior empty/no-match, first/last match and repeated-value tests
process a large buffer split work over scans only when partial completion is acceptable progress state, data version, deadline and restart/cancel behavior

This guide owns the integrated array, indexing, data-movement, numeric and scan-budget workflow. The existing PLC math instructions guide remains the focused owner for ADD, SUB, MUL, DIV, MOD and compute expressions. The PLC data types guide owns the complete type catalogue. The indirect addressing definition owns the concise direct/indexed/indirect distinction. This page connects those pieces into tested array applications without replacing them.

Conceptual PLC memory array with a guarded valid range and an out-of-range write stopped at the boundary
Array safety starts at the boundary: validate the calculated index before the controller evaluates the array reference.

Define the data contract before writing a loop

An array declaration answers only part of the engineering question. ARRAY[0..7] OF REAL describes eight values and their element type. It does not state whether they are temperatures, whether a bad-quality sample is represented by a separate Boolean, which task writes them, whether the values form a coherent snapshot, or what should happen if an operator requests sample 9.

Write a compact contract for every production array:

Contract field Example for an eight-channel temperature buffer Why it matters
owner acquisition function block writes; calculation routine reads prevents hidden multiple writers
bounds indices 0 through 7 inclusive prevents off-by-one assumptions
element meaning channel number maps to an approved instrument list stops valid values being assigned to the wrong equipment
element type REAL engineering value plus separate validity/status avoids treating a sentinel number as healthy data
units degrees Celsius prevents scale or unit mismatch
update model all channels staged, then version increments tells readers when a coherent set is available
invalid policy exclude invalid channels; alarm if fewer than six are valid makes average behavior deterministic
consumer deadline completed within one 20 ms task invocation turns scan performance into a testable requirement
restart behavior initialize validity false; do not reuse an unverified retained buffer prevents plausible stale data after startup

Use a structure array when every element needs related fields:

TYPE ST_ChannelSample :
STRUCT
    Value      : REAL;
    Valid      : BOOL;
    StatusCode : UINT;
    Sequence   : UDINT;
END_STRUCT
END_TYPE

VAR_GLOBAL CONSTANT
    cFirstChannel : DINT := 0;
    cLastChannel  : DINT := 7;
END_VAR

VAR_GLOBAL
    aSamples : ARRAY[cFirstChannel..cLastChannel] OF ST_ChannelSample;
END_VAR

This IEC-style example is a portable design sketch, not paste-ready code for every tool. Current CODESYS, TwinCAT and Schneider documentation supports explicit lower/upper limits and arrays of derived types, but syntax, accepted constant types, initialization and variable-length parameters vary. Rockwell Logix array declarations are normally created as tags with a dimension, and zero-based indexing is central to that environment. Siemens STEP 7 supports array types and symbolic indexing, with exact instruction and type availability depending on the target CPU and TIA version.

Array bounds are inclusive—and vendor fault behavior differs

For ARRAY[0..7], the valid indexes are 0, 1, 2, 3, 4, 5, 6 and 7. The array has eight elements because the count is upper - lower + 1. A loop using 0 TO 8 performs nine iterations and attempts one invalid access. A loop using 0 TO 6 silently leaves the final element stale.

Where supported for the array form in use, derive limits with LOWER_BOUND and UPPER_BOUND:

FOR i := LOWER_BOUND(aSamples, 1) TO UPPER_BOUND(aSamples, 1) DO
    (* bounded work *)
END_FOR;

The dimension argument 1 means the first dimension in the cited CODESYS/Schneider/TwinCAT family documentation. Do not assume every compiler version supports the same operators for both fixed and variable-length arrays. When a target lacks bound introspection, define named constants once and use the same constants for the declaration, validation and loop.

Validate before the array reference is evaluated

The guard must surround the reference itself:

IndexValid := (RequestedIndex >= cFirstChannel)
           AND (RequestedIndex <= cLastChannel);

IF IndexValid THEN
    SelectedValue := aSamples[RequestedIndex].Value;
    SelectedValid := aSamples[RequestedIndex].Valid;
ELSE
    SelectedValid := FALSE;
    ArrayIndexFault := TRUE;
END_IF;

Do not calculate SelectedValue := aSamples[RequestedIndex].Value and then inspect the index. By then the invalid access has already occurred. Avoid “fixing” every bad index with an unconditional clamp unless the requirement explicitly says the nearest valid element is an acceptable substitute. Clamping recipe 12 to recipe 9 can apply the wrong product settings while hiding the original defect.

Platform behavior is not portable. Current Rockwell documentation states that an out-of-range Logix array subscript can generate a major fault, including type 4 code 20 for the documented instruction context. Siemens warns that indirect addressing is calculated at runtime and can access or overwrite incorrect values. CODESYS-derived environments can use implicit CheckBounds behavior, but whether it clamps, reports or raises an exception depends on the generated or customized check and project settings. A code review that says “the runtime will catch it” is therefore incomplete.

Boundary acceptance matrix

Test Requested index Expected result
lower boundary 0 element 0 read or written exactly once
interior 3 element 3 selected; neighbors unchanged
upper boundary 7 element 7 selected exactly once
below lower -1 access blocked, invalid flag/alarm set, no array element changes
above upper 8 access blocked, invalid flag/alarm set, no array element changes
extreme input minimum/maximum value the source tag can carry arithmetic cannot wrap into a plausible valid index
startup retained or externally written index before first normal scan initialization and validation prevent accidental access

These cases must be run on the exact target or an approved representative test environment. A browser exercise can teach the reasoning but cannot reproduce vendor runtime faults or task scheduling.

Worked example: calculate a quality-aware array average

The requirement is to calculate the minimum, maximum and arithmetic mean of eight channels. Invalid samples must not influence the result. When no samples are valid, the result must be marked invalid and division must not execute. The operation must finish within its task budget.

VAR
    i          : DINT;
    ValidCount : UDINT;
    SumWide    : LREAL;
    Minimum    : REAL;
    Maximum    : REAL;
    Mean       : REAL;
    ResultValid: BOOL;
END_VAR

ValidCount := 0;
SumWide := 0.0;
ResultValid := FALSE;

FOR i := cFirstChannel TO cLastChannel DO
    IF aSamples[i].Valid THEN
        IF ValidCount = 0 THEN
            Minimum := aSamples[i].Value;
            Maximum := aSamples[i].Value;
        ELSE
            IF aSamples[i].Value < Minimum THEN
                Minimum := aSamples[i].Value;
            END_IF;
            IF aSamples[i].Value > Maximum THEN
                Maximum := aSamples[i].Value;
            END_IF;
        END_IF;

        SumWide := SumWide + REAL_TO_LREAL(aSamples[i].Value);
        ValidCount := ValidCount + 1;
    END_IF;
END_FOR;

IF ValidCount > 0 THEN
    Mean := LREAL_TO_REAL(SumWide / UDINT_TO_LREAL(ValidCount));
    ResultValid := TRUE;
END_IF;

The explicit conversion function names are representative IEC-style notation. Confirm exact names and rounding behavior in the target compiler. A wider LREAL accumulator reduces the chance of losing range or precision compared with summing into the individual REAL element type, but it does not make a result mathematically exact or guarantee the target supports efficient 64-bit floating-point execution.

Initializing minimum and maximum to zero is wrong for an all-positive or all-negative valid set. The first accepted sample is a defensible initializer. The ValidCount > 0 guard prevents divide by zero. If at least six valid channels are required, replace the final criterion with that explicit minimum and expose the rejected count.

Scan-by-scan trace

Assume the valid samples are 12.5, invalid, 15.0, -2.0, 10.5, invalid, 14.0, 10.0:

Iteration/index Value Valid ValidCount after SumWide after Minimum Maximum
start 0 0.0 not yet assigned not yet assigned
0 12.5 yes 1 12.5 12.5 12.5
1 unknown no 1 12.5 12.5 12.5
2 15.0 yes 2 27.5 12.5 15.0
3 -2.0 yes 3 25.5 -2.0 15.0
4 10.5 yes 4 36.0 -2.0 15.0
5 unknown no 4 36.0 -2.0 15.0
6 14.0 yes 5 50.0 -2.0 15.0
7 10.0 yes 6 60.0 -2.0 15.0
complete 6 60.0 -2.0 15.0

The accepted mean is 60.0 / 6 = 10.0. Record the result alongside ResultValid, ValidCount, the input version and a completion sequence. A bare 10.0 cannot tell a consumer whether it came from eight channels, six channels or an old retained calculation.

Conceptual cyclic PLC scan with a bounded array workload and task time budget gauge
A bounded loop still needs a measured time budget; element count, element type, called functions and target CPU all influence execution time.

Control array work against the scan budget

An eight-element calculation is usually small, but the engineering method must survive when eight becomes eight hundred. A FOR loop normally completes all iterations during the current program invocation. It does not automatically spread work over future scans. If its upper limit depends on configuration or received data, the worst-case path can grow after commissioning.

Measure the task with representative data and simultaneous load. Include communication, HMI access, diagnostics and other scheduled programs. The watchdog is a final fault boundary, not the acceptable design target. Also measure the application deadline: a calculation can remain below the watchdog yet still make an output, alarm or sequence response too late.

Strategy Use when State that must be explicit Main risk
process all elements each scan bounded work is comfortably inside the measured budget input snapshot/version and result completion later array growth consumes the margin
process N elements per scan partial progress is acceptable and deadline spans scans current index, running result, data version, busy/done/error mixed datasets or consumers reading partial output
process on command in a slower task result is not needed every fast-control scan request/acknowledge, task ownership and result age priority/preemption and stale result assumptions
use a platform file instruction mode instruction semantics and mode match the need control structure, position, completion/error and retrigger policy copied examples hide vendor-specific multi-scan behavior
move work outside the PLC algorithm/data volume exceeds deterministic controller role interface contract, quality, timeout and fallback external result treated as always available or authoritative

Multi-scan chunking pattern

The following design sketch processes at most four elements per invocation. It restarts if the producer changes InputVersion during the calculation, so one result cannot silently combine two datasets.

IF Start AND NOT Busy THEN
    Busy := TRUE;
    Done := FALSE;
    WorkIndex := cFirstChannel;
    CapturedVersion := InputVersion;
    RunningSum := 0.0;
    RunningValidCount := 0;
END_IF;

IF Busy THEN
    IF InputVersion <> CapturedVersion THEN
        Busy := FALSE;
        DataChangedError := TRUE;
    ELSE
        ElementsThisScan := 0;
        WHILE (WorkIndex <= cLastChannel)
          AND (ElementsThisScan < 4) DO
            IF aSamples[WorkIndex].Valid THEN
                RunningSum := RunningSum
                            + REAL_TO_LREAL(aSamples[WorkIndex].Value);
                RunningValidCount := RunningValidCount + 1;
            END_IF;
            WorkIndex := WorkIndex + 1;
            ElementsThisScan := ElementsThisScan + 1;
        END_WHILE;

        IF WorkIndex > cLastChannel THEN
            IF RunningValidCount > 0 THEN
                Mean := LREAL_TO_REAL(
                    RunningSum / UDINT_TO_LREAL(RunningValidCount));
                ResultValid := TRUE;
            ELSE
                ResultValid := FALSE;
            END_IF;
            ResultVersion := CapturedVersion;
            Busy := FALSE;
            Done := TRUE;
        END_IF;
    END_IF;
END_IF;

Done needs defined semantics: one scan, latched until acknowledged, or a sequence number change. Start needs edge or handshake behavior so it cannot restart the operation continuously. Cancellation, startup and a mid-operation recipe change all need tests. For tightly coupled control data, copying the producer's completed staging buffer into a consumer snapshot may be simpler than aborting and retrying; use only a copy/synchronization mechanism supported by the target.

Move, copy, fill, search and compare instructions

Data-handling instruction names look similar across platforms, but the operands can use different units and the runtime may treat interruption or overlap differently.

Intent Rockwell Logix examples Siemens S7-1200/1500 examples IEC/CODESYS-style approach Verification focus
move one compatible value MOV MOVE typed assignment conversion, range and enable behavior
copy a contiguous block COP or CPS MOVE_BLK, UMOVE_BLK, MOVE_BLK_VARIANT where supported array/structure assignment or a bounded loop supported by the compiler length unit, extent, interruption and overlap
fill a block FLL FILL_BLK, UFILL_BLK bounded loop or supported initialization/assignment first/last destination and retrigger behavior
operate across a file/array FAL loop or appropriate array instruction bounded FOR loop/function all-at-once versus distributed work and fault state
search/compare FSC, compare instructions compare/array instructions by CPU/version bounded loop with explicit not-found result duplicates, first/last match and data quality
obtain array size/bounds SIZE for documented dimensions LOWER_BOUND, UPPER_BOUND where supported LOWER_BOUND, UPPER_BOUND for supported array forms dimension numbering and version support
Conceptual PLC memory operations showing move copy fill and a guarded overlapping-copy boundary
Block operations are compact, not self-proving: verify the unit of length, full source and destination extents, overlap rules and concurrent writers.

Rockwell COP and CPS are byte-oriented transfers with destination-element length

Current Rockwell documentation states that COP and CPS perform a straight byte-to-byte copy over contiguous memory. The Length operand represents the number of destination elements, so Length := 10 copies different byte counts when the destination is ten SINT, INT, DINT or structure elements. This is why “copy 10” is not a complete review statement.

CPS provides synchronous-copy behavior so other tasks or I/O updates do not change the participating data until the copy completes in the documented context. That consistency has a scheduling cost and is not a reason to use CPS blindly for large structures. The same official reference warns that a copy can write beyond a member array while remaining inside the containing base tag. Surround the destination with known sentinel fields during a bench test and prove that only the intended bytes change.

COP(SourceArray[0], DestinationArray[0], 10)

This conceptual call is correct only when both arrays, element types, lengths and controller family match the reviewed instruction documentation. Do not infer type conversion from a raw block copy. If the types differ, the byte pattern may remain intact while its interpreted value changes.

Siemens block moves distinguish interruptible and uninterruptible work

Current S7-1200 documentation lists MOVE_BLK, UMOVE_BLK, MOVE_BLK_VARIANT, FILL_BLK and UFILL_BLK among move operations. The U variants communicate an important design choice: uninterruptible work changes task responsiveness. Confirm supported CPU, operands, count semantics, optimized/non-optimized data restrictions and runtime behavior in the exact STEP 7 help for the target. Do not translate a Rockwell COP length directly into a Siemens count without re-deriving the contract.

Never assume overlapping-copy behavior

If source and destination ranges overlap, a forward element-by-element copy can overwrite a value before it is read. Some runtime functions act like a raw memory copy; others may define safe behavior only for certain directions or operands. Unless the target documentation explicitly guarantees the required overlap behavior, copy into a separate staging array and then commit it, or implement a direction-aware bounded algorithm with tests for both overlap directions.

For a recipe commit, a staging design is usually easier to audit:

  1. write and validate StagingRecipe;
  2. confirm range, units, permissions, product identity and checksum/version;
  3. copy or assign the complete staging value to ActiveRecipe through one defined owner;
  4. increment ActiveRecipeVersion; and
  5. let equipment logic acknowledge only the complete new version.

Math instructions begin with type and failure policy

The same arithmetic expression can produce different results depending on operand types, evaluation rules, destination conversion and controller fault configuration. Select types from the credible range and required resolution, not from habit.

IEC-family type Typical width Nominal range or role Array/math review question
SINT 8-bit signed -128 to 127 can a count, intermediate or imported byte exceed this?
USINT / BYTE 8-bit unsigned/bit string 0 to 255 is it a number or a raw bit/byte contract?
INT 16-bit signed -32,768 to 32,767 can addition or multiplication exceed the element range?
UINT / WORD 16-bit unsigned/bit string 0 to 65,535 can a negative engineering result occur?
DINT 32-bit signed -2,147,483,648 to 2,147,483,647 is it wide enough for the accumulator and subscript expression?
UDINT / DWORD 32-bit unsigned/bit string 0 to 4,294,967,295 will a subtraction underflow or be reinterpreted?
LINT / ULINT 64-bit integer large signed/unsigned range does the CPU/compiler support it efficiently and consistently?
REAL usually 32-bit float approximate wide-range numeric value is its precision adequate at the operating magnitude?
LREAL usually 64-bit float wider precision/range is target support and execution time acceptable?

The ranges above align with current Schneider IEC-type documentation, but memory layout and extensions remain platform-specific. A bit-string type such as WORD is not automatically interchangeable with an arithmetic UINT just because both occupy 16 bits in a given environment. Use explicit conversions when the design intends a semantic change.

Integer division truncates the fractional result

With integer operands and an integer destination, 7 / 2 commonly yields 3, not 3.5. A scaling expression such as Raw / 4095 * 100 can yield zero for nearly the entire input range if the first division truncates before multiplication. Options include:

  • deliberately promote the calculation to a floating type;
  • multiply before dividing after proving the wider intermediate cannot overflow; or
  • use a reviewed scaling function with explicit raw/engineering ranges and validity.

Each option has a different overflow and rounding surface. Raw * 100 / 4095 preserves more integer resolution but requires an intermediate wide enough for Raw * 100. Adding 0.5 before converting a positive float to an integer is not a universal rounding function, especially for negative values. Use the target's documented conversion or rounding operator and test positive/negative half-way cases.

Guard divide by zero and invalid domains before execution

IF Denominator <> 0.0 THEN
    Quotient := Numerator / Denominator;
    QuotientValid := TRUE;
ELSE
    QuotientValid := FALSE;
    DivideByZeroCount := DivideByZeroCount + 1;
END_IF;

The guard must use a comparison appropriate to the numeric contract. For a computed floating denominator, “not exactly zero” may still allow an impractically tiny divisor and an enormous result; use a documented minimum magnitude when the physical/model requirement supports one. Square-root and logarithm functions need their own domain checks. CODESYS provides project check functions such as the documented CheckDivInt family when included, but portable application logic should still state the required failure behavior.

Detect overflow before it becomes a plausible value

For signed addition, prove that operands cannot exceed the destination range, use a wider intermediate, or compare against safe limits before calculation. For multiplication, divide the safe limit by the magnitude of one operand where that method is valid, or calculate in a proven wider type. Do not rely on a wrapped result looking obviously wrong; 32,000 + 1,000 stored in a 16-bit signed result can become a plausible negative number that propagates into an index or setpoint.

Platform response varies. Rockwell exposes documented math status and fault behavior by instruction/controller context. CODESYS-derived targets can insert checking POUs. Siemens behavior depends on instruction, type, CPU and diagnostic context. Record the actual result, flag/fault and application response for the exact target instead of asserting one universal PLC rule.

Conceptual PLC numeric pipeline with integer width, floating point, overflow, truncation and division guards
Type conversion is part of the calculation: prove intermediate range, resolution, rounding and invalid-domain behavior before storing the destination.

Vendor dialect notes: translate the contract, not just the syntax

Vendor-neutral PLC engineering workbench comparing ladder file operations function blocks and Structured Text array loops
Equivalent intent does not imply equivalent instructions: re-prove bounds, count units, conversion, interruption, faults and timing on every target.
Concern Rockwell Logix Siemens S7-1200/1500 CODESYS / Schneider / TwinCAT family
common array base tag with declared dimension; zero-based indexing is typical ARRAY[low..high] OF type in supported data declarations ARRAY[low..high] OF type; explicit non-zero lower bounds supported
dynamic index tag/expression subscript symbolic indirect indexing and array components integer expression subscript
bound discovery SIZE reports a documented dimension size LOWER_BOUND/UPPER_BOUND where supported operators available for documented fixed/variable forms by product/version
out-of-range behavior documented major-fault cases including type 4 code 20 runtime access/diagnostic behavior depends on CPU and instruction implicit CheckBounds behavior is project/runtime specific
bulk copy COP, synchronous CPS MOVE_BLK, UMOVE_BLK, variant form where supported typed assignment, library function or bounded loop
fill/search/file math FLL, FSC, FAL, AVE, SIZE by language/mode appropriate move, compare, math and array instructions loops/functions; exact libraries vary
distributing work FAL/FSC documented modes or application state machine application/task design and available instructions application state machine/task design
portability trap destination-element Length and raw byte transfer count/variant/optimized data and interruptibility compiler-version bounds/check functions and implicit conversion

Rockwell Logix

Use current online help for the exact controller generation. FAL and FSC have modes that can operate all elements, a numerical quantity per scan, or incrementally under documented triggers. Their control structure is persistent state; retrigger, .POS, completion and error behavior belong in the requirement. A raw COP is not a type-aware recipe converter. Rockwell also documents that an out-of-range subscript can major fault, so validate operator/HMI/message-supplied indexes before the referenced instruction is evaluated.

Siemens STEP 7

Prefer symbolic array access over raw pointers where it meets the requirement. Siemens' current indirect-addressing documentation explicitly warns that runtime-calculated addresses can access wrong values or overwrite memory. Use LOWER_BOUND and UPPER_BOUND only where supported by the selected CPU/tool/instruction context. PEEK, POKE and variant operations expand the possible data surface; they require a stronger type, area and bounds contract than ordinary symbolic indexing.

CODESYS, Schneider Machine Expert and Beckhoff TwinCAT

These environments share substantial IEC-style syntax but are not one interchangeable runtime. Current CODESYS documentation shows variable-length ARRAY[*] parameters with LOWER_BOUND and UPPER_BOUND. Current Schneider documentation describes implicit boundary checks and shows a default check that clamps an invalid index; that is an example implementation, not permission to accept silent substitution. Beckhoff recommends consistent named array/loop bounds and documents CheckBounds options. Review the generated check POU, compiler settings and deployed target rather than assuming an IDE-family default.

Production pattern: staged recipe array and ring buffer

A recipe array should separate the editable candidate from the active settings. Each recipe needs identity, version, value limits and validation status. Equipment logic should not read a half-edited recipe merely because an HMI can write its fields.

Recipe state Writer Reader Required transition
stored library controlled recipe service selection function integrity/version acceptable
staging HMI or authorized import through one interface validator only every field, unit and permission checked
validated staging validator commit owner product identity and machine state permit commit
active commit owner only sequence/equipment logic complete atomic/synchronized assignment as supported
applied acknowledgement equipment logic HMI/batch system active version accepted at a defined safe point

For a circular event buffer, maintain WriteIndex, Count, Sequence and overflow policy explicitly. After writing one complete event, advance the index and wrap it only inside the bounds:

IF NewEvent THEN
    IF (WriteIndex >= cFirstEvent) AND (WriteIndex <= cLastEvent) THEN
        aEvents[WriteIndex] := PendingEvent;
        aEvents[WriteIndex].Sequence := NextSequence;

        IF WriteIndex = cLastEvent THEN
            WriteIndex := cFirstEvent;
        ELSE
            WriteIndex := WriteIndex + 1;
        END_IF;

        IF StoredCount < cEventCapacity THEN
            StoredCount := StoredCount + 1;
        ELSE
            BufferOverrun := TRUE; (* oldest event is being replaced *)
        END_IF;
    ELSE
        BufferIndexFault := TRUE;
    END_IF;
END_IF;

This is not a high-speed event recorder or a safety log. Define whether overwriting the oldest item is acceptable, how a reader obtains a coherent event, what happens during upload, and whether retained memory/endurance meet the requirement. A sequence number helps detect replacement or missed events; it does not authenticate the record.

Conceptual staged recipe commit and circular PLC event buffer with validity version and diagnostic states
Robust data structures expose ownership, validation, commit, version and overrun states instead of presenting a bare array as trustworthy.

Troubleshoot arrays and math by the first divergent boundary

Do not start by changing indexes online or clearing the destination array. Preserve the fault record, task state and input values first. A reset can remove the evidence that distinguishes an invalid external request from a loop defect.

Symptom First evidence to capture Likely boundary Controlled next check
controller/program faults on access exact fault type/code, routine/instruction, index expression and values out-of-range or overflowed subscript calculate the expression offline and test low/high guards on a bench
wrong element changes requested index, mapped equipment ID, source/destination extents index mapping or copy length place distinctive values and sentinels in every element
last element never updates declaration bounds and loop terminal value off-by-one loop trace first and final iteration with execution counters
adjacent structure field changes copy source, destination, base tag and length units raw block overwrite compare byte layout and use a same-type isolated destination
average is too low valid flags, accumulator type, operation order and valid count integer truncation or invalid-value policy replay a small hand-calculated dataset
result changes during calculation input version, task writers, I/O/communication updates incoherent snapshot stage a completed dataset and repeat under simultaneous load
scan time spikes element count, instruction mode, data type, called functions and task monitor unbounded/all-at-once work force maximum configured size in a representative test
divide or domain fault numerator, denominator, operation, conversion and runtime diagnostics missing invalid-domain guard test zero, near-zero, negative and maximum cases as applicable
recipe appears partially applied staging/active versions, writer cross-reference and commit handshake multiple writers or non-coherent copy write unique values to every field and interrupt at controlled points
ring buffer loses events write/read indexes, count, sequence gaps and overrun flag capacity or reader/writer ownership inject exactly capacity, capacity+1 and simultaneous read/write cases

Cross-reference every writer, including bulk operations

A leaf member may change even when it has no obvious assignment. Include array-indexed assignments, COP/CPS, FLL, FAL, block moves, structure assignments, HMI writes, messages, produced/consumed data, OPC UA access and initialization logic. On platforms with raw memory access or pointers, a normal tag cross-reference may not resolve every dynamic write; document that limitation and use controlled watchpoints/traces where available.

Use non-symmetric test patterns

Zeros and repeated values hide mapping defects. Populate test arrays with distinctive values such as 101, 202, 303 or byte patterns that do not look the same when swapped. Put known sentinel values immediately before and after the intended destination when the platform and safe test environment allow it. Then prove:

  • the correct first and final elements changed;
  • the number of changed elements matches the requirement;
  • adjacent fields stayed unchanged;
  • source values remained unchanged where required;
  • the consumer accepted only the completed version; and
  • invalid/partial data carried an explicit quality state.

Twelve acceptance tests for an array/data routine

Test Stimulus Required recorded result
1 lower valid index first element selected once; no neighbor changes
2 upper valid index final element selected once; no fault
3 one below lower access prevented and diagnostic set
4 one above upper access prevented and diagnostic set
5 empty/no-valid dataset no division, result invalid, count zero
6 all-positive and all-negative datasets minimum/maximum initialize from real samples, not zero
7 maximum credible arithmetic values no silent overflow; documented fault/substitute policy occurs
8 fractional and negative conversions documented rounding/truncation matches target behavior
9 full copy/fill length with sentinels exact intended extent changes; adjacent data remains intact
10 source changes during processing snapshot/version policy produces coherent result or explicit abort
11 maximum configured array under simultaneous normal load task execution and application deadline remain within limits
12 power/mode/download and recipe change initialization, retention, busy/done and commit states recover deterministically

Record CPU/catalog number, firmware, engineering-tool/compiler version, task configuration, array/type declarations, optimized/standard layout settings where relevant, test values, expected result, observed result, execution time and fault logs. The acceptance record should let a maintainer reproduce the decision without the original programmer.

PLC array, data and math answer map

Question Concise answer Boundary to retain
What is an array in a PLC? An indexed collection of same-type elements with declared bounds. Bounds, ownership and update coherence are project-specific.
How many elements are in ARRAY[0..7]? Eight; both lower and upper bounds are inclusive. Some vendors use a dimension count rather than declaration syntax.
How do I stop an array index fault? Validate the calculated index before any array reference executes. Runtime fault/clamp behavior differs by platform.
Should a PLC array start at 0 or 1? Use the explicit project convention and declared bounds consistently. Rockwell arrays are commonly zero-based; IEC tools can support other lower bounds.
How do I loop through an array? Use declared/named bounds or supported bound operators and measure worst-case execution. A FOR loop normally completes in the current invocation.
How do I average PLC array values? Sum accepted values in a suitable accumulator, count them, guard zero count and expose result validity. Invalid-value and snapshot policy must be defined.
What is the difference between move and copy? Move commonly transfers one typed value; copy/block operations transfer a specified extent. Conversion, length units and byte layout are vendor-specific.
What is Rockwell COP length? The documented Length is a number of destination elements for a contiguous byte copy. Element type determines the byte count.
What is the difference between COP and CPS? Both copy; CPS provides documented synchronous protection against participating data changes during the copy. It affects scheduling and is not automatically best for every size.
Why does PLC integer division lose decimals? Integer result types truncate the fractional part. Promotion and conversion rules vary by expression/platform.
Can arrays increase PLC scan time? Yes; work grows with elements, operations, data types and calls. Measure maximum configured work under representative load.
Are PLC arrays safe for recipes? Yes when staging, validation, commit, version, access and machine-state rules are explicit. A writable array alone is not a safe recipe transaction.

Frequently asked questions

What is a PLC array?

A PLC array groups multiple elements of the same declared type under one name and selects them by an index. Arrays are useful for channels, recipes, steps, alarms, samples and buffers. The declaration defines bounds and element type; the application must additionally define meaning, writer, quality, update and failure behavior.

How do you declare an array in Structured Text?

IEC-style tools commonly use syntax such as aValues : ARRAY[0..7] OF REAL;. CODESYS, Schneider and TwinCAT document that form, including explicit lower and upper limits. Exact support for initialization, variable-length parameters, bounds operators and derived types depends on the product and compiler version.

Is ARRAY[0..10] ten elements?

No. It contains eleven elements because both endpoints are included. Its valid indexes run from 0 through 10. Calculate the element count as upper - lower + 1, and test the two boundary indexes explicitly.

What happens when a PLC array index is out of range?

It depends on the controller and runtime. Rockwell documents major-fault cases for out-of-range Logix subscripts. CODESYS-family projects can use implicit check functions whose response may clamp, report or raise an exception. Siemens warns that runtime indirect addressing can access wrong data. Prevent the invalid reference in application logic and verify the target response.

Should I clamp an invalid PLC array index?

Only when the requirement explicitly accepts substituting the nearest element and the substitution is diagnosed. For recipes, device selection or commands, clamping can apply valid data to the wrong target. Rejecting the request, holding a defined safe application state and exposing a diagnostic is usually clearer.

How do I copy an array in a PLC?

Use a target-supported typed assignment, bounded loop or documented block-copy instruction. Prove the source and destination types, complete extents, length units, overlap, concurrency and task-time behavior. A raw byte copy does not perform semantic type conversion.

What do Rockwell COP and CPS do?

Both copy contiguous bytes from a source to a destination, with length expressed in destination elements in the current documentation. CPS prevents participating data from changing until the copy completes in its supported context. Validate controller generation, operands and scheduling impact before choosing either.

How do I prevent divide-by-zero in PLC math?

Test the denominator before the division and define an invalid-result path. For floating calculations, consider whether a very small nonzero divisor is also invalid for the physical requirement. Record a diagnostic and do not let an old destination look like a new valid result.

Why does my PLC average return a whole number?

The operands or destination may be integers, so the fractional result is truncated or converted. Promote deliberately to REAL/LREAL or use a documented fixed-point method, then verify rounding, range, target execution time and negative values.

Can a FOR loop cause a PLC watchdog fault?

Yes. A loop usually completes all iterations in the current invocation, and maximum work can exceed the task/watchdog budget. Keep bounds finite and configuration-limited, avoid uncontrolled WHILE conditions, measure the worst case, and split work over scans only with explicit progress and coherence state.

How do I make a multi-scan array calculation coherent?

Capture a producer version or create a supported snapshot before processing. If the source changes, restart, abort or continue only according to a written policy. Publish results with their own completed version and validity so consumers never treat partial accumulators as complete.

Can a PLC array or math routine be a safety function?

Ordinary array access and math code do not become safety-rated because they run in a PLC. A safety function requires the approved safety controller, permitted instructions and data types, certified architecture where applicable, fault response, timing analysis and validation against the risk assessment and relevant standards.

Primary sources, review record and limitations

Reviewed August 30, 2026. Use the documentation revision that matches the exact controller, firmware, engineering tool and compiler.

The six figures are original conceptual editorial illustrations generated for this guide. They are not vendor screenshots, memory-layout specifications, instruction symbols, timing guarantees or safety designs. Product and company names belong to their respective owners. This independent guide is not an IEC, Rockwell Automation, Siemens, CODESYS, Schneider Electric or Beckhoff publication.

This page does not authorize online edits, forced indexes, raw-memory writes, recipe changes, downloading to a running controller, clearing a fault without diagnosis, bypassing an interlock or altering a safety function. Only qualified and authorized personnel following the site risk assessment, hazardous-energy procedure, approved backup/change/rollback process, exact product manuals and validated safety lifecycle should modify an installed control system.

PPI

PLC Programming IO Editorial Team

Industrial automation education, references, and software testing

Sources TrackedVersions RecordedCorrections Accepted

The PLC Programming IO Editorial Team publishes sourced industrial-automation education and documents how material is reviewed, tested, and corrected. A team byline means the publisher is responsible for the page; it does not represent a fictional person or imply an engineering licence.

Coverage:

  • • PLC programming concepts and examples
  • • Vendor software tutorials and comparisons
  • • SCADA, HMI, protocols, and instrumentation
  • • Training, careers, and reference material

Review standard:

  • • Prefer primary and official sources
  • • Record software versions when material
  • • Separate tested facts from estimates
  • • Publish material corrections

Important scope note

This site provides education, not project-specific engineering approval. Safety, code, and compliance decisions require a qualified person with access to the actual machine and jurisdiction.