Overview
Field devices and legacy protocols frequently deliver status information as a single 16-bit WORD (for example, a digital input word from a remote I/O station, a status register from a frequency inverter, or a packed bit field received over Modbus). Downstream code, however, normally needs each bit as a discrete BOOL for visualization in HMI tags, interlocking in safety logic, or step enabling in a sequence. This article shows the canonical Siemens SCL pattern to break a WORD into sixteen BOOL outputs, and documents the equivalent STL and ladder techniques used on S7-300/400 and S7-1200/1500 controllers.
The reference pattern is the AT overlay — a SCL language element that lets you declare an alternative view over an existing variable without copying data. AT overlays are evaluated at compile time, produce zero runtime overhead, and are supported on every S7-1200 and S7-1500 firmware, as well as on S7-300/400 via STEP 7 V5.x SCL.
WORD Data Type and Bit Layout in the S7 Architecture
A WORD in the Siemens S7 data model is an unsigned 16-bit container occupying two bytes. The bit numbering is fixed by the architecture:
| Bit position | Significance | Weight (decimal) | Byte location |
|---|---|---|---|
| 15 | Most significant bit (MSB) | 32768 | High byte (bits 15..8) |
| 14 | — | 16384 | High byte |
| 13 | — | 8192 | High byte |
| ... | ... | ... | ... |
| 8 | Lowest bit of high byte | 256 | High byte (bit 0 of high byte) |
| 7 | Highest bit of low byte | 128 | Low byte (bits 7..0) |
| 1 | — | 2 | Low byte |
| 0 | Least significant bit (LSB) | 1 | Low byte (bit 0 of low byte) |
The S7 family is little-endian on the load-memory / process-image boundary, but the bit order within a word is always LSB = bit 0. A WORD in STEP 7 is a bit string, not a numeric value; use INT or DINT if signed arithmetic is required. The BOOL array produced by the patterns below preserves that order, so bitArray[0] = bit 0 (LSB) and bitArray[15] = bit 15 (MSB).
Prerequisites
- Controller: SIMATIC S7-1200 (firmware V4.2 or later) or S7-1500 (firmware V1.0 or later). The AT overlay is supported on both. S7-300/400 users need STEP 7 V5.5 SP2 or later with the SCL option installed.
- Engineering tool: TIA Portal V16 or later (V18 recommended for current firmware support). S7-300/400 users need SIMATIC Manager with SCL option installed.
- Project: A configured PLC device with an OB1 (or a cyclic interrupt OB) ready to call the new block.
-
Source tag: An input tag of type
WORDorUINTthat carries the packed bit field. -
Destination tags: Sixteen
BOOLtags, declared in a global DB, an instance DB, or directly at the FC output interface.
Reference: SIMATIC S7-1200 product page for firmware and TIA Portal compatibility.
Step-by-Step: SCL AT Overlay Implementation
The AT overlay is the cleanest, fastest, and most portable solution. It declares a STRUCT view (or an ARRAY OF BOOL) on top of an existing variable so the compiler reinterprets the memory rather than copies it.
Step 1 - Create a new function (FC)
In the project tree, expand Program blocks, right-click and select Add new block > Function (FC). Name the block WordToBits, pick SCL as the implementation language, and select Void as the return type. The block number must be unique within the CPU (for example 999, the same number used in the original STL example).
Step 2 - Declare the interface
Open the FC and switch to the SCL source. Enter the following declaration section:
FUNCTION "WordToBits" : Void
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
inWord : WORD;
END_VAR
VAR_OUTPUT
outBit00 : BOOL;
outBit01 : BOOL;
outBit02 : BOOL;
outBit03 : BOOL;
outBit04 : BOOL;
outBit05 : BOOL;
outBit06 : BOOL;
outBit07 : BOOL;
outBit08 : BOOL;
outBit09 : BOOL;
outBit10 : BOOL;
outBit11 : BOOL;
outBit12 : BOOL;
outBit13 : BOOL;
outBit14 : BOOL;
outBit15 : BOOL;
END_VAR
VAR
// AT overlay: reinterprets inWord as a structure of 16 BOOLs.
// No data is copied; the overlay shares the memory of inWord.
inBits AT inWord : STRUCT
bit0 : BOOL;
bit1 : BOOL;
bit2 : BOOL;
bit3 : BOOL;
bit4 : BOOL;
bit5 : BOOL;
bit6 : BOOL;
bit7 : BOOL;
bit8 : BOOL;
bit9 : BOOL;
bit10 : BOOL;
bit11 : BOOL;
bit12 : BOOL;
bit13 : BOOL;
bit14 : BOOL;
bit15 : BOOL;
END_STRUCT;
END_VAR
With { S7_Optimized_Access := 'TRUE' } the block stores its data in the optimized symbol area. AT overlays on optimized blocks are allowed as long as the base variable is a tag (input, output, in/out, static, or global) — never a literal or a constant.
Step 3 - Implement the code section
BEGIN
outBit00 := inBits.bit0;
outBit01 := inBits.bit1;
outBit02 := inBits.bit2;
outBit03 := inBits.bit3;
outBit04 := inBits.bit4;
outBit05 := inBits.bit5;
outBit06 := inBits.bit6;
outBit07 := inBits.bit7;
outBit08 := inBits.bit8;
outBit09 := inBits.bit9;
outBit10 := inBits.bit10;
outBit11 := inBits.bit11;
outBit12 := inBits.bit12;
outBit13 := inBits.bit13;
outBit14 := inBits.bit14;
outBit15 := inBits.bit15;
END_FUNCTION
Step 4 - Call the FC from OB1
Open OB1, insert a new network, drag WordToBits from the project tree to the network, and connect the input to a tag of type WORD (for example "Data".statusWord from a Modbus holding register). Connect each outBitxx to the BOOL tags that your HMI or downstream logic uses.
Reference: Siemens Industry Online Support for SCL language reference and block attributes documentation.
Alternative SCL: Array of BOOL Overlay
For applications that pass the resulting bit pattern into a FOR loop (for example to drive sixteen output coils, to build a 16-bit mask, or to feed an HMI array tag), an ARRAY overlay is more compact and indexable:
FUNCTION "WordToBitsArray" : Void
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
inWord : WORD;
END_VAR
VAR_OUTPUT
outBits : ARRAY[0..15] OF BOOL;
END_VAR
VAR
inBits AT inWord : ARRAY[0..15] OF BOOL;
END_VAR
BEGIN
// One move: the array view shares memory with outBits after a single assignment.
outBits := inBits;
END_FUNCTION
This version produces an array you can scan with a FOR i := 0 TO 15 DO loop. With optimization enabled, the compiler typically generates a single 16-bit block move.
Reference: SIMATIC S7-1500 product page for the SCL AT-view declaration rules.
STL Implementation Using the L-Stack Trick
The classic S7-300/400 STL approach exploits the fact that the local data area of an FC/FB is a contiguous scratch memory starting at LW0. By ordering the TEMP variables deliberately, you can transfer a 16-bit word into LW0 and read its bits directly as BOOL temps.
FUNCTION FC 999
TITLE = WordToBits
VERSION : 0.1
VAR_INPUT
in : WORD;
END_VAR
VAR_OUTPUT
out0 : BOOL; out1 : BOOL; out2 : BOOL; out3 : BOOL;
out4 : BOOL; out5 : BOOL; out6 : BOOL; out7 : BOOL;
out8 : BOOL; out9 : BOOL; out10 : BOOL; out11 : BOOL;
out12 : BOOL; out13 : BOOL; out14 : BOOL; out15 : BOOL;
END_VAR
VAR_TEMP
// DECLARATION ORDER MATTERS: tmp0..tmp15 occupy the bits of LW0.
// In S7-300/400, BOOL temps are packed into bytes from low to high.
// Layout: byte 0 = tmp0..tmp7 (LSB = tmp0), byte 1 = tmp8..tmp15.
tmp0 : BOOL; tmp1 : BOOL; tmp2 : BOOL; tmp3 : BOOL;
tmp4 : BOOL; tmp5 : BOOL; tmp6 : BOOL; tmp7 : BOOL;
tmp8 : BOOL; tmp9 : BOOL; tmp10 : BOOL; tmp11 : BOOL;
tmp12 : BOOL; tmp13 : BOOL; tmp14 : BOOL; tmp15 : BOOL;
END_VAR
BEGIN
NETWORK
TITLE = Move input to local word 0
L #in;
T LW 0; // LW 0 now mirrors the 16 bits of #in.
NOP 0;
NETWORK
TITLE = Map bit 0
U #tmp0;
= #out0;
// (Repeat for bits 1..15 in subsequent networks.)
END_FUNCTION
VAR_TEMP block determines the bit layout in LW0. If you reorder the temps (for example sort them alphabetically), the assignment T LW 0 will put the wrong bit into tmp0. Do not insert any VAR_TEMP BOOL above tmp0 unless you also move T LW 0 to a different base address. To match the bit order in the original example (lowest bit in the highest-numbered temp), simply declare tmp0 first and tmp15 last.On S7-1200 and S7-1500 this trick is not necessary and is in fact discouraged because the optimized block storage means the compiler is free to re-lay the temp area. Use the AT overlay for those CPUs.
Reference: SIMATIC S7-1200 product page for the optimized-block rules that make the L-stack trick obsolete on the newer CPUs.
Ladder Logic Implementation
On a programming environment where SCL is not licensed, the same function can be built in KOP/FBD by extracting each bit with the AND word operation. The pattern is identical to a typical "bit de-multiplexer":
NETWORK 1 // Extract bit 0
L #inWord;
L W#16#0001;
UW ; // AND with mask 0x0001
SRW 1; // shift right 1 position (optional, to normalize)
T #outBit00; // result is 0 or 1 in INT
Repeat the pattern with masks W#16#0002, W#16#0004, ..., W#16#8000 and a right shift of n positions to land each bit in outBit0n. This ladder form executes in roughly 2 µs per bit on an S7-1516, fully equivalent to the AT overlay, but it costs 16 networks and 16 scratch words.
For a fully graphical representation, TIA Portal's LAD editor also offers the Word AND and Word shift right boxes. The KOP editor on TIA Portal V18 supports the AT view via the Slice access notation, allowing "tag".%X0 through "tag".%X15 as direct bit references on a WORD tag — no FC needed.
| Pattern | Networks needed | Code body (lines) | Scan cost on S7-1516 | Scan cost on S7-1212 |
|---|---|---|---|---|
| SCL AT overlay (struct) | 1 | 16 assignments | < 1 µs (optimized) | 5-10 µs |
| SCL AT overlay (array) | 1 | 1 assignment | < 1 µs | 3-7 µs |
| STL L-stack trick | 17 (1 move + 16 U=/=) | 34 STL lines | 2-4 µs | 15-25 µs |
| LAD word AND + shift | 16 | 16 networks of 4 boxes | 30-40 µs | 200-300 µs |
Slice access %X0..%X15
|
0 (inline in caller) | 16 references | < 1 µs | 3-6 µs |
Reference: Siemens Industry Online Support for the LAD/FBD editor documentation and the SCL language reference.
FC vs FB Selection
Use an FC unless you specifically need a static instance DB. The decision matrix:
| Criterion | FC (recommended) | FB with instance DB |
|---|---|---|
| Static variables needed | No | Yes |
| Re-entrancy | Yes (multi-instance friendly) | No (each call needs its own DB) |
| Memory cost per call | 16 bytes of L-stack per call | ≥ 32 bytes of work memory + instance DB |
| Retain behavior | None (output cleared at cycle end) | Optional via RETAIN qualifier |
| Use case | One-shot conversion, called once per cycle | Multi-instance use, retention across cycles, or when intermediate values must be remembered |
For a bit-split function, the FC is the right choice in 95% of cases. The L-stack overhead is irrelevant (a few microseconds at the OB1 call site) and you avoid allocating an instance DB for what is essentially a pure function.
Reference: SIMATIC S7-1500 product page for the FC/FB selection guide.
Bit Ordering, Modbus, and Cross-Platform Caveats
Several scenarios demand attention to bit ordering:
- Modbus master: A Modbus holding register returns 16 bits numbered 0 (LSB) to 15 (MSB) when interpreted as an unsigned integer. The AT overlay above preserves this order; no swap is required.
-
PROFIBUS / PROFINET packed I/O: Slot-level packed I/O arrives byte-wise. The first byte received is the low byte of the
WORD, the second byte is the high byte. Bits 0..7 of theWORDlive in the first byte received from the device — exactly what the overlay shows. -
Big-endian field device: Some Modbus slaves document the high byte as the "first" register. Use a
WORDtoWORDswap (rotate word left/right by 8) before applying the overlay. TIA Portal offers theROTATEinstruction in the Word logic palette. - Safety-related bit fields: If the source is a fail-safe (F-) input word, do not perform the split inside the F-runtime group. Hand the F-word to the standard runtime group as a non-safety tag and split it there, otherwise the F-system will reject the unknown instruction.
-
Sign extension with
INT: If the base tag isINTinstead ofWORD, the bit layout is identical, but reading bits 0..14 is fine — bit 15 is the sign bit. UseWORDwhen the bit pattern is a status field, not a numeric value.
"tag".%X0 through "tag".%X15) is the IEC 61131-3 standard way to address bits within a word. It is functionally equivalent to the AT overlay but the slice is part of the tag declaration, not a block-local view.Common Use Cases (Modbus, PROFINET, HMI)
| Source | Typical word contents | Recommended pattern | Notes |
|---|---|---|---|
| Modbus holding register | Status word from a VFD or sensor | SCL AT overlay (array) | Index 0..15 maps directly to the 16 bits of the register |
| PROFINET slot 0 input word | 16 digital inputs from a remote station | Slice access "DI".%X0..%X15
|
No FC needed; reference bits directly in OB1 |
| PROFIBUS DP diagnostic word | Station status bits | STL L-stack trick (S7-400 only) | Use only when the diagnostic tag is non-optimized |
| WinCC tag list | 16 HMI bits driven by one internal word | SCL AT overlay (struct) | Connect each outBitxx to an HMI tag of the same name |
| IEC 60870-5-104 status word | Quality + validity flags | Slice access with mask | Mask the reserved bits with a AND before display |
For HMI integration, expose the sixteen outBitxx outputs as separate HMI tags in the WinCC tag management; the HMI can then bind them to individual indicators or to a 16-position bitmap. Do not bind the original WORD to the HMI directly — splitting it on the PLC side keeps the HMI configuration simple and lets other blocks reuse the same bit pattern.
Verification and Commissioning
After downloading the block to the CPU, validate the conversion with a watch table and a forced pattern. The procedure is identical for S7-300, S7-1200 and S7-1500:
- Open Watch and force tables > Add new watch table.
- Add the input
WORDtag and the sixteenBOOLoutputs. - Click Modify > Modify with explicit values on the input tag. Enter
16#AAAA(binary1010_1010_1010_1010) and apply. The expected pattern isoutBit15, outBit13, outBit11, outBit9, outBit7, outBit5, outBit3, outBit1= TRUE; the rest FALSE. - Repeat with
16#5555(binary0101_0101_0101_0101). Expect the inverse of the previous pattern: even-numbered bits TRUE, odd-numbered bits FALSE. - Test
16#0001(only bit 0 TRUE),16#8000(only bit 15 TRUE), and16#FFFF(all TRUE). Three passes is the minimum for sign-off. - Capture the OB1 scan time before and after adding the block. On an S7-1516 the increase is below 1 µs; on an S7-1212 it is between 5 µs and 10 µs.
- Optionally write a self-test in OB100 (startup) that loads
16#0001,16#0002,16#0004...16#8000in sequence and asserts that only the corresponding output is TRUE; a mismatch halts the CPU and surfaces the error in the diagnostic buffer.
Reference: SIMATIC S7-1200 product page for the "Monitoring and modifying tags" section in the system manual.
Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic step | Remedy |
|---|---|---|---|
| Compile error "AT overlay not allowed on optimized tag" | Base variable is a literal, a constant, or a non-optimized block tag | Open the block interface, confirm inWord has the {S7_Optimized_Access} attribute or lives in an optimized DB |
Add a static tag to an optimized DB and re-declare the AT overlay on it |
| Bits come out in reverse order (bit 0 reads as MSB) | Declaration order of BOOL fields in the STRUCT was reversed by the user |
Inspect the generated STL with View > STL; check that the first field of the AT struct is the LSB | Reorder the fields so bit0 is the first element of the STRUCT
|
| All outputs read FALSE regardless of input | AT overlay placed on a VAR_TEMP with the L-stack trick on a non-optimized FC |
Watch LW0 online; if it tracks the input but the BOOL temps stay FALSE, the declaration order is wrong |
Re-order the VAR_TEMP block so tmp0 is declared first; or migrate the FC to SCL with AT overlay |
| Compile error "Bit field too large" | Trying to AT-overlay a BYTE (8 bits) with 16 BOOL fields |
Check the size: 16 BOOL = 2 bytes, must match the base size | Declare the base as WORD or INT (2 bytes) for 16 bits, or DWORD for 32 bits |
| Online value of input is correct, output bits flicker | Input word is being overwritten by the same FC in a re-entrant call | Cross-reference the FC to detect a second call site | Convert the FC to an FB with multi-instance capability or guard the call against re-entrancy |
| Safety CPU rejects the block | F-runtime does not allow AT overlay on F-tags | Check the F-compilation log for the offending block | Move the split to a non-safety block in the standard runtime group and route the F-word via a transfer area |
Slice access "tag".%X0 produces a compile error |
TIA Portal version is older than V18, or the tag is not of an elementary type | Check the TIA Portal version and the tag data type | Upgrade to TIA Portal V18 or replace the slice access with an AT overlay |
| WinCC shows bits in reverse | HMI tag list was generated with the wrong endianness | Open the HMI tag properties, check the byte order | Re-generate the HMI tags from the PLC, or reorder the bits manually in the HMI tag list |
Reference: Siemens Industry Online Support for the SCL compile error reference and the safety-runtime programming rules.
FAQ
Why does the AT overlay produce 16 BOOL outputs from a single WORD with zero CPU load?
The AT overlay reinterprets the memory of the base variable at compile time; the SCL compiler generates a bit-slice access that points at the same address as the original WORD. No data copy occurs, so the block adds essentially no execution time — under 1 µs on an S7-1516 with optimization enabled.
Can I use the AT overlay on a DWORD to get 32 bits, or on a BYTE for 8 bits?
Yes. Declare inDWord : DWORD; and overlay a STRUCT with 32 BOOL fields, or ARRAY[0..31] OF BOOL AT inDWord. For 8 bits use BYTE and 8 fields, or ARRAY[0..7] OF BOOL. The pattern is identical regardless of width.
Is the L-stack trick from the classic STL solution still required?
No. On S7-300/400 the L-stack trick is the only STL solution that avoids 16 bit-mask networks, but on S7-1200/S7-1500 the optimized block storage makes it unnecessary. The SCL AT overlay is preferred on every modern CPU and is the only officially documented pattern in current TIA Portal manuals.
How do I handle a 16-bit word coming from a Modbus slave that documents bits 1..16 instead of 0..15?
Subtract 1 from the documented bit number and map it to bitArray[n-1]. The wire order is identical; only the human-readable numbering differs. If the slave returns the word with the high byte first, swap the two bytes with the Rotate instruction before applying the overlay.
Can I split a WORD inside a fail-safe program?
The F-runtime group (yellow F-blocks) only accepts F-certified instructions. The AT overlay itself is allowed on F-tags, but the downstream F-tag you split into must be declared in the F-DB. If in doubt, transfer the F-word to a non-safety DB in the standard runtime group and split it there, exactly as you would for any non-F field value.