SCL AND Operator Bit Masking Explained in TIA Portal
When you encounter legacy SCL code such as IF (Byte_To_Bool(value) AND 1) THEN ... END_IF;, the literal expression AND 1 can confuse engineers transitioning from LAD/FBD or from other IEC 61131-3 dialects. The expression is not an address reference, it is a bit-mask operation. This reference explains the semantics of AND in SCL, the role of the constant 1 as a binary mask, the interaction with the Byte_To_Bool conversion, and the recommended idioms for bit extraction in SIMATIC S7-1200 and S7-1500 controllers programmed with TIA Portal.
IF and WHILE constructs.1. Overview of SCL and the AND Operator
Structured Control Language (SCL) is Siemens' high-level, Pascal-derived implementation of the IEC 61131-3 ST (Structured Text) language. It is fully integrated into TIA Portal and supported on S7-300/400 (with restrictions), S7-1200, S7-1500, ET 200SP CPUs, and the WinAC RTX platform. SCL expressions and operations are documented in the SIMATIC S7-1200 manual collection, which states that the SCL control statements include IF-THEN, CASE-OF, FOR-TO-DO, WHILE-DO, REPEAT-UNTIL, CONTINUE, GOTO, and RETURN, and that a single statement typically occupies one line within a block (Siemens TIA Portal Docs - SCL Expressions and Operations).
The bitwise AND operator is a first-class element of SCL and follows IEC 61131-3 semantics. It performs a bitwise logical conjunction on two integer operands. The result type is the wider of the two operand types. When the right-hand operand is the integer literal 1, the operation isolates the least-significant bit of the left-hand operand. This is the foundation of every bit-mask test in SCL.
The key SCL syntax forms for a single-bit test are listed below. All four statements are semantically equivalent for the data types BOOL, BYTE, WORD, and DWORD when the bit under test is bit 0:
| Syntax form | Type of right operand | Notes |
|---|---|---|
IF (value AND 1) <> 0 THEN |
Integer literal | Implicit conversion; classic idiom. |
IF (value AND 2#1) <> 0 THEN |
Binary literal | Self-documenting; bit position visible. |
IF (value AND 16#01) <> 0 THEN |
Hexadecimal literal | Compact; one hex digit per nibble. |
IF value.%X0 THEN |
Bit slice | S7-1500 only; no operator required. |
IF Byte_To_Bool(value) THEN |
Standard function | Returns LSB only (see §5). |
2. Bit Masking Fundamentals in SCL
A bit mask is a constant whose binary representation contains 1s exactly in the positions you want to keep and 0s everywhere else. The AND operator applies that mask to an integer value, producing a result that is non-zero if and only if at least one of the masked positions is set in the source value.
For the mask 1 (binary 2#0000_0001), only bit 0 survives. The truth table for an 8-bit operand is shown below:
| x (hex) | x (binary) | x AND 1 | Result is TRUE when |
|---|---|---|---|
| 16#00 | 2#0000_0000 | 0 | — |
| 16#01 | 2#0000_0001 | 1 | Bit 0 = 1 |
| 16#02 | 2#0000_0010 | 0 | — |
| 16#03 | 2#0000_0011 | 1 | Bit 0 = 1 |
| 16#FE | 2#1111_1110 | 0 | — |
| 16#FF | 2#1111_1111 | 1 | Bit 0 = 1 |
For a 16-bit operand the mask is still 1 because AND operates on the value, not on the data type. The other 15 bits of the source are masked out and contribute zero to the result.
2.1 Mask generation rules
To test bit n of an integer V, the canonical mask is 2 ** n or its equivalent literal form. The SCL compiler will fold this expression at compile time when both operands are constants, so no runtime cost is incurred. The patterns below all compile to a single-word load and bit-test on S7-1500:
// Test bit 0
IF (V AND 2#0000_0001) <> 0 THEN ... END_IF;
// Test bit 3
IF (V AND 2#0000_1000) <> 0 THEN ... END_IF;
// Test bit 7
IF (V AND 16#80) <> 0 THEN ... END_IF;
// Test bit 15
IF (V AND 16#8000) <> 0 THEN ... END_IF;
3. AND 1 vs AND 2#1 vs AND TRUE — Syntax Comparison
The SCL compiler accepts the right-hand operand of AND in any literal form that resolves to an integer. The three forms 1, 2#1, and 16#01 produce the same bit pattern and the same machine code. The form TRUE is also accepted, but its type is BOOL rather than an integer, and the SCL compiler performs an implicit conversion from BOOL to the left operand's integer type. The conversion rule is TRUE → 1 and FALSE → 0, which preserves the mask semantics.
AND TRUE is used. Resolve by replacing with an explicit integer mask such as 1 or 2#1. The warning does not affect generated code; it is a style hint.3.1 Comparison table
| Expression | Type of 1
|
Compiler warning | Generated code |
|---|---|---|---|
value AND 1 |
INT literal |
None | Single AND word op |
value AND 2#1 |
INT binary literal |
None | Identical to above |
value AND 16#01 |
INT hex literal |
None | Identical to above |
value AND TRUE |
BOOL |
Possible implicit-conversion note | Conversion + AND word op |
value AND 16#FFFF |
INT hex literal |
None | Identical mask, wider result |
4. Address Reference Behavior in SCL
The question that motivated this reference is whether AND 1 could be a syntactically shortened form for addressing bit 550.1 in the input area. It cannot. SCL bit addressing is always written with a % qualifier (%I for input, %Q for output, %M for memory) and an explicit bit offset, for example %I550.1 or, in TIA Portal symbolic form, "IW550".%X1. The plain token 1 is the integer literal one, never an address fragment.
However, the appearance of 550 in the input image is not a coincidence. S7-1200 and S7-1500 CPUs place process-image inputs in word-aligned addresses. The identifier I550.0 refers to bit 0 of input byte 550, and I550.1 to bit 1 of the same byte. When legacy code reads Byte_To_Bool(IB550) it implicitly extracts bit 0, which is why the AND 1 mask in the surrounding IF looks redundant.
4.1 SCL bit-slicing syntax (S7-1500)
On S7-1500 CPUs with firmware V2.0 or later, SCL supports a typed bit-slice syntax that avoids the need for an explicit mask:
IF "DB_Modbus".StatusWord.%X0 THEN // bit 0 of a WORD tag
// ...
END_IF;
The .%X<n> accessor is not available on S7-1200 (firmware V4.x); on those controllers the bit-mask idiom remains the recommended approach. S7-300/400 SCL supports the older DBx.DBBy.%X<n> absolute form.
5. The Byte_To_Bool Function in SCL
Byte_To_Bool is a standard type-conversion function in the IEC 61131-3 library. It accepts a BYTE operand and returns the value of the least-significant bit as a BOOL. The semantics are identical to the expression (byte AND 1) <> 0. This is the reason the surrounding mask looks redundant: Byte_To_Bool has already reduced the byte to the LSB before the AND is evaluated.
| Input (BYTE) | Binary | Output (BOOL) |
|---|---|---|
| 16#00 | 2#0000_0000 | FALSE |
| 16#01 | 2#0000_0001 | TRUE |
| 16#02 | 2#0000_0010 | FALSE |
| 16#55 | 2#0101_0101 | TRUE |
| 16#A0 | 2#1010_0000 | FALSE |
| 16#FF | 2#1111_1111 | TRUE |
Because Byte_To_Bool returns BOOL, applying AND 1 to that result triggers the implicit BOOL-to-INT conversion mentioned in §3. The boolean TRUE becomes integer 1, and the mask 1 AND 1 remains 1 (non-zero, truthy). The boolean FALSE becomes integer 0, and 0 AND 1 is 0 (falsy). The net effect is a no-op identity, which is why the legacy code still works even though the mask is logically superfluous.
6. Bit Extraction Patterns and Best Practices
For new SCL code on S7-1200 and S7-1500, prefer the most readable form. The following examples demonstrate equivalent tests for bit 0 of a word tag named StatusWord:
// Pattern A — explicit mask, no conversion (recommended for S7-1200)
IF (StatusWord AND 2#0000_0001) <> 0 THEN
// bit 0 is set
END_IF;
// Pattern B — bit slice (recommended for S7-1500, FW V2.0+)
IF StatusWord.%X0 THEN
// bit 0 is set
END_IF;
// Pattern C — boolean conversion of a BYTE (legacy compatible)
IF Byte_To_Bool(LO_BYTE(StatusWord)) THEN
// bit 0 of the low byte is set
END_IF;
// Pattern D — symbolic bit tag (TIA Portal optimized)
IF "Status_bit0" THEN
// bit 0 mapped to a derived BOOL tag in the data block
END_IF;
6.1 Setting, clearing, and toggling bits
The AND operator is read-only. To modify a bit in place, combine AND (clear) and OR (set) with a mask, or use the dedicated SCL bit-slicing assignment syntax on S7-1500:
// Clear bit 3
WordTag := WordTag AND 16#FFF7; // 16#FFF7 = 2#1111_0111_0111_0111
// Set bit 3
WordTag := WordTag OR 16#0008;
// Toggle bit 3
WordTag := WordTag XOR 16#0008;
// S7-1500 bit-slice assignment
WordTag.%X3 := TRUE; // set
WordTag.%X3 := FALSE; // clear
WordTag.%X3 := NOT WordTag.%X3; // toggle
7. Common Pitfalls and Misinterpretations
The most frequent issues observed in the field are summarized below.
| Pitfall | Symptom | Root cause | Correction |
|---|---|---|---|
| Masking with a negative literal | Compiler error or unexpected sign extension |
-1 is interpreted as INT and sign-extends to 32 bits |
Use 16#FFFF or cast with WORD#16#FFFF
|
Masking a signed INT tag |
Bit test result differs from expectation for negative values | Two's-complement representation | Cast to WORD or UINT before masking |
Using AND on REAL
|
Compiler error "Type conversion not possible" |
AND is integer-only |
Use TRUNC or move to DINT first |
Confusing AND with &
|
Syntax error in strict SCL mode |
& is C-style, not SCL |
Use only AND
|
Using AND on BOOL directly |
Warning, possible code bloat | Bool already returns truthy | Use IF b THEN directly |
| Wrong bit position | IF triggers on the wrong input pattern | Off-by-one in mask | Use binary literal: 2#0000_1000 is bit 3 |
Implicit BOOL→INT on AND TRUE
|
Compiler warning | Implicit conversion | Replace with integer literal 1
|
8. Verification and Testing Strategies
Before trusting legacy SCL code that contains AND <mask> constructs, run the following verification procedure in TIA Portal:
- Compile and check warnings. Project tree → right-click CPU → Compile > Software (rebuild all). Resolve every warning of class Implicit type conversion and Bit access not on %I/%Q/%M before continuing.
-
Inspect the compiled STL. Right-click the SCL block → Generate source from blocks (or use Compare STL/FBD view). Confirm that the
ANDcompiles to a single 16-bit or 32-bit logical AND. A multi-instruction sequence indicates an unintended type promotion. -
Trace the right operand. Use Go to definition on the literal to verify it resolves to an integer constant and not a tag named
"1"in a global data block. -
Force and monitor. Load the block to the CPU, open the watch table, and force the source byte to
16#00,16#01,16#02, and16#FFin turn. TheIFbranch must execute only when the LSB is set. -
Edge-detect with PLCSIM. In S7-PLCSIM V15 or later, add a sequence of transitions in the input image and record the OB1 scan-cycle count at which the
IFevaluates to TRUE. The transition count must match the number of LSB edges in the test vector. -
Cross-check with LAD. Translate the SCL construct to an equivalent LAD network:
---[ IB550 AND 1 ]---( )using a WAND_W (word AND word) box feeding a comparator. Both branches must produce identical results on the same input pattern. -
Document the intent. Add a header comment with the mask in binary form so that future maintainers do not need to re-derive the bit position, e.g.
// AND 2#0000_0001 → tests bit 0 (LSB) of StatusByte.
9. Performance Considerations
On S7-1500 CPUs, a single AND against a constant mask is a one-cycle operation in the bit-instruction set. On S7-1200 CPUs (firmware V4.x), the same construct compiles to a load-immediate / AND-word / compare sequence of roughly 3 to 5 µs per call, depending on the data type width. Constant folding eliminates any runtime cost of the mask itself, so the only variable cost is the bit-test itself.
If the SCL code is inside a tight FOR loop that runs every OB1 cycle, prefer the bit-slice syntax on S7-1500 because it avoids the integer-to-bool conversion generated by Byte_To_Bool. The relevant benchmark on a CPU 1515-2 PN is approximately:
| Form | Instruction count | Typical time |
|---|---|---|
value AND 1 <> 0 |
3 | ~0.045 µs |
value.%X0 |
2 | ~0.030 µs |
Byte_To_Bool(value) AND 1 |
5 | ~0.075 µs |
Byte_To_Bool(value) |
4 | ~0.060 µs |
10. SCL Coding Standards and Style
The following style recommendations are taken from the SIMATIC S7-1200 manual collection and the SITRAIN course SIMATIC Programming 1 with SCL in TIA Portal (SITRAIN course page; see also the introductory walkthrough Writing your first SCL Code in TIA Portal for context on FB/FC structure and block interface design).
- Always write the mask in binary or hexadecimal form unless the literal
1is unambiguously the LSB. - Prefer the bit-slice syntax
.%X<n>on S7-1500 because it removes the risk of mask typos and produces smaller STL. - Cast to an unsigned type before masking signed integers.
- Comment the bit position in plain text above the test.
- Extract named BOOL tags for frequently tested bits in the data block; this makes the SCL self-documenting and allows the HMI to subscribe to the same tag.
11. Cross-Reference: STL, LAD, and FBD Equivalents
Engineers familiar with LAD/FBD often find it easier to confirm the SCL semantics by translating the construct to another language. The table below shows the four equivalent representations for testing bit 0 of a word.
| Language | Code |
|---|---|
| SCL | IF (MW100 AND 2#0000_0001) <> 0 THEN "Bit0Set" := TRUE; END_IF; |
| STL | L MW100 |
| LAD | MW100 ---[ WAND_W 1 ]---[ <>0 ]---( "Bit0Set" ) |
| FBD | MW100 & WAND_W 1 ⇒ CMP <> 0 ⇒ AND "Bit0Set" |
12. Frequently Asked Questions
What does AND 1 mean inside an SCL IF condition?
AND 1 is a bitwise conjunction with the integer literal 1 (binary 2#0000_0001). It tests whether bit 0 of the left operand is set; the result is non-zero if and only if the LSB is 1. It is not an address reference and has no connection to the input image address 550.1.
Is AND 1 the same as AND TRUE in SCL?
Yes, semantically. TRUE is implicitly converted to integer 1 by the SCL compiler. However, the conversion can trigger a warning in TIA Portal under Block consistency > Implicit type conversion. For clean builds, prefer the integer literal 1 or the binary literal 2#1.
Why does the legacy code use AND 1 after Byte_To_Bool when the conversion already returns the LSB?
The mask is logically redundant. Byte_To_Bool(x) returns the LSB as a BOOL; BOOL AND 1 then re-encodes the boolean as 1 or 0. The author likely wrote it for clarity or copied it from a word-mask idiom. It is safe to remove, and modernizing the code to the S7-1500 bit-slice syntax x.%X0 yields a smaller and faster block.
Can AND be used on a REAL tag in SCL?
No. AND is defined for integer types only (BOOL, BYTE, WORD, DWORD, SINT, INT, DINT, LINT, and their unsigned variants). For floating-point values, convert with TRUNC or REAL_TO_DINT first, or extract the IEEE-754 bit pattern with a AT-style overlay (S7-1500).
Which SCL form is best for testing a single bit on S7-1500 firmware V2.9?
Use the typed bit-slice syntax tag.%X<n>. It compiles to a single load-and-test sequence, is self-documenting, and avoids any type-conversion warnings. Reserve the explicit AND mask form for S7-1200 projects, for S7-300/400 SCL, or when the bit under test is computed at runtime.