Overview
A lookup table maps an input value (in this case a temperature) to a pre-computed output value (a corresponding setpoint, density, viscosity, pH compensation, or similar process constant). On a Siemens SIMATIC S7-300, S7-400, S7-1200, or S7-1500 controller you implement this as either:
- An SCL array indexed by a fixed index range, with linear or binary search logic in a function block.
- A STEP 7 data block of REAL values accessed by pointer arithmetic in LAD/FBD/STL (classic STEP 7 V5.x).
- The TBL_FIND instruction from the S7-300/S7-400 extended instruction set, which searches a source range for a pattern match.
- The POLYGON function from the Siemens application examples, which linearly interpolates between adjacent table points when the input value falls between two tabulated keys.
This article covers all four approaches for a 40-point temperature table. The first three return an exact match (or no match); the fourth is the correct choice when the process variable can fall between two tabulated values and you need an interpolated output.
Prerequisites
- STEP 7 V5.7 (classic) or TIA Portal V16/V17/V18/V19/V20/V21 with S7-300, S7-400, S7-1200, or S7-1500 CPU firmware compatible with the installed TIA Portal version. See the Siemens TIA Portal version compatibility list.
- S7-SCL compiler license installed (S7-SCL V5.7 for STEP 7 V5.x, or the SCL option integrated in TIA Portal).
- For S7-300/S7-400: the Extended Instructions package containing the table functions (TBL_FIND, Table instructions). The catalog is part of the standard STEP 7 installation; no separate license is required.
- An S7 program in which the analog input is already normalized to engineering units (REAL) and the output is wired to a destination tag that can receive the looked-up REAL value.
- Optional: the OSCAT open-source library (free, no Siemens license) for a pre-built X-Y curve block. Verify the license terms before production deployment.
Method Comparison
| Method | CPU families | Matches exact key only | Interpolates between keys | Sort requirement | Typical scan time (40 points) |
|---|---|---|---|---|---|
| SCL array with linear scan | S7-1200, S7-1500, S7-300/400 | Yes | No (extend to interpolation) | No (unsorted works) | ~80-200 µs (S7-1500) |
| SCL array with binary search | S7-1200, S7-1500, S7-300/400 | Yes | No | Yes, ascending by key | ~30-60 µs (S7-1500) |
| STEP 7 classic DB + pointer | S7-300, S7-400 | Yes | No | No | ~150-400 µs (S7-400) |
| TBL_FIND (LAD/FBD) | S7-300, S7-400 | Yes (pattern match) | No | No | ~120-300 µs (S7-400) |
| POLYGON (interpolation) | S7-300, S7-400, S7-1200, S7-1500 | N/A | Yes (linear between points) | Yes, strictly ascending by key | ~100-250 µs (S7-1500) |
Method 1: SCL Array Lookup (TIA Portal)
This is the most maintainable solution on S7-1200 and S7-1500. Define a global data block with two parallel arrays (or one array of a user-defined struct) of length 40, and search by index.
Step 1: Create the data block
In TIA Portal, add a new global DB named DB_Lookup. Inside, declare a structure that holds the input keys (temperatures) and the output values:
DATA_BLOCK "DB_Lookup"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : EngAuto
FAMILY : Lookup
VERSION : 0.1
STRUCT
Key : ARRAY[1..40] OF REAL; // Temperature in °C
Value : ARRAY[1..40] OF REAL; // Lookup result (engineering units)
END_STRUCT;
END_DATA_BLOCK
Step 2: Populate the table in a startup OB
Use OB100 (warm restart) or OB101 (hot restart) to load the 40 pairs from the project or from a recipe DB. For fixed tables, hard-code them in OB100:
"DB_Lookup".Key[1] := 0.0; "DB_Lookup".Value[1] := 1.000;
"DB_Lookup".Key[2] := 5.0; "DB_Lookup".Value[2] := 0.998;
"DB_Lookup".Key[3] := 10.0; "DB_Lookup".Value[3] := 0.996;
// ... continue for all 40 points ...
"DB_Lookup".Key[40] := 195.0; "DB_Lookup".Value[40] := 0.879;
Step 3: Implement the lookup function block in SCL
FUNCTION_BLOCK FB_Lookup_Exact
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
iSearchValue : REAL; // Temperature in °C
END_VAR
VAR_OUTPUT
oResult : REAL; // Value from table
oIndex : INT; // Index of the match (0 = no match)
oFound : BOOL; // TRUE if exact match
END_VAR
VAR
i : INT;
END_VAR
BEGIN
oFound := FALSE;
oIndex := 0;
oResult := 0.0;
// Linear scan; switch to FOR loop with EXIT for early termination
FOR i := 1 TO 40 DO
IF "DB_Lookup".Key[i] = iSearchValue THEN
oResult := "DB_Lookup".Value[i];
oIndex := i;
oFound := TRUE;
RETURN;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
Step 4: Use a tolerance for noisy analog inputs
If the temperature comes from an RTD or thermocouple module, exact equality is rare. Wrap the comparison in a ±0.5 °C window:
IF ABS("DB_Lookup".Key[i] - iSearchValue) <= 0.5 THEN
For better noise immunity, average the AI input in the analog input driver block (e.g., 16-sample moving average) before calling the lookup.
Method 2: Classic STEP 7 DB Lookup (S7-300/S7-400, V5.x)
On STEP 7 V5.7 with an S7-300 or S7-400, you can build the table in a shared DB and use pointer arithmetic in STL to walk the entries.
Data block
DATA_BLOCK DB 100
TITLE = Temperature Lookup
STRUCT
Key : ARRAY[1..40] OF REAL;
Value : ARRAY[1..40] OF REAL;
END_STRUCT;
BEGIN
Key[1] := 0.0; Value[1] := 1.000;
// ... populate all 40 entries ...
END
STL scan
// In OB1, searchKey = MD100 (REAL), result -> MD104
L 40
T LW 0 // Loop counter
L P#DBX 0.0 // Pointer to Key[1]
T LD 2
LOOP: L DBD [LD 2] // Load Key[i]
L MD 100 // Load searchKey
==R
JC FOUND
L P#8.0 // Increment pointer by 8 bytes (REAL)
+D
T LD 2
L LW 0
LOOP LOOP
L 0.0
T MD 104 // No match -> 0.0
JU DONE
FOUND: L DBD [LD 2]
L P#320.0 // Offset from Key[1] to Value[1] = 40*8
+D
LAR1
L DBD [AR1,P#0.0] // Load Value[i]
T MD 104
DONE: NOP 0
Key to Value is 40 * 8 = 320 bytes. This is the single most common pointer bug in classic STEP 7 — verify it by cross-checking with the DB's offset view in the editor.
Method 3: TBL_FIND Instruction (S7-300/S7-400)
TBL_FIND (Find value in table) is in the Extended Instructions catalog under Table functions. It scans a source range (SRC) for entries that match a comparison pattern defined by CMD (1=EQ, 2=NE, 3=GT, 4=GE, 5=LT, 6=LE). The block returns the index of the first match, the number of matches, and the source/destination ranges used.
TBL_FIND interface
| Parameter | Type | Direction | Description |
|---|---|---|---|
| REQ | BOOL | IN | Start the search on a rising edge |
| SRC | VARIANT | IN | Pointer to the source range to search (must be ARRAY of BYTE/INT/DINT/REAL) |
| PATTERN | VARIANT | IN | Pointer to the comparison value (single element) |
| CMD | INT | IN | Comparison: 1=EQ, 2=NE, 3=GT, 4=GE, 5=LT, 6=LE |
| POSITION | DINT | OUT | Index of the first match (zero-based) |
| COUNT | DINT | OUT | Number of matches found |
| BUSY | BOOL | OUT | 1 while the block is running |
| ERROR | BOOL | OUT | 1 if the call returned an error |
| STATUS | WORD | OUT | Error/status code (0x0000 = no error, 0x8220 = invalid SRC, 0x8221 = invalid PATTERN, 0x8230 = data type mismatch, 0x8231 = CMD out of range) |
Wiring TBL_FIND in FBD
+-------+--------+
| | POSITION |
| +--------+
| | COUNT |
| +--------+
REQ ---| TBL_ | BUSY |
SRC ---| FIND | ERROR |
PATTERN -- | | STATUS|
CMD ------| +--------+
+-------+
Drive REQ with a one-shot pulse (use a rising-edge contact of your scan enable), set CMD = 1 (equal), and read POSITION. The returned index is zero-based, so add 1 to map it onto your 1..40 DB array.
Error handling checklist
| STATUS | Meaning | Remediation |
|---|---|---|
| 0x0000 | OK | Proceed; read POSITION |
| 0x8220 | Invalid SRC pointer | Verify the SRC pointer references a DB/array of compatible type |
| 0x8221 | Invalid PATTERN pointer | PATTERN must be a single element of the same type as SRC |
| 0x8230 | Data type mismatch | SRC and PATTERN must be the same elementary type |
| 0x8231 | CMD out of range | Set CMD to 1..6 |
BUSY before reusing the SRC/PATTERN pointers or before re-triggering with REQ. On S7-1500, TBL_FIND runs synchronously and BUSY is not used.Method 4: Polygon Interpolation for Non-Exact Values
When the process variable can fall between two tabulated keys, exact-match lookup will frequently return "no match." Use linear interpolation between the bracketing points. The Siemens application example 8803015 provides the standard POLYGON function block.
SCL implementation of linear interpolation
FUNCTION_BLOCK FB_Lookup_Interp
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
iX : REAL; // Input (e.g., temperature)
END_VAR
VAR_OUTPUT
oY : REAL; // Interpolated value
oOK : BOOL; // TRUE if iX is inside table range
END_VAR
VAR
i : INT;
x1, x2, y1, y2 : REAL;
END_VAR
BEGIN
oOK := FALSE;
oY := 0.0;
// Clamp below first key
IF iX <= "DB_Lookup".Key[1] THEN
oY := "DB_Lookup".Value[1];
oOK := TRUE;
RETURN;
END_IF;
// Clamp above last key
IF iX >= "DB_Lookup".Key[40] THEN
oY := "DB_Lookup".Value[40];
oOK := TRUE;
RETURN;
END_IF;
// Find bracketing pair (Key array is assumed ascending)
FOR i := 1 TO 39 DO
IF (iX >= "DB_Lookup".Key[i]) AND (iX < "DB_Lookup".Key[i+1]) THEN
x1 := "DB_Lookup".Key[i];
x2 := "DB_Lookup".Key[i+1];
y1 := "DB_Lookup".Value[i];
y2 := "DB_Lookup".Value[i+1];
// y = y1 + (y2 - y1) * (x - x1) / (x2 - x1)
oY := y1 + (y2 - y1) * (iX - x1) / (x2 - x1);
oOK := TRUE;
RETURN;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
Key[] is sorted ascending. If the table is loaded from a recipe or HMI, validate the order in OB100 and raise an alarm if not monotonic.
Performance and Memory Footprint
For 40 REAL pairs you need 40 × 8 bytes × 2 = 640 bytes of load memory. S7-1500 CPUs and S7-1200 CPUs from firmware V4.4 onward have ample work memory; on the S7-300 CPU 312 (work memory 32 KB) or the S7-400 CPU 412-1 (144 KB), 640 bytes is negligible. Watch out for:
- Optimized vs. non-optimized access: TIA Portal defaults to optimized symbolic access on S7-1200/S7-1500, which costs a few extra cycles for array indexing versus a direct DB number. This is the correct tradeoff for maintainability.
-
Volatile vs. retentive: Mark the table DB as retentive only if you intend to modify it from the HMI at runtime. Hard-coded engineering tables should be non-retentive so a CPU restart reinitializes from
OB100. - Cyclic load: Calling a 40-point linear scan every 1 ms on an S7-1516 is fine. On an S7-314 with 0.1 ms OB1 period, it consumes a measurable share of cycle time. Use a slower OB (e.g., OB35 at 100 ms) for the lookup call if your process allows it.
Step-by-Step Commissioning (40-Point Temperature Table)
- Decide whether the application needs exact match or interpolation. For setpoint conversion (e.g., RTD to density), use interpolation. For discrete process steps (e.g., recipe stage selection), use exact match.
- Build the source data. Export your engineering values from Excel as CSV; in TIA Portal use Tools > Data Block Generator with the CSV import to auto-fill the DB. In STEP 7 V5.x, paste values directly into the DB initial values view.
- Create
DB_Lookupwith the 40 keys and 40 values. - Implement the lookup FB in SCL (exact or interpolated) and compile the SCL source.
- In
OB100, populate the DB with your engineering values. Compile and download. - In
OB1(or OB35), call the FB and wire the analog-input REAL toiSearchValue/iX. - Connect a watch table to monitor
oIndex,oFound, andoResultduring commissioning.
Verification
| Test | Procedure | Pass criterion |
|---|---|---|
| Exact match in range | Force iSearchValue = 75.0 °C (a known key) |
oFound = TRUE, oIndex = matching index, oResult = expected value |
| Exact match, key not present | Force 77.5 °C (not in the table) |
oFound = FALSE, oIndex = 0, oResult unchanged from last valid value (or 0.0 if initialized) |
| Interpolation mid-range | Force 77.5 °C, with interpolation block |
oResult between Value[15] and Value[16] linearly; oOK = TRUE |
| Clamp below | Force -5.0 °C |
oResult = Value[1]; oOK = TRUE |
| Clamp above | Force 250.0 °C |
oResult = Value[40]; oOK = TRUE |
| TBL_FIND STATUS | Force a bad PATTERN pointer via watch table |
ERROR = TRUE, STATUS = 0x8221 |
| Cycle time | Read OB1/OB35 cycle time in online > diagnostics | Lookup call < 5% of total cycle time |
Troubleshooting Matrix
| Symptom | Likely cause | Remediation |
|---|---|---|
| Lookup always returns index 0 / not found | Key values not loaded (OB100 missing), or wrong DB instance | Online > Monitor > DB_Lookup — confirm Key[i] is non-zero; check OB100 wiring |
| Result jumps wildly | Analog input not normalized, or noise larger than tolerance window | Verify AI scaling in the analog input driver; widen tolerance or apply input filtering |
| TBL_FIND STATUS 0x8230 | PATTERN and SRC differ in data type | Ensure both reference the same elementary type (e.g., both REAL or both INT) |
| TBL_FIND STATUS 0x8220 | SRC pointer is not a typed ARRAY | Wrap the source DB in an ARRAY of the required type before passing to SRC |
| Interpolation result out of range | Key array not sorted ascending | Sort the DB values in OB100; add a monotonicity check that raises an alarm on violation |
| Compile error: "Incompatible types" on array index | INT used where DINT expected (or vice versa) | Match the index type to the array bounds; S7-1500 arrays can use DINT |
| Cycle time spike after enabling lookup | Linear scan in a fast OB on a small CPU | Move the call to OB35 (100 ms) or use binary search; on S7-1500, parallelize via a UDT |
| Download fails: "DB_Lookup is being accessed" | Background HMI polling on the table | Disable HMI tags pointing to the DB; redownload; re-enable |
FAQ
How many entries can a single SCL ARRAY lookup hold in TIA Portal?
The maximum ARRAY size is limited by CPU work memory. S7-1500 CPUs support arrays well beyond 10 000 elements; S7-1200 from firmware V4.4 also supports multi-thousand-element arrays. The 40-point temperature table described here consumes only 640 bytes and runs on any S7-300/S7-400/S7-1200/S7-1500 CPU.
Should I use exact match or linear interpolation?
Use exact match only when the process variable is quantized to your key values (e.g., a recipe number). Use linear interpolation when the input is a continuous measurement such as temperature, pressure, or flow. Interpolation is also the correct choice when the analog input has more resolution than the table.
Is TBL_FIND available on S7-1200 or S7-1500?
TBL_FIND is documented in the Extended Instructions catalog for S7-300 and S7-400 in the Siemens TIA Portal documentation. On S7-1200 and S7-1500 the table search is usually implemented in SCL as a FOR loop, which is more compact and benefits from the faster cycle time of these CPUs.
How do I load the 40 table values from an HMI recipe?
Create a recipe DB on the HMI, expose DB_Lookup.Key and DB_Lookup.Value as symbolic tags, and write both arrays from the recipe function. Mark DB_Lookup as retentive if the values must survive a warm restart; otherwise re-download the engineering values from OB100 on every restart.
What is the fastest way to implement a 40-point lookup on an S7-314?
Use a binary search in SCL on the pre-sorted Key array. With 40 entries the search converges in at most 6 iterations, keeping the cycle time well under 100 µs on a CPU 314. Alternatively, offload the lookup to a faster S7-1500 if the project is being upgraded.