1. Problem Overview
The Bool_to_Word_&_Text function block (FB) is a common aggregator pattern in SIMATIC S7-1200 and S7-1500 projects: it accepts up to eight Boolean inputs, packs them into a WORD for compact HMI tag polling, and emits descriptive STRING tags that name whichever input is active. The pattern saves HMI point-count and produces human-readable diagnostics on a Comfort Panel, WinCC Unified, or a third-party SCADA bridge.
Engineers typically wire the FB inputs with Normally Open (NO) contacts of output coils (Q addresses) that are set in several logic networks upstream — manual mode, automatic mode, setup mode, and so on. The observed defect is that the FB's Boolean inputs read TRUE in one scan cycle and FALSE in another, even though the corresponding output coil is held TRUE by its own network. The Word output flickers and the descriptive text oscillates between the active label and a blank string.
The defect is not in the FB itself. It is in the upstream coil structure: the same output tag is being written by more than one -( )- assignment coil in different networks. Siemens' LAD/FBD editor tolerates this layout at compile time but the runtime semantics of the last assignment in the scan win, and the intermediate Q bit does not reflect a stable Boolean union of the conditions that should drive it.
2. Root Cause: Duplicate Coil Assignment Semantics
Siemens SIMATIC S7-1200 Programmable Controller system manual defines a single output coil -( )- as a write instruction that overwrites the referenced Boolean tag with the result of the rung's logical combination. When two or more networks contain -( )- instructions that target the same tag, the Ladder/FBD editor generates a sequential set of MOVE-style assignments to that tag in the compiled STL/SCL.
At runtime, every network is processed in the order it appears in the OB (typically OB1). If network 1 sets "SetupModeActive" to TRUE and network 7 sets the same tag to FALSE because its trigger condition was previously satisfied in a prior scan, the value the FB sees at the contact sample point depends on which network evaluated last. The bit is therefore not a stable union of all conditions that "want it on"; it is the value of the last condition that was evaluated.
| Network | Condition | Coil -( )- target |
Runtime effect |
|---|---|---|---|
| Network 1 | Setup mode request TRUE | Q0.1 | Writes Q0.1 = TRUE |
| Network 2 | Manual mode request TRUE | Q0.1 | Writes Q0.1 = TRUE (duplicate) |
| Network 3 | Automatic mode request TRUE | Q0.1 | Writes Q0.1 = TRUE (duplicate) |
| Network 4 | No active request, bit clear logic present | Q0.1 | Overwrites Q0.1 = FALSE |
The Bool_to_Word FB's i_00 through i_07 inputs are sampled after the entire OB has executed. The value they read is the result of the last write, not the union. This is sometimes called "last-writer-wins" or "scan-order coupling." It is documented behavior in the IEC 61131-3 standard and is enforced by every major PLC vendor, not just Siemens.
3. Why PLCSim Behavior Misleads the Engineer
PLCSIM simulates the S7-1200/S7-1500 CPU instruction set and the cyclic OB execution order with full fidelity. The duplicate-coil defect therefore reproduces in PLCSIM exactly as it appears on the physical CPU. The misleading part is the timing: in PLCSIM the scan is fast and deterministic, so the engineer may briefly observe the expected TRUE before the last assignment overwrites the bit. Watching the FB inputs in a watch table may show the last value written, not the value the engineer mentally associates with the triggering coil.
This causes engineers to conclude that "the FB is broken" or "TIA Portal has a bug." In reality, the FB is reading a tag that has been overwritten in the same OB scan. The hardware does not change this; it only changes the visible scan latency.
4. The Solution Architecture: Intermediate Memory Coils
The correct pattern, used across all major PLC brands, is to allocate a separate BOOL tag in a data block (DB) or in the M (memory) area for each condition that should drive the output, then unify those tags in a final network using parallel NO contacts to drive the actual output. Each condition writes only its own intermediate bit; the output coil is driven by the OR of all intermediate bits.
| Element | Type | Address / DB | Use |
|---|---|---|---|
| Setup mode request | BOOL | DB_HMI.i_SetupReq | Set by Setup mode logic only |
| Manual mode request | BOOL | DB_HMI.i_ManualReq | Set by Manual mode logic only |
| Auto mode request | BOOL | DB_HMI.i_AutoReq | Set by Automatic mode logic only |
| Aggregated output | BOOL | DB_HMI.o_ModeActive | Final OR of all requests |
| Bool_to_Word input 0 | BOOL | DB_HMI.o_ModeActive | Stable bit read by FB |
The Bool_to_Word FB then reads the aggregated tag, not the raw request bits. The aggregator tag is written exactly once per scan, by a single network that contains parallel NO contacts of all the intermediate request bits. Because the assignment is unique, the "last-writer-wins" ambiguity disappears and the FB sees a stable Boolean value.
5. Implementing the Bool_to_Word & Text FB
Below is a TIA Portal V17 / V18 / V19 compatible SCL implementation of an 8-input aggregator FB. The function block accepts eight Boolean inputs, builds a bit-packed WORD by left-shifting each input into its corresponding bit position, and emits an array of eight STRING[32] tags. The descriptive text is the engineer's choice and is held in the FB's INPUT interface so it can be localized from the HMI dictionary without recompiling the FB.
FUNCTION_BLOCK "Bool_to_Word_&_Text"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
i_00 : BOOL; // bit 0
i_01 : BOOL; // bit 1
i_02 : BOOL; // bit 2
i_03 : BOOL; // bit 3
i_04 : BOOL; // bit 4
i_05 : BOOL; // bit 5
i_06 : BOOL; // bit 6
i_07 : BOOL; // bit 7
s_Text0 : STRING[32];
s_Text1 : STRING[32];
s_Text2 : STRING[32];
s_Text3 : STRING[32];
s_Text4 : STRING[32];
s_Text5 : STRING[32];
s_Text6 : STRING[32];
s_Text7 : STRING[32];
END_VAR
VAR_OUTPUT
w_Packed : WORD;
s_Active : STRING[32];
b_AnyActive : BOOL;
END_VAR
VAR_TEMP
t_Word : WORD;
t_Idx : INT;
END_VAR
BEGIN
// Build the bit-packed WORD from individual Boolean inputs.
// SHL performs a logical left shift; OR accumulates the bits.
t_Word := 0;
IF #i_00 THEN t_Word := t_Word OR WORD#16#0001; END_IF;
IF #i_01 THEN t_Word := t_Word OR WORD#16#0002; END_IF;
IF #i_02 THEN t_Word := t_Word OR WORD#16#0004; END_IF;
IF #i_03 THEN t_Word := t_Word OR WORD#16#0008; END_IF;
IF #i_04 THEN t_Word := t_Word OR WORD#16#0010; END_IF;
IF #i_05 THEN t_Word := t_Word OR WORD#16#0020; END_IF;
IF #i_06 THEN t_Word := t_Word OR WORD#16#0040; END_IF;
IF #i_07 THEN t_Word := t_Word OR WORD#16#0080; END_IF;
#w_Packed := t_Word;
#b_AnyActive := t_Word <> 0;
// Resolve the active label. Lowest-numbered active input wins.
#s_Active := '';
FOR #t_Idx := 0 TO 7 DO
IF (t_Word AND SHL(WORD#16#0001, #t_Idx)) <> 0 THEN
CASE #t_Idx OF
0: #s_Active := #s_Text0;
1: #s_Active := #s_Text1;
2: #s_Active := #s_Text2;
3: #s_Active := #s_Text3;
4: #s_Active := #s_Text4;
5: #s_Active := #s_Text5;
6: #s_Active := #s_Text6;
7: #s_Active := #s_Text7;
END_CASE;
EXIT;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
The key insight is that the FB does not need to know where the Boolean came from. It only sees the OR-ed result. As long as the upstream logic produces a single, deterministic BOOL per input pin, the FB behaves identically in PLCSIM, on the real CPU, and in every engineering environment that supports Siemens SCL conversion operators.
6. SCL Conversion Instructions for Type-Clean Aggregation
When the Boolean inputs are not the same data type — for example, an I input is BOOL while a tag pulled from a non-optimized DB is BOOL in legacy layout — the engineer can use the explicit SCL conversion operator _BOOL_TO_WORD(...) or the generic _TO_ form documented in the TIA Portal help. The conversion operator generates the exact same bit pattern as the SHL/OR approach above but is more readable for engineers new to bitwise packing.
// Generic conversion form (SCL)
#w_Packed := _TO_(
BOOL_TO_WORD(#i_07) * 16#0080 OR
BOOL_TO_WORD(#i_06) * 16#0040 OR
BOOL_TO_WORD(#i_05) * 16#0020 OR
BOOL_TO_WORD(#i_04) * 16#0010 OR
BOOL_TO_WORD(#i_03) * 16#0008 OR
BOOL_TO_WORD(#i_02) * 16#0004 OR
BOOL_TO_WORD(#i_01) * 16#0002 OR
BOOL_TO_WORD(#i_00) * 16#0001 );
Per the Siemens SCL conversion operations reference, the _TO_(in) form performs an implicit type check and raises a compile-time diagnostic when the target type does not support the source. Use the explicit BOOL_TO_WORD form to silence that diagnostic in libraries that must compile against multiple firmware targets.
7. Ladder Logic Pattern: Multi-Mode Output Aggregation
The pattern below shows the correct LAD layout for a three-mode output. Each mode writes its own intermediate flag; the final network drives the physical output with parallel NO contacts. This is the structure that must replace the duplicate-coil layout that caused the original defect.
Network 1 — Setup mode request
| i_SetupKey i_SafetyOK i_PowerOn |
|------|------|------|---( #i_SetupReq )---|
Network 2 — Manual mode request
| i_ManKey i_SafetyOK i_PowerOn |
|------|------|------|---( #i_ManualReq )---|
Network 3 — Automatic mode request
| i_AutoRun i_SafetyOK i_PowerOn |
|------|------|------|---( #i_AutoReq )---|
Network 4 — Aggregated output (single coil, parallel contacts)
| #i_SetupReq |
|------|------|
|---( #o_ModeActive )---|
| #i_ManualReq |
|------|------|
| #i_AutoReq |
|------|------|
The #o_ModeActive tag is now written by exactly one coil instruction. The Bool_to_Word FB can read it directly. If interlocks require mode exclusivity, insert an XOR or mutual-exclusion network upstream — never on the aggregated output.
8. HMI Wiring of the Aggregated Tag
Once the aggregated BOOL is stable, wire the Bool_to_Word FB and the HMI as follows:
- Create a
DB_HMIdata block with optimized access and add eight intermediate flag tags and one output tag (see Section 4 table). - Place the Bool_to_Word_&_Text FB instance as a single-call instance in OB1 (or in a cyclic OB at the desired priority).
- Wire each of the eight intermediate flag contacts to the corresponding FB input pin in the call interface.
- Connect the FB's
w_Packedto a WinCC Comfort tag with display formatHEXorBIN; the bit pattern shows which modes are active. - Connect the FB's
s_Activeto an HMI text field; it updates on every scan and reflects the lowest-numbered active input. - For multiple simultaneous active inputs, build a multipage HMI faceplate that decodes the
w_Packedword with eight visibility animations.
9. Verification and Commissioning Steps
After applying the intermediate-flag pattern, verify with the following checklist before re-commissioning the line.
- Compile the project in TIA Portal and confirm zero "Duplicate coil assignment" warnings in the information window.
- Open the cross-reference (Ctrl+Shift+F) for the aggregated output tag. It must show exactly one write location (the OR network) and one or more read locations (the FB input and any interlocks).
- In PLCSIM, force each mode request individually and confirm the FB input reads
TRUEwithin one scan. Force two requests simultaneously and confirm the FB still readsTRUEfor both input pins (the OR behavior). - Cycle power to the CPU and confirm the aggregated tag retains its last state across the restart if it is declared as
RETAIN; otherwise confirm it initializes toFALSEas expected. - Watch
w_Packedin the HMI and verify the hex pattern changes from16#00to16#01,16#02,16#03, etc., as each request is forced. - Log the scan time of OB1 with the FB instance added; on an S7-1214C the additional load is typically under 50 microseconds and is well within the 1 ms minimum OB1 budget for the default configuration.
10. Edge Cases and Field-Proven Caveats
Output image update timing. The process image of the outputs is refreshed at the end of OB1. If the Bool_to_Word FB is called in an OB that runs at a different priority (e.g., OB35 cyclic interrupt at 100 ms), the FB will read the previous OB1 result for the aggregated output until the next OB1 cycle. This is rarely a defect but explains "one scan of latency" observations.
Retentive behavior on S7-1200. Intermediate flags in an optimized DB are non-retentive by default. If the project requires that an active request survive a CPU stop/start, mark each flag with the RETAIN attribute in the DB. The aggregated output can remain non-retentive to force a safe re-initialization.
Multiple instances of the same FB. If the same eight Boolean tags drive two aggregators (for example, a HMI panel and a SCADA bridge), call the FB twice and pass the same inputs. The inputs are passed by value in an SCL FB so there is no contention.
Watchdog budget. On the S7-1212C DC/DC/DC with firmware V4.6, the OB1 maximum cycle time is 150 ms with a watchdog factor of 1. Adding 100 instances of the Bool_to_Word FB adds roughly 4 ms to the scan. Always re-measure the scan time after adding multiple instances.
Cross-vendor portability. The same pattern applies to Allen-Bradley ControlLogix (use tags instead of output coils), Omron NJ/NX (use work bits in a global symbol table), and Beckhoff TwinCAT 3 (use boolean variables in a DUT). For Omron CX-Programmer the FB syntax is different but the underlying pattern is identical; see the Omron CX-Programmer FB/ST Operation Manual (W447) for the function block declaration syntax on CJ/CP-series PLCs.
Set/Reset coils. A common error is to use -( S )- and -( R )- on the same output tag in different networks. This is functionally the same as duplicate assignment and produces the same defect; the set network must write an intermediate flag, and the reset network must also write an intermediate flag, and the final output is the OR of all set flags ANDed with the NOT of all reset flags.
11. Diagnostic Tables for Quick Reference
| Symptom in HMI | Likely root cause | Fix |
|---|---|---|
| FB input flickers TRUE/FALSE every scan | Duplicate coil on the upstream output | Add intermediate flag, OR the requests, drive one coil |
| FB input is always FALSE even though Q bit looks TRUE in the watch table | Watch table shows the bit immediately after OB1 execution; FB reads after subsequent network overwrites it | Add intermediate flag |
| FB input is correct in PLCSIM but wrong on the real CPU | Different OB priority for FB and coil | Call FB in the same OB as the aggregated output, or use __GET/__SET patterns |
| FB input is stuck TRUE after a single request is removed | Retentive flag is not cleared | Add a reset path or set the flag to non-retentive |
| w_Packed shows wrong hex value | Bit ordering reversed (bit 0 is MSB in some HMI conventions) | Reverse the SHL/OR order, or remap in the HMI |
12. Frequently Asked Questions
Why does my Bool_to_Word FB read FALSE even though the Q output is TRUE in the watch table?
You are writing the same output tag from more than one network. The watch table shows the value after OB1 finishes, but the FB may read the value before a later network overwrites it. Add intermediate flags for each condition and OR them into a single output coil; the FB then sees a stable value.
Is the duplicate-coil pattern a Siemens bug?
No. The IEC 61131-3 standard defines "last assignment wins" semantics for variables assigned multiple times in the same program organization unit. Every major PLC vendor — Siemens, Allen-Bradley, Omron, Beckhoff — implements the same rule. The fix is to add intermediate memory flags, not to change the FB.
Can I use the same Q output in multiple rungs as long as one of them is a Set/Reset coil?
No. The S and R instructions on the same tag in different networks still produce a duplicate-assignment conflict unless the S is in one network and the R is in another with no other writes. In practice, drive an intermediate flag with S/R pairs and let the final output coil be a single read of the flag.
Will the fix work in PLCSIM and on the real CPU identically?
Yes. The duplicate-coil defect reproduces in PLCSIM with the same symptoms as the real CPU, and the intermediate-flag fix produces identical behavior in both. The fix is purely a logical restructuring; it does not depend on scan timing.
What is the correct SCL conversion operator for BOOL to WORD aggregation?
Use the explicit form BOOL_TO_WORD(#i_00) or the generic form _TO_(#i_00) documented in the Siemens SCL conversion reference. Multiply the converted value by the desired bit weight (16#0001, 16#0002, etc.) and OR the eight products together to build the packed word.