1. Problem Overview
Engineers integrating counters, piece counters, or scaled values from fieldbus partners frequently need to detect whether a 32-bit unsigned value (DWORD) on a SIMATIC S7-300 CPU has transitioned away from zero. The classic use case is a real-time parts counter: as long as the counter is greater than zero, an output, marker, or HMI tag must remain TRUE, and the program must capture the rising edge so that a downstream one-shot logic (e.g., a batch increment) fires exactly once.
Although STEP 7 STL, LAD and FBD all support DWORD natively, the comparison to a constant zero (L#0) is a 32-bit signed operation by default. This creates confusion for programmers who assume that a direct "MOVE" of a DWORD into a DINT will preserve the unsigned bit pattern. The MOVE box in LAD/FBD performs a type-checked copy, and on a CPU that does not accept the implicit conversion, the operation fails to compile or - worse - is silently coerced to zero in online monitor. The robust, language-agnostic solution uses three built-in STEP 7 statements: CLR, L, and >D (or <>D), followed optionally by FP/FN edge detection.
This article walks through the data-type theory, presents ready-to-paste STL, LAD/FBD and SCL code blocks, and finishes with a verification procedure and a troubleshooting matrix for the most common failure modes - including the MB200-MB255 scratchpad flag range and the LAD/FBD type-check switch.
2. Data Type Fundamentals: DWORD vs. DINT
STEP 7 defines several 32-bit data types that share the same 32 bits of memory but differ in how the CPU interprets those bits during arithmetic and comparison. The three that matter for this application are:
| Data type | Length | Range | Signed | Default compare op |
|---|---|---|---|---|
| BOOL | 1 bit | 0 or 1 | No | =, <> |
| BYTE | 8 bits | 0 to 255 (B#16#00..FF) | No | -- |
| WORD | 16 bits | W#16#0000..FFFF (0 to 65535) | No | -- |
| INT | 16 bits | -32768 to 32767 | Yes | >I, <I, =I, <>I |
| DWORD | 32 bits | DW#16#0000_0000..FFFF_FFFF (0 to 4 294 967 295) | No (unsigned) | -- |
| DINT | 32 bits | -2 147 483 648 to 2 147 483 647 (L#-2147483648..2147483647) | Yes | >D, <D, =D, <>D |
| REAL | 32 bits | IEEE 754 single precision | Yes | >R, <R, =R, <>R |
The CPU has no internal concept of "hex" - every operand is a 32-bit bit string. The interpretation as DWORD, DINT or REAL is selected entirely by the instruction that touches the accumulator. This is why a single MOVE of a DWORD into a DINT symbol does not convert; it just re-labels the same bit string, and any subsequent signed comparison can produce wrong results if the most significant bit (bit 31) is set.
For a piece counter that is always non-negative, the simplest and safest interpretation is unsigned 32-bit. Detecting "greater than zero" therefore reduces to detecting "not equal to zero" - because for an unsigned value, any non-zero bit pattern is necessarily > 0.
2.1 Bit-Level View of a Counter
Consider a parts counter holding the value 1 000 (decimal):
- Hex:
W#16#0000_03E8orDW#16#000003E8 - Signed 32-bit (DINT) view:
+1000 - Unsigned 32-bit (DWORD) view:
+1000
Now consider a counter holding 4 300 000 000 (decimal):
- Hex:
DW#16#0000_0001_0042_C1A0 - Signed 32-bit (DINT) view:
+4300000000- this is out of range for DINT (max 2 147 483 647) and would be flagged as a compiler error or wrap to a negative value. - Unsigned 32-bit (DWORD) view:
+4300000000- valid.
For a counter that will never exceed 2 147 483 647 parts, the DINT-signed comparison >D against L#0 works flawlessly. For counters that can exceed 2.1 billion, the correct unsigned comparison is the 32-bit bit-pattern test <>D against L#0 or, more strictly, a direct test of the most significant bit and the byte 0 ORed across all four bytes.
3. Prerequisites
Before editing the project, confirm the following:
- STEP 7 V5.5 or V5.6 (classic) is installed with the S7-300 optional package. TIA Portal can also be used, but the symbol naming and offline/online behaviour differ; this article uses classic STEP 7 conventions.
- The CPU firmware supports the symbol's declared data type. A CPU 312C, 313C, 314, 315-2 DP, 317-2 or 319-3 is sufficient. Reference: SIMATIC S7-300 CPU 31xC and CPU 31x Operating Instructions (Siemens KB 91696622).
- The counter source - a DB field such as
DB100.DBD114, an I/Q area, or a value received from a PN/DP partner - is already declared with the correct data type (DWORD or equivalent 32-bit area). - The destination marker (M bit) and any auxiliary M bits (FP/FN helpers) are not inside the reserved range MB200-MB255 used by some S7-300 CPUs as scratchpad flags. Use M0.0-M199.7 or M256.0-M4095.7.
- PG/PC is online (MPI, PROFIBUS or PROFINET) so the result of the comparison can be monitored with Monitor/Modify (VAT) or with the program status.
4. STL Implementation: The Three-Instruction Solution
Statement List (STL) gives the most direct access to the two accumulators (ACCU 1 and ACCU 2). The reference pattern is the canonical "compare-DWORD-to-zero-and-set-marker" snippet:
// Compare DWORD "RealizedQuantity" against L#0 and set M199.0 when > 0
CLR // ACCU 1 = 0, RLO = 0
L "RealizedQuantity" // ACCU 1 := DWORD, ACCU 2 := 0
L L#0 // ACCU 1 := 0, ACCU 2 := DWORD
>D // RLO = 1 if ACCU 2 > ACCU 1 (signed 32-bit)
= M 199.0 // Marker follows RLO
Instruction-by-instruction trace:
-
CLRsets the RLO (result of logic operation) to 0 and clears ACCU 1. This is required only when the preceding network leaves a residual value in ACCU 1 that could interfere; modern programmers include it for hygiene. -
L "RealizedQuantity"loads the 32-bit bit string of the source symbol into ACCU 1. The old ACCU 1 shifts to ACCU 2. The data type tag of the symbol tells STEP 7 to load it as a 32-bit value, but the bits are not reinterpreted. -
L L#0loads the constantL#0(DINT zero) into ACCU 1; ACCU 2 keeps the counter value. -
>Dperforms a 32-bit signed compare: if ACCU 2 > ACCU 1 the RLO becomes 1, otherwise 0. -
= M 199.0assigns RLO to the marker coil.
For the more robust unsigned case use <>D (not equal):
CLR
L "RealizedQuantity"
L L#0
<>D
= M 199.0
<>D is true for any non-zero bit pattern, including the value 4 294 967 295 (all 32 bits set) which would otherwise look like -1 in signed interpretation. For piece counters this is the recommended form.
4.1 Full STL Block With Edge Detection
// Network 1: Continuous "> 0" flag
CLR
L "RealizedQuantity" // DB100.DBD114, DWORD
L L#0
<>D
= M 199.0 // M 199.0 = 1 when counter <> 0
// Network 2: Rising-edge one-shot (FP)
A M 199.0
FP M 199.1 // M 199.1 = previous state of M 199.0
S M 199.3 // Set M 199.3 on rising edge
// Network 3: Falling-edge one-shot (FN)
A M 199.0
FN M 199.2 // M 199.2 = previous state of M 199.0
R M 199.3 // Reset M 199.3 on falling edge
The FP (Flank Positive / rising edge) and FN (Flank Negative / falling edge) instructions need their own helper bits because the previous-cycle state must be remembered. M 199.1 and M 199.2 are edge memory bits and must be assigned exclusively to one FP/FN pair. The reference description of FP/FN is in the STEP 7 Programming and Operating Manual, section on bit-logic instructions.
5. LAD/FBD Implementation Using the Comparator Block
In LADDER (LAD) and FUNCTION BLOCK DIAGRAM (FBD), the comparator CMP >D or CMP <>D block is dragged from the comparator folder of the program-element catalog. Wire the inputs as follows:
| Block pin | Wired to | Notes |
|---|---|---|
| IN1 | "RealizedQuantity" (MW/DW) | Source DWORD |
| IN2 | L#0 | Enter the constant directly in the pin |
| Output (BOOL) | M 199.0 | Continuous flag |
Steps to insert the comparator:
- Open the target block (OB1, OB35 or FC) in LAD or FBD.
- From the program-element tree, expand Comparator and select CMP <>D.
- Drop it on an empty network. STEP 7 will auto-create the input and output placeholders.
- Click the IN1 placeholder, type the symbol name (e.g.,
"RealizedQuantity"). - Click the IN2 placeholder, type
L#0. - Click the output and type
M 199.0or any BOOL marker. - Save the block and download to the CPU.
For edge detection, insert FP from the bit-logic folder after the comparator output, and wire a S (set) coil to a retention marker such as M 199.3. The companion FN/R pair resets the same marker when the comparator returns to zero.
6. SCL Implementation for Compact Code
Structured Control Language (SCL) lets you express the same logic in two lines. Open a new source file or FC, change the language to SCL, and type:
// SCL: edge-detected comparison
IF "RealizedQuantity" <> DWORD#16#0 THEN
"CounterActive" := TRUE;
ELSE
"CounterActive" := FALSE;
END_IF;
IF "CounterActive" AND NOT "CounterActiveOld" THEN
"NewBatchEvent" := TRUE; // rising-edge event
END_IF;
"CounterActiveOld" := "CounterActive"; // edge memory
Notes on the SCL syntax:
- Use the
DWORD#16#0literal for an unsigned 32-bit zero. TheL#0literal from STL is also accepted in SCL as a DINT zero, butDWORD#16#0documents the unsigned intent more clearly. - SCL automatically generates the FP/FN edge memory block; you do not need explicit auxiliary flags.
- The SCL compiler produces STL internally, so the resulting MC7 code is identical in size to the hand-written STL of Section 4.
7. Edge Detection: FP and FN Instructions
Continuous comparison is rarely the final logic. Typical consumer blocks only want a one-shot pulse on the rising edge of the comparator (e.g., increment a batch counter, log a tag change, fire a one-shot output). The combination of FP and FN provides exactly that.
| Instruction | Symbol | Behaviour | Helper bit |
|---|---|---|---|
| FP - Flank Positive | --|P|-- | RLO = 1 in the cycle the input transitions 0→1 | Edge-memory BOOL |
| FN - Flank Negative | --|N|-- | RLO = 1 in the cycle the input transitions 1→0 | Edge-memory BOOL |
| --[P]-- | --[N]-- | -- | -- |
Both instructions require an edge memory bit whose address must be unique to that instruction. Reusing the same edge-memory bit for two FP blocks causes one of the edges to be lost. A common convention is to reserve M 100.0-M 199.7 as a scratch area for FP/FN helpers, leaving M 0.0-M 99.7 free for global flags and M 200+ free (avoiding the scratchpad range, see Section 8).
8. Scratchpad Flag Warning: Avoid MB200-MB255
Several S7-300 CPUs reserve MB200-MB255 as internal scratchpad memory for the operating system. On the S7-31xC series, the system uses bits in this range for communication diagnostics, time-stamping and internal scheduling. The exact behaviour depends on firmware version:
| CPU | MLFB / order no. | Firmware | Reserved flags |
|---|---|---|---|
| CPU 312C | 6ES7312-5BF04-0AB0 | V3.3 | MB200-MB215 (partial) |
| CPU 313C-2 PtP | 6ES7313-6BF04-0AB0 | V3.3 | MB200-MB255 |
| CPU 315-2 DP | 6ES7315-2AH14-0AB0 | V3.3 / V4.x | MB200-MB255 |
| CPU 317-2 PN/DP | 6ES7317-2EK14-0AB0 | V4.x | MB200-MB255 |
If the application places the FP helper or the continuous-flag marker inside this range, the OS can overwrite it on every OB1 cycle. The result is unpredictable: the marker may flicker, FP may never fire, or FN may fire repeatedly. The fix is to relocate the bits:
- Use M 0.0 to M 199.7 for the user program.
- Or use M 256.0 to M 4095.7 (large S7-300 CPUs allow 4 KB of M area; verify the technical data of your CPU).
- For retentive flags, configure the M-retentive area in HW Config > CPU Properties > Retentive Memory and avoid the scratchpad area.
9. Type Check Toggle in STEP 7 LAD/FBD
STEP 7 enforces type checking in LAD and FBD by default. If the comparator pin expects DINT but the symbol is declared as DWORD, the editor will refuse the wire. There are two legitimate ways to resolve this:
- Preferred - change the symbol's data type to DINT if the value can never exceed 2 147 483 647. This is the cleanest fix and removes the type mismatch permanently.
- Temporary - disable type checking for this network. Open Options > Customize > LAD/FBD and uncheck Type Check of Address. The compiler will accept the wire, but the program becomes prone to silent errors: a REAL wired into a DINT pin will be misinterpreted as a 32-bit bit string instead of triggering a clear compile error.
10. Online Monitoring and Debugging
To verify the logic is live on the CPU, use the standard STEP 7 monitoring features:
- Program Status (LAD/FBD/STL) - right-click inside the block and select Monitor. The comparator highlights green when its result is 1, the marker M 199.0 is shown in dark blue (TRUE) or grey (FALSE).
-
Monitor/Modify (VAT) - create a Variable Table (VAT) with three rows: the source DWORD, M 199.0, and M 199.3. Click the Monitor button. Force the source to
DW#16#0with Modify, then toDW#16#1- the marker should toggle 0→1 and the M 199.3 one-shot should fire exactly once. - Reference Data - Options > Reference Data > Display shows every location where M 199.0 is read or written, helping to track down overwrites.
- Cross-reference for FP/FN - confirm that the edge-memory bits M 199.1 and M 199.2 are not referenced anywhere else in the program.
10.1 Forced Value Test Pattern
Use the following sequence in Monitor/Modify to validate every path:
| Step | Force source DWORD | Expected M 199.0 | Expected M 199.3 |
|---|---|---|---|
| 1 | DW#16#0 | 0 (FALSE) | unchanged from previous |
| 2 | DW#16#1 | 1 (TRUE) | 1 for one cycle, then remains 1 |
| 3 | DW#16#FFFFFFFF | 1 (TRUE) | already 1, no new edge |
| 4 | DW#16#0 | 0 (FALSE) | 0 (FN fired) |
| 5 | DW#16#12345678 | 1 (TRUE) | 1 again on next edge |
11. Verification Procedure
Once the logic is on the CPU, perform the following commissioning checks before handing the system to production:
- Confirm the counter is being updated as expected by reading RealizedQuantity in the VAT. The hex view should change with every counted part.
- Toggle the comparator to 1 by setting the source to 1, then back to 0. The M 199.0 flag must follow in real time.
- Watch M 199.3 (the one-shot) for at least 10 seconds with the counter held at 0. It must stay 0. Then increment the counter by 1 - M 199.3 must pulse high for one OB1 cycle.
- Power-cycle the CPU (STOP→RUN via mode switch or power OFF/ON). Verify that the M-bit state is consistent with the configured retentive behaviour. By default, M flags are non-retentive, so M 199.0 will be 0 after a cold restart regardless of the source value.
- Trigger a diagnostic OB (OB82, OB85, OB121) and confirm that no M bit in the 200-255 range is touched by the OS.
12. Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic | Fix |
|---|---|---|---|
| M 199.0 always 0 even though counter is 1000 | Wrong data type on MOVE source | Open the source DB, verify data type of the field | Change to DINT or use STL L/>D
|
| M 199.0 always 0 in online monitor but works in PLCSIM | Source symbol is in MB200-MB255 scratchpad | Cross-reference shows the symbol address | Relocate the user data outside the reserved area |
| FP fires every OB1 cycle, not just on the edge | Edge-memory bit is also written by user code | Cross-reference for M 199.1 | Use a unique edge-memory bit and remove the redundant write |
| Comparator compiles with red squiggle in LAD/FBD | Type check enabled, DWORD into DINT pin | Hover the pin for the tooltip | Change symbol type, or use STL/SCL for that network |
| Counter value is shown as negative in VAT | Symbol declared as DINT but value > 2 147 483 647 | Read the hex view; if MSB set, value exceeds DINT range | Declare as DWORD, use <>D against L#0 |
| Logic works online but does not appear in HMI | HMI tag points to the wrong DB or to M 200+ scratchpad | Open WinCC flexible / TIA tag list | Re-point the HMI tag to the user M area |
| CPU goes to STOP after download | OB121 not loaded and a conversion error occurred | Diagnostic buffer entry "OB not loaded" | Load OB121 or fix the data type mismatch |
Why does my MOVE box in LAD not transfer the DWORD into a DINT symbol?
MOVE in STEP 7 LAD/FBD enforces strict type checking. When the source is a DWORD and the destination a DINT, the compiler draws a red squiggle. The cleanest fix is to declare the destination as DWORD instead, or to use an STL network with the L/T instructions which reinterpret the same 32 bits without conversion.
Is the CMP >D instruction safe for a 32-bit unsigned piece counter?
Yes, as long as the counter never exceeds 2 147 483 647 (DINT positive range). For higher counts, use CMP <>D against L#0 or a direct test of the unsigned bit pattern. The <>D form is recommended for any counter that may grow beyond the DINT boundary.
Why does my marker flicker in RUN even though the logic is correct?
The marker is most likely in the MB200-MB255 range, which several S7-300 CPUs reserve as scratchpad for the operating system. Relocate the flag, the FP helper and the FN helper to M 0.0-M 199.7 or M 256.0-M 4095.7, and re-verify with Monitor/Modify.
Can I disable STEP 7 type checking to make the MOVE compile?
Yes, via Options > Customize > LAD/FBD > Type Check of Address. Siemens does not recommend this in production because a REAL or POINTER inadvertently wired into a DINT pin will no longer be caught at compile time. Prefer changing the symbol's data type or using STL for the affected network.
How do I trigger a one-shot pulse on the rising edge of the comparator in STL?
Wire the comparator output to a FP instruction with a unique edge-memory bit, and set a marker with the S (set) coil. The companion FN/R pair resets the same marker when the comparator returns to zero. The edge-memory bit must not be written by any other code in the program.