Reading 4 Binary Inputs as a UINT on the S7-1212C with TIA Portal V14
A single rotary switch, BCD thumbwheel, or four discrete sensors can present 16 unique states using only four digital inputs. On a Siemens SIMATIC S7-1212C, packing those four bits into one byte gives you a direct 0–15 integer that you can use to select between 16 analog setpoints, dispatch to 16 branches of logic, or feed a recipe index. This reference covers the hardware wiring, tag configuration, four practical implementation methods in TIA Portal V14 (LAD byte-mapping, FBD multiplexer, SCL CASE block, and AT/slice view), the analog-output mapping table, and the verification steps you run on the bench before commissioning.
1. Why Pack Four Bits into One Integer?
Four boolean tags give 16 combinations but only when treated individually. The moment you read them as a single byte (or word) the CPU produces a numeric value 0–15 that you can index, compare, or table-look-up. This eliminates 15 of 16 nested AND/compare rungs and replaces them with a single equality test, a CASE statement, or a multiplexer select.
| I3 | I2 | I1 | I0 | Integer (USInt) | Hex |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 16#00 |
| 0 | 0 | 0 | 1 | 1 | 16#01 |
| 0 | 0 | 1 | 0 | 2 | 16#02 |
| 0 | 0 | 1 | 1 | 3 | 16#03 |
| 0 | 1 | 0 | 0 | 4 | 16#04 |
| 0 | 1 | 0 | 1 | 5 | 16#05 |
| 0 | 1 | 1 | 0 | 6 | 16#06 |
| 0 | 1 | 1 | 1 | 7 | 16#07 |
| 1 | 0 | 0 | 0 | 8 | 16#08 |
| 1 | 0 | 0 | 1 | 9 | 16#09 |
| 1 | 0 | 1 | 0 | 10 | 16#0A |
| 1 | 0 | 1 | 1 | 11 | 16#0B |
| 1 | 1 | 0 | 0 | 12 | 16#0C |
| 1 | 1 | 0 | 1 | 13 | 16#0D |
| 1 | 1 | 1 | 0 | 14 | 16#0E |
| 1 | 1 | 1 | 1 | 15 | 16#0F |
2. Prerequisites
- SIMATIC S7-1212C CPU (any variant — DC/DC/DC, DC/DC/Relay, AC/DC/Relay). Confirm available DI count in the device manual; the standard 1212C ships with onboard 24 V DC inputs that can be used as sourcing inputs.
- TIA Portal V14 SP1 or later (V14 baseline is acceptable for the byte-mapping and SCL approaches; some advanced FBD MUX examples benefit from updates).
- S7-1200 Programmable controller — S7-1212C manual for terminal layout: Siemens S7-1200 System Manual (entry ID 109478121)
- TIA Portal V14 installation: STEP 7 / TIA Portal V14 release notes
- Wiring: four 24 V sourcing sensors or switches wired to inputs I0.0–I0.3 (or any free group of four). Sink/source must match the CPU variant.
- SM 1232 analog output module (or onboard analog — only on CPUs that have it) to drive the resulting scaled setpoint.
3. Hardware Wiring on the S7-1212C
The S7-1212C onboard DI block is galvanically isolated from the logic side and accepts 24 V DC in standard wiring. For a 4-bit selector, wire as follows:
| Terminal | Symbol | Address | Weight | Source Device |
|---|---|---|---|---|
| 1 | DI a.0 | %I0.0 | 1 (LSB) | Selector bit 0 / sensor A |
| 2 | DI a.1 | %I0.1 | 2 | Selector bit 1 / sensor B |
| 3 | DI a.2 | %I0.2 | 4 | Selector bit 2 / sensor C |
| 4 | DI a.3 | %I0.3 | 8 (MSB) | Selector bit 3 / sensor D |
| 5 | 1M | Reference | — | 24 V common for the input group |
If a free 4-bit group of onboard DIs is not available, the same approach works through a SM 1221 DI module at slot 1. The address offsets to IBn where n is the module’s input start byte.
4. PLC Tag Configuration in TIA Portal V14
Open the project, expand PLC_1 > PLC tags > Show all tags and create the following tags before writing any code. Tag names must be unique and follow IEC 61131-3 identifier rules (no spaces, no leading digit).
| Name | Data Type | Address | Comment |
|---|---|---|---|
| i_Sel_Bit0 | Bool | %I0.0 | Selector bit 0 (weight 1) |
| i_Sel_Bit1 | Bool | %I0.1 | Selector bit 1 (weight 2) |
| i_Sel_Bit2 | Bool | %I0.2 | Selector bit 2 (weight 4) |
| i_Sel_Bit3 | Bool | %I0.3 | Selector bit 3 (weight 8) |
| ib_Sel_Raw | Byte | %IB0 | Packed input byte, 0–15 |
| i_Sel_Value | USInt | — | Working copy of the packed value |
| q_AO_Setpoint | Int | %QW64 | Analog output to SM 1232 (example) |
| aAO_Setpoints | Array[0..15] of Int | — | 16-element setpoint table |
The key tag is ib_Sel_Raw at address %IB0. This is a byte-typed view over the same physical inputs as the four Bool tags. The CPU is not duplicating data — IB0 is simply the byte-wide alias of I0.0…I0.7. The four unused upper bits (I0.4–I0.7) must be masked out if other code reads them, because they would corrupt the integer when extended to a wider type.
5. Method 1 — Byte-Mapped Memory Approach (Ladder)
This is the smallest, fastest, and most maintainable solution for production code. One rung copies IB0 to a working USInt, one rung masks the unused upper nibble, and a CASE block (or array index) selects the analog output.
OB1 main scan rung sequence:
- Move the raw byte into a working USInt:
i_Sel_Value := IB0 AND 16#0F;(SCL) or use the LAD AND box with constant 16#0F followed by a MOVE. - Index into a 16-element setpoint array:
q_AO_Setpoint := aAO_Setpoints[i_Sel_Value]; - Scale the Int to the analog module’s raw range (0–27648 for 0–10 V or 4–20 mA) and write to %QW64.
SCL implementation (FB or OB1):
// Read & mask
i_Sel_Value := IB0 AND 16#0F;
// Lookup
CASE i_Sel_Value OF
0: q_AO_Setpoint := aAO_Setpoints[0];
1: q_AO_Setpoint := aAO_Setpoints[1];
2: q_AO_Setpoint := aAO_Setpoints[2];
3: q_AO_Setpoint := aAO_Setpoints[3];
4: q_AO_Setpoint := aAO_Setpoints[4];
5: q_AO_Setpoint := aAO_Setpoints[5];
6: q_AO_Setpoint := aAO_Setpoints[6];
7: q_AO_Setpoint := aAO_Setpoints[7];
8: q_AO_Setpoint := aAO_Setpoints[8];
9: q_AO_Setpoint := aAO_Setpoints[9];
10: q_AO_Setpoint := aAO_Setpoints[10];
11: q_AO_Setpoint := aAO_Setpoints[11];
12: q_AO_Setpoint := aAO_Setpoints[12];
13: q_AO_Setpoint := aAO_Setpoints[13];
14: q_AO_Setpoint := aAO_Setpoints[14];
15: q_AO_Setpoint := aAO_Setpoints[15];
ELSE
q_AO_Setpoint := 0; // fault state for invalid codes
END_CASE;
The same lookup is one line if you use the array directly:
i_Sel_Value := IB0 AND 16#0F;
IF (i_Sel_Value <= 15) THEN
q_AO_Setpoint := aAO_Setpoints[i_Sel_Value];
END_IF;
6. Method 2 — FBD Multiplexer (MUX)
For users who prefer FBD or LAD with no SCL source, the standard library provides the Multiplex (MUX) box. The MUX function has one selector (K) and up to 32 inputs (IN0…IN31) and returns the selected input at the output. The input count is variable — in TIA Portal V14 you right-click the box and use the yellow star to add or remove IN pins.
Configuration of the MUX box:
| Pin | Connection | Description |
|---|---|---|
| K (selector) | IB0 masked with 16#0F → USInt | 0–15 |
| IN0 | Setpoint 0 (Int) | Code 0000 |
| IN1 | Setpoint 1 (Int) | Code 0001 |
| … | … | … |
| IN15 | Setpoint 15 (Int) | Code 1111 |
| OUT | Tag to scale and write to %QW | Selected value |
To insert the MUX in TIA Portal V14 FBD:
- Open an FBD network in OB1.
- From the right-side catalog, navigate to Instructions > Bit logic operations > Multiplex (or use the search field).
- Drag MUX into the network.
- Right-click the box, choose Add input until 16 IN pins exist (yellow star in older builds; in V14 the context menu is Add input).
- Connect K to the masked byte; connect each IN pin to the appropriate setpoint constant or array element.
IB0 AND 16#0F is also USInt, the type matches and no coercion is required. Passing the unmasked byte as K will still work in TIA Portal V14 (selector values above 15 wrap to the highest defined input) but is unsafe — always mask first.7. Method 3 — SCL with CASE / Direct Array Index
The SCL approach is recommended for any logic with more than a handful of branches. It compiles to efficient native code on the S7-1200 and is far easier to maintain than a 16-element MUX box. Create an FB (function block) named FB_Selector4 with the section shown in Section 5, declare it in OB1, and call it once per scan.
FB declaration (TIA Portal V14 — Simplified Chinese / English / German all use the same editor):
| Section | Name | Type | Initial Value |
|---|---|---|---|
| Input | |||
| Input | i_Sel_Bit0 | Bool | FALSE |
| Input | i_Sel_Bit1 | Bool | FALSE |
| Input | i_Sel_Bit2 | Bool | FALSE |
| Input | i_Sel_Bit3 | Bool | FALSE |
| Output | |||
| Output | q_Sel_Value | USInt | 0 |
| Output | q_AO_Setpoint | Int | 0 |
| Static | |||
| Static | s_AO_Setpoints | Array[0..15] of Int | [16(0)] |
Set the array values in the FB’s initialization or load them from a recipe DB at startup. This is the typical pattern when the 16 setpoints are user-configurable at runtime — populate s_AO_Setpoints from a recipe DB and the CASE block becomes a single array-index operation.
8. Method 4 — AT / Slice Access for Partial Bytes
On S7-1200 firmware V4.0 and later, TIA Portal V14 supports Slice access — a named, typed view over a sub-range of a byte. The syntax is tag.%X0 for the lowest bit, and the same syntax can be grouped to extract a nibble.
// In a static data block
mySelector : Byte; // AT view of %IB0
mySelector.%X0 : Bool; // bit 0
mySelector.%X1 : Bool; // bit 1
mySelector.%X2 : Bool; // bit 2
mySelector.%X3 : Bool; // bit 3
Or, equivalently, the AT overlay on a DB:
DATA_BLOCK "DB_Sel"
STRUCT
rawByte : BYTE; // bound to %IB0 via the PLC tag table
b0 : BOOL; // rawByte.%X0
b1 : BOOL; // rawByte.%X1
b2 : BOOL; // rawByte.%X2
b3 : BOOL; // rawByte.%X3
nibble : USINT; // rawByte.%B0 (low nibble, 0..15)
END_STRUCT;
END_DATA_BLOCK
Slice access produces the same result as the byte-mapped method but lets you name each derived boolean symbolically. It is the cleanest style for HMI tag generation, where each derived bit needs a unique HMI tag.
%X0, %B0, %W0) on the S7-1200 requires CPU firmware V4.0 or higher. The S7-1212C shipped from roughly 2014 onward typically runs V4.x; confirm in Online & diagnostics > Diagnostic information. If you must support V3.x firmware, use the byte-mapping method and bit-mask manually with WAND_W (Word AND Word).9. Analog Output Mapping (16 Setpoints)
The end-goal of the 4-bit decode is typically a single analog setpoint. Below is a worked example where the analog output is 0–10 V on a SM 1232 AO4 module. The Int range 0–27648 maps to 0–10 V (or 0–20 mA / 4–20 mA depending on module configuration).
| Code | Bit Pattern (b3 b2 b1 b0) | Engineering Value | Raw Int (0–27648) |
|---|---|---|---|
| 0 | 0000 | 0.0 V | 0 |
| 1 | 0001 | 0.67 V | 1843 |
| 2 | 0010 | 1.33 V | 3686 |
| 3 | 0011 | 2.00 V | 5529 |
| 4 | 0100 | 2.67 V | 7372 |
| 5 | 0101 | 3.33 V | 9216 |
| 6 | 0110 | 4.00 V | 11059 |
| 7 | 0111 | 4.67 V | 12902 |
| 8 | 1000 | 5.33 V | 14745 |
| 9 | 1001 | 6.00 V | 16588 |
| 10 | 1010 | 6.67 V | 18432 |
| 11 | 1011 | 7.33 V | 20275 |
| 12 | 1100 | 8.00 V | 22118 |
| 13 | 1101 | 8.67 V | 23961 |
| 14 | 1110 | 9.33 V | 25804 |
| 15 | 1111 | 10.0 V | 27648 |
For 4–20 mA output, the raw range shifts to 0–27648 mapping to 0–20 mA. To clip the live-zero 4 mA minimum, add a 5530-count offset and cap at 27648 — i.e. setpoint = 5530 + (value × (27648 − 5530) / 15).
10. Verification and Commissioning Procedure
- Force the inputs in PLCSIM or with a hardwired jumper. In TIA Portal V14 use Online & diagnostics > Force only on a test PLC, never on a production CPU. In PLCSIM (which is the offline simulator shipped with TIA Portal), set the four input bits individually and observe IB0.
-
Watch table check. Open a watch table, add the tags
IB0,i_Sel_Value,q_AO_Setpoint, andQW64. Toggle each input pair (00, 01, 10, 11 on the low bits, then 00, 01, 10, 11 on the high bits) and confirm the integer value matches the table in Section 1. - Edge cases. Force all four inputs simultaneously to 0; verify the analog output is the setpoint for code 0. Force all four to 1; verify code 15. Force invalid combinations — i.e. an additional bit in the upper nibble (I0.4 = 1) — and confirm the masking code returns only the low nibble.
- Scan time impact. The byte-mapping, SCL CASE, and array-index approaches are all single-instruction in steady state. The MUX box compiles to a jump table and is comparable. None of these materially extend the OB1 cycle on a 1212C.
-
HMI faceplate. If a Comfort Panel or Basic Panel is in the project, expose
i_Sel_Valueas a multi-state symbol. Each of the 16 states can display a unique icon or setpoint label without further code.
11. Edge Cases and Field-Engineering Notes
11.1 Contact bounce and debounce
Mechanical selector switches and reed relays can produce multiple transitions before settling. If the analog output drives a critical actuator (valve, drive reference), debounce the inputs with one of:
- TP / TON timers per input (typical 5–20 ms).
- IEC timer TON with a settling window of 50–100 ms for a 4-bit thumbwheel.
- The S7-1200 built-in input filter (configured per input in the device configuration — default is 6.4 ms in TIA Portal V14; can be raised to 12.8 ms in hardware).
11.2 Partial input failure
If a wire breaks or a sensor fails open, the corresponding bit latches to 0. The integer will jump to a wrong code. Add a plausibility check: if the resulting code corresponds to a setpoint outside the user-allowed range, force the analog output to a safe default (e.g. the last valid value or 0 mA).
11.3 Level inversion
If the physical switch is wired as active-low (sink to 1M, pull-up inside the PLC), the integer at rest is 15 and the active states are 14, 13, … 0. Either invert the bit mask (IB0 XOR 16#0F) or remap the setpoint table.
11.4 Glitches during scan
All four inputs are sampled at the start of OB1. If a switch transitions during the scan, the next cycle will read the new state — no race condition. The risk is only if the cycle time is longer than the dwell time of the selector (e.g. a 5 ms pulse on a 200 ms cycle). For those applications, latch the value into a marker on the rising edge of a strobe input.
11.5 PERSISTENT setpoint storage
If the 16 analog setpoints are recipe data, declare the array in a DB with RETAIN attribute. The values survive power-cycle. For changing recipes from HMI, expose the array as a recipe view in WinCC Comfort/Advanced.
12. Method Comparison
| Criterion | Byte Map (LAD/SCL) | MUX (FBD) | SCL CASE | AT/Slice |
|---|---|---|---|---|
| Lines of code | 2–3 | 1 box + 16 constants | 16 case branches | 2–4 |
| Maintainability | High | Medium | High | High |
| Firmware requirement | Any | Any | Any | V4.0+ |
| Runtime cost | Negligible | Negligible | Negligible | Negligible |
| Recipe support | Direct (array index) | Manual (16 constants) | Direct (array index) | Direct (array index) |
| Best for | Production code, all skill levels | FBD-only programmers | Engineers comfortable with text | HMI tag generation, mixed-language teams |
13. Glossary of Useful TIA Portal V14 Paths
| Action | Navigation |
|---|---|
| Add a new PLC tag | Project tree > PLC_1 > PLC tags > double-click Default tag table > add row |
| Insert MUX box in FBD | Instructions > Bit logic operations > Multiplex |
| Insert AT view in DB | Open DB > right-click on a tag > Add new AT view |
| Configure input filter | Device view > DI module properties > Inputs > Input filter (ms) |
| Add a watch table | Project tree > PLC_1 > Watch and force tables > Add new watch table |
| Compile and download | Project tree > PLC_1 > right-click > Compile > Download to device |
14. Related Siemens Documentation
- S7-1200 Programmable Controller — System Manual (terminal layouts, I/O counts, electrical specs)
- STEP 7 Basic V14 in the TIA Portal — Programming and Operating Manual (tag configuration, SCL editor)
- S7-1200 Automation System — System Manual entry
- STEP 7 / WinCC V14 — Release notes & download
- S7-1200 Function Manuals (LAD/FBD/SCL instruction set, MUX semantics)
Do I need four separate digital input tags, or can I read the four bits as one variable from the start?
You can read them as one variable from the start. The four physical inputs I0.0–I0.3 are also accessible as the byte %IB0 in the process image. Define a byte-typed tag at address %IB0, mask with 16#0F to keep only the low nibble, and you have a 0–15 integer in a single read.
Which method is fastest for an S7-1212C — byte-mapping, MUX, or SCL CASE?
All three compile to a few native instructions on the S7-1200. The byte-mapping + array-index method is the most compact and typically the fastest because it avoids a 16-way branch. The MUX box compiles to a small jump table and is comparable. The difference at scan-time scale is in the microsecond range and does not matter for a 1–10 ms OB1 cycle.
My integer is rotated — code 1 appears when the switch is at position 8. What went wrong?
Bit weight is mismatched. The lowest-weight bit (LSB, value 1) must be on input I0.0; the highest-weight bit (MSB, value 8) on I0.3. If you wired the MSB to I0.0 by accident, the integer is shifted 3 bits. Either swap the physical wiring or remap the bits with an explicit SCL combination (e.g. i_Sel_Value := (i_Sel_Bit0 SHL 0) OR (i_Sel_Bit1 SHL 1) OR (i_Sel_Bit2 SHL 2) OR (i_Sel_Bit3 SHL 3);).
Does slice access (%X0, %B0) work on every S7-1212C firmware version?
No. Slice access requires S7-1200 firmware V4.0 or later. If you must support older firmware, use the byte-mapping method with a manual WAND_W (word AND word) mask of 16#000F, or use four separate Bool tags and combine them in SCL with shift and OR.
How do I scale the integer 0–15 to a 4–20 mA analog output on a SM 1232?
Use NORM_X and SCALE_X, or compute directly: raw = 5530 + (selector × (27648 − 5530) / 15). The 5530 offset represents the 4 mA live-zero, and 27648 − 5530 = 22118 is the span. Write the resulting Int to the analog output word (e.g. %QW64 for the first channel of a SM 1232 AO4) and configure the channel for current output in the device configuration.