PLC Arrays Let One Index Variable Address Any Stored Value

Daniel Price6 min read
HMI ProgrammingOther ManufacturerTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

A PLC array is one variable that holds several elements of the same data type, and each element is reached through an index that the program can change at runtime. For a drive with ten speed presets, you store the presets in Velo[1] through Velo[10]. The speed reference then becomes Velo[indice], and you change speed by writing a value from 1 to 10 into indice. You never add another IF branch.

How does an index value turn into a memory location?

Follow the request from the instruction to the data. The instruction Velo[indice] asks the runtime for an element. The runtime takes the array's base address, subtracts the declared lower bound from indice, and multiplies the result by the element size. That gives the element's position within one contiguous block. It works only because every element has the same type and size, so no element needs its own name. The index is an ordinary integer variable, so a HMI entry, a sequence step, a counter, or a loop variable can set it.

Access form Who sets the target When it resolves Typical use
Velo[3] Programmer, fixed at compile Compile time Same as a named tag
Velo[indice] Program logic or operator Every scan Preset selection, recipes
Array[i] inside FOR Loop counter Each loop pass, same scan Sums, averages, searches

Check: open the array in the online watch table and confirm the element count and lower bound match the declaration. Some platforms start at 0, while an ARRAY[1..10] declaration starts at 1.

How should the speed-preset table be declared so operator numbering matches the index?

Declare the bounds to match the numbering the operator already uses. If the HMI shows presets 1 to 10, declare 1 to 10. Then nobody has to add or subtract 1 anywhere in the program.


Load the ten presets as initial values or from the HMI. If the presets must survive a power cycle, mark them retentive. An array that is not retentive can reload zeros or initial values on a restart, and the drive then receives an unexpected reference.

Check: after a power cycle, read Velo[1] and Velo[10] online and confirm they still hold the configured presets.

How does the selected preset reach the drive without an out-of-range fault?

The index is the weak point in the path. If indice holds 0 or 11 while the bounds are 1..10, the address calculation points outside the block. Depending on the platform, the controller then faults, clamps the value, or reads or writes whatever memory lies next to the array. Clamp the request before it becomes an index:

indice := LIMIT(1, SpeedSelect, 10);
DriveSpeedRef := Velo[indice];
  1. Write SpeedSelect from the HMI or the sequence logic, never directly into indice.
  2. Clamp it with LIMIT, or reject out-of-range values and raise an operator message.
  3. Move Velo[indice] to the drive reference tag that the fieldbus or analog output scales and sends.
SpeedSelect written indice after clamp Element sent to drive
1 1 Velo[1]
7 7 Velo[7]
0 1 Velo[1]
11 10 Velo[10]

Check: force SpeedSelect to each value in the table and confirm that DriveSpeedRef and the drive's own reference display follow it.

What does "walking the array with a loop" actually execute?

A FOR loop sets its counter to each value in the range in turn and runs the body once per value, all within the same PLC scan. Using the counter as the index means one line of code processes every element:


With Array[1] := 10, Array[2] := 20 and Array[3] := 30, the passes run as follows:

Pass i Operation Suma after pass
1 1 0 + 10 10
2 2 10 + 20 30
3 3 30 + 30 60

The Suma := 0; line before the loop is mandatory in a PLC. The program runs every scan and Suma keeps its value between scans. Without the reset, the result grows by 60 on every scan instead of staying at 60. Also keep the loop bounds inside the declared array bounds. A loop running to 4 over a 1..3 array causes the same out-of-range access as a bad selector.

Check: monitor Suma across several scans. It must hold steady at 60, not climb.

How is a running average built from stored samples?

Averaging combines both access types. A trigger writes each new sample to the next slot with index := index + 1. A loop then sums the stored samples, and the program divides by the number of samples. Wrapping the write index turns the array into a ring buffer, so the average always covers the most recent samples.


Three details decide whether the code works:

  • The trigger must be a one-shot. A level signal writes a sample on every scan and fills the whole buffer within ten scans.
  • Divide by Count, not by 10. Otherwise the average reads low until the buffer has filled once.
  • The Count > 0 guard prevents a division by zero on the first scan after startup.

Check: inject a constant value on AnalogIn. Avg must equal that value from the first sample onward, and Idx must go back to 1 after 10.

Which other loops earn their place, and how is the full chain proven?

Any job that applies the same operation to many same-type values fits an array plus a loop:

Pattern Array content Loop action Recurring pitfall
Alarm summary BOOL alarm flags Set AnyAlarm if any element is TRUE; record the first index Not clearing AnyAlarm before the loop
Min/max search Measured values Compare each element with the running min/max Seeding min with 0 instead of element 1
Recipe table Arrays of setpoint structures Copy the selected recipe to the active setpoints Unclamped recipe number
Part tracking One element per station Shift elements down one slot per conveyor step Shifting in the wrong direction overwrites data

Every pass of every loop adds to scan time, because the whole loop runs before the scan finishes. Read the controller's maximum cycle time from its diagnostics after you add large loops, and compare it with the configured watchdog.

End-to-end check:

  1. Step SpeedSelect through 0, 1, 5, 10 and 11. Confirm that indice clamps, that DriveSpeedRef matches the expected Velo element, and that the drive's reference display matches.
  2. Run the summing loop with known values and confirm Suma holds 60 across consecutive scans.
  3. Feed a constant into the averaging buffer and confirm that Avg equals it before, during and after the first wrap of Idx.
  4. Record the maximum cycle time with all loops active and confirm it stays below the watchdog setting with margin.

FAQ

Why does my FOR loop sum keep increasing every PLC scan?

The accumulator keeps its value between scans, so each scan adds the full total again. Set it to 0 on the line immediately before the FOR statement, for example Suma := 0;.

Why does the PLC fault when my array index changes?

The index has gone outside the declared bounds, such as 0 or 11 for an ARRAY[1..10]. Clamp it with LIMIT(1, value, 10) before you use it, and read the diagnostic buffer to see which instruction faulted.

Why does my moving average read low right after startup?

The code divides by the full array size while only a few slots hold samples. Keep a sample count, capped at the array size, and divide by that count, with a guard for zero.

Why does a large FOR loop cause a cycle time or watchdog fault?

The whole loop runs inside one scan, so its execution time adds directly to the cycle. Shorten the loop, spread the work over several scans with a persistent index, or move the loop to a slower task. Then check the maximum cycle time against the watchdog.

How do I select a VFD speed preset from an array in Structured Text?

Store the presets in ARRAY[1..10] OF REAL, clamp the selector to 1-10, and assign DriveSpeedRef := Velo[indice];. Verify it by stepping the selector and comparing the result with the drive's reference display.

Back to blog