Problem Statement: Step 5 Subtraction Yields Two Different Values
A standard SUB (subtraction) network in a SIMATIC S5 FB33 produces a value in the programmer's status display that does not match the value seen downstream in PB65:
L FW 108 // Load Flag Word 108
L DW 35 // Load Data Word 35 from opened DB
-F // 16-bit integer subtraction, result in ACCU 1
T FW 106 // Transfer ACCU 1 to Flag Word 106
JU PB 65 // Unconditional jump to PB 65
While the program is in STOP with the cursor sitting on the T FW 106 line, the STEP 5 online status (PG or PG-Via-LAN) shows:
| Operand | Display | Interpretation |
|---|---|---|
| FW 108 | KF+20 | Source A = +20 |
| DW 35 | KF+731 | Source B = +731 |
| FW 106 (status) | KF+10 | Displayed result = +10 |
| FW 106 (in PB 65) | KF-1 | Observed downstream = -1 |
Arithmetic on the operands the operator is watching gives 20 − 731 = −711; +10 in the status window is therefore already wrong in absolute terms. The downstream reading of −1 is yet a third, inconsistent value. Both observations come from the same scan, and both can be correct under STEP 5 semantics once you understand what the PLC is actually doing with the operands.
STEP 5 Quick Reference for the Operands in Use
The mistake almost always arises from confusing symbolic names with physical addresses. The mnemonics used in the network above map onto specific memory areas of the S5 CPU:
| Mnemonic | Area | Width | Range (S5-115U example) | Use |
|---|---|---|---|---|
| FW | Flag / Merker | 16 bits | FW 0 ... FW 254 | Bit-scratch and intermediate results, retained only for the current scan unless declared retentive |
| DW | Data word in currently opened DB | 16 bits | DW 0 ... DW 255 per DB | Process data associated with a DB |
| MW | Not standard S5; some S5-155U H CPUs expose | 16 bits | CPU-specific | Process image / extended flag |
| PB / FB / OB / SB | Program / Function / Organization / Step blocks | Code | PB 0 ... PB 255, FB 0 ... FB 255, OB 1 ... | Logic containers |
Every DW operand is a data word inside whatever data block has been opened with A or AX just prior to the access. DW 35 is meaningless without that DB context; DW 35 in DB 4 is a different physical cell from DW 35 in DB 7.
The Arithmetic Operation `-F` in Detail
STEP 5 has three integer subtractions. Make sure you used the one that matches your data type:
| Op | Operands accepted in ACCU 1 / ACCU 2 | Result type | Range |
|---|---|---|---|
-F |
16-bit fixed point (KF / DH) | 16-bit signed fixed point | −32768 ... +32767 |
-G |
32-bit fixed point (KG / DG) | 32-bit signed fixed point | −2147483648 ... +2147483647 |
-D |
BCD coded (real number as BCD) | Real (32-bit) | ≈ ±3.4·1038 |
The example uses -F, which on 20 − 731 must yield KF -711 (or overflow behaviour for the 16-bit wraparound). KF +10 in the status display is therefore either a sign/data-type misinterpretation in the display or, far more commonly, a sign that FW 108 or DW 35 you are inspecting is not the same physical cell the CPU actually used to execute the network.
16-bit signed wrap examples
FW108 = +20, DW35 = +731 -> 20 - 731 = -711 (KF -711)
FW108 = +20, DW35 = -731 -> 20 - (-731) = 751 (KF +751)
FW108 = +20, DW35 = 0
Acc2=+731 Acc1=+20 subtract = Acc2 - Acc1 = +711 (KF +711)
If you change DW 35 between the program doing the subtraction and you reading the status, the displayed operand value can be valid for the display but no longer relevant for the executed operation.
Why the Online Status Window Disagrees with PB 65
Three effects are layered on top of each other; any one of them is enough to produce a non-intuitive mismatch.
1. The STEP 5 status is only coherent at OB 1 boundaries
In cyclic OB 1 processing, the PG or STEP 5 > STATUS BLOCK view is refreshed at the end of the OB 1 pass, not continuously during execution. The values shown in the status variable list are the values present after the most recent OB 1 completion. If your subtraction network is inside FB 33 and FB 33 is called from multiple points in OB 1, the displayed FW 106 reflects the most recent write regardless of which call you are looking at.
In S5, the standard OB1 cycle runs in milliseconds. A status snapshot taken with the program in RUN reflects the state at the trailing edge of the previous OB 1 pass, not the current scan position.
2. `FW` is shared scratch memory - any block can write it
Flag words are not local. FW 106 can be written by FB 33, by an FB 12 instance that happens to use the same intermediate, or by a direct T FW 106 elsewhere in OB 1. The most common cause of the exact symptom shown here is that another network overwrites FW 106 after FB 33 writes it but before PB 65 reads it. If the unconditional jump follows that second write, PB 65 sees the second value, not the subtraction result.
3. DB context / opened DB may differ between sites
DW 35 refers to the offset 35 in the currently opened DB. If a block runs AX DB 9 somewhere between the subtraction and PB 65's read, the address DW 35 silently points to offset 35 of DB 9, not of DB 4. The status view (which is anchored in the DB that was active when the debugger opened) and the runtime read in PB 65 are then looking at two different physical cells.
Root Cause in the Original Case
Re-reading the operator's follow-up: "I just figured out that the reason for my problems is DW 109 and everything else is fine — merely I was looking for a value of 10 in PB 65 but realized where the issue is after checking values."
This is the canonical fingerprint of effect (2). A second write to the same flag word was happening, and DW 109 of some DB was being copied into FW 106 by a different network or function block. The status snapshot just before JU PB 65 showed the residual of the subtraction (KF +10 arithmetic noise / last-coincidence value), and at the entry of PB 65 the runtime was already showing the freshly written value the operator had been tracking (here, a flag driven by a different DW 109 source). The arithmetic in the original network was innocent.
Diagnostic Methodology
Follow this ladder; each step is non-destructive.
-
Capture both windows simultaneously. Place the cursor in
FB 33on the line afterT FW 106and request status, then request status again from insidePB 65. If the values agree, the CPU is consistent and your mental model is wrong. If they disagree, the runtime between the two points of observation modified memory. -
Cross-reference writes to the operand. In STEP 5, search the entire project (FB, PB, OB, SB and the called function blocks) for every
T FW 106. Use the cross-reference listCTRL+F5 > Cross Refsin classic STEP 5, orIST Editor > References. Any hit afterFB 33is a prime suspect. -
Inspect operand
DW 35at the same scan. ReadDW 35in DB 4 explicitly before and after the operation. If the value displayed in the operator's snapshot was being supplied by a different DB, the read in DB 4 will not match. -
Watch
FW 108at the entry of FB 33. IfFW 108is the result of a multiplication, a counter or a BCD conversion performed earlier in OB 1, its value at the point of subtraction will differ from its value at any pre-OB 1 snapshot. A stuckKF +20in the live view is a hint that another path is overriding the counter before this network ever sees it. -
Disable subcalls. In
RUN, set a single-shot breakpoint at the end ofFB 33by inserting aSTPat that location briefly. ReadFW 106directly from PG. Now single-cycle to PB 65's input read. Compare. -
Use the runtime test mode. In the S5 tester, set
RUN-Tmode on PG so you can single-step. This eliminates the OB1-update assumption and any cross-task write.
Status Block vs. Status Variable: Two Different Tools
The STEP 5 programmer exposes two complementary views. Knowing which one to use is critical:
| Tool | What it shows | When to use it |
|---|---|---|
Status Variable (CTRL+F5) |
Coherent copy of selected operands at OB1 end-of-pass; refreshed cyclically | Quick check during RUN; bias: lagged by one full cycle |
Status Block (CTRL+F7) |
Block-internal accumulator, status word and operand values at the program line where the cursor sits | Debug a single network live; you see what that specific network just did |
| Force / Set / Reset Variable | Write to operand, never read | Drive a value into a suspect input |
| IST / Cross Reference | All references to an operand across the program | Detect double-write before runtime ever runs |
Use the Status Block, not Status Variable, while you sit on the line under suspicion. Status Variable gives the cycle-end view; Status Block gives the runtime view at your program line.
Step-by-Step Reproduction & Verification Procedure
- Open STEP 5 in offline or online mode targeting the CPU (e.g., S5-115U, AG 115, AG 135, AG 150).
-
Load project and bring
FB 33plusPB 65into working windows. -
Open DB 4 explicitly with
A DB 4in OB 1 prior toFB 33if not already done. -
Set a breakpoint or cursor on the
T FW 106line inFB 33; pressCTRL+F7to enter Status Block. -
Trigger a single scan. From the PG, force
RUN-Tor setStatus / Single Cycle; observe ACCU 2, ACCU 1, status word CC 1/CC 0/OV/OS. -
Verify CC bits: after
-Fthe CC 1 / CC 0 pair must encode the signed comparison of the result. CC 1 = 1, CC 0 = 1 means result < 0. -
Single-cycle into
PB 65and readFW 106again from the Status Variable list immediately afterward. -
Compare: if the Status Block and PB 65 entry agree, the subtraction is correct. The discrepancy then is purely a result of an intervening write to
FW 106, a DB swap, or a conversion that PB 65 performs immediately on its input.
Common Pitfalls Specific to S5
Operand aliasing by symbolic names
STEP 5 supports symbolic names (Symbol Table, SYMBOL EDITOR). Two different symbols can resolve to the same absolute operand FW 106. Cross-references computed on a single symbol will not list the alias writes.
Indirect addressing and the offset confusion
L DW [FW200] reads DW where the index is in FW 200. If a probe sets FW 200 to a different value while you are looking at the screen, the runtime references jump to a different cell than your display does. Always check whether the operands in your suspicious network are absolute or indexed.
DB rights and the wrong DB
DW 35 in DB 4 may be read-only in that DB (e.g., a parameter DB). If you alter it from PG, the read-back shows new value but the runtime still sees the snapshot loaded for that OB pass.
Counter / timer PV versus CV
If FW 108 is the PV of a counter block and DW 35 is the CV, then reading either at the wrong instant of the count cycle will not give the post-subtraction number. JU PB 65 may then operate on values that are mid-update.
Process image vs extended I/O
The PII / PIQ tables are not interchangeable with flag memory. Treat anything wired through I, IB, QW, QD differently from FW when timing is in question.
Service / startup OBs
OB 21 / OB 22 (warm / cold restart) and OB 100 (in newer S5-155U H versions) can execute initialization code that touches flag memory and data blocks. A subtraction network that runs in the first cycle after STOP > RUN transition can produce a transient value that the steady-state OB 1 cycle never reproduces.
Verification Checklist After the Fix
| Verification | Tool | Acceptance |
|---|---|---|
| FW 106 = expected subtraction result at the entry of PB 65 | Status Block in PB 65 first network | Value matches arithmetic on FW 108 - DW 35 |
| No cross-write between FB 33 and PB 65 | Cross Reference list on FW 106 | Single write in FB 33 / absent elsewhere |
| Stable across 50 consecutive OB 1 cycles | Status Variable, single-cycle to 50 | No drift, no overflow, CC consistent |
| DB pointer unchanged | Status word ANZ1 / ANZ0 in OB1 / FB 33 | DB register matches between sites |
| Watchdog / SF LED | CPU front panel | No SF, no OB 26 stop fault during test |
Field-Engineering Recommendations
-
Reserve flag ranges per scope. Adopt the convention
FW 200 ... FW 254for inter-block scratch, and never write to those flags inside application blocks. This makes any cross-write visible at commissioning time. - Pass intermediate results through their own DB. When an intermediate value must travel across an unconditional jump, store it in a dedicated DW in a private DB rather than into a flag. DW values then cannot be clobbered by FB instance code.
-
Avoid unconditional
JU PB xchains in OB 1; prefer oneSPB / SPAtable per cycle. This forces a visible call order in the cross-reference and stops silent jumps to PB 65 from hiding writes. - Label subtraction operands on both sides. Use symbols on every operand so that double-name issues surface during symbol table cross-checks.
-
Run a self-test sequence in
OB 100/ restart code that writes known constants to all flag and data areas the program uses, then asserts the expected subtraction results; an alarm on mismatch is a fast alarm on future regressions. -
Where STEP 5 substitutes for STEP 7: remember that
FCin STEP 7 retains a similar scratch-merker behaviour with the multi-instance DB, so the diagnostic philosophy carries forward, even though the syntax changes.
Edge Cases That Look Like a Subtraction Bug but Are Not
Conversion rounding
If FW 106 is a fixed-point result displayed as KF+10 while downstream is a counter that interprets it as BCD, that single bit difference 10010BCD vs 10hex is the entire apparent mismatch. Validate the downstream block's input declaration, not the subtraction.
Negative vs. sign-extension
FW 106 = KF -1 as a 16-bit signed word is hex 0xFFFF. If PB 65's input is a 32-bit accumulator and the load does sign-extension, you may be re-interpreting 0xFFFFFFFF as -1, where another site might mask to 0x00FF for BCD purposes.
Forced variable from PG
Forcing FW 106 from Force Variable overrides every program write of that cell. If an operator is forcing FW 106, the subtraction result will appear correct briefly after the T, then the forced value reasserts before PB 65 sees it. PG-side forced values are persistent across STOP > RUN until cleared.
Compatibility Notes (S5 family)
| CPU family | Typical use today | Flag range | DB range | Notes |
|---|---|---|---|---|
| S5-90U / 95U | Compact, OEM | FW 0..127 typical, expand to 255 | DB 1..31 (small) | Limited DW per DB; double-check |
| S5-115U | Plant floor, very common | FW 0..254 (CPU-specific) | DB 1..255, 256 DW per DB | Most common platform for legacy STEP 5 |
| S5-135U / 155U | Process control | FW 0..2047+ in 155U H | DB 1..255 / 1..4095 | Increased memory, more useful for indirect operands |
Operator advice originally given was targeting a CPU compatible with DB 4 and flag memory in the FW 0..254 range, which fits comfortably in any of the above. If you are running S5-155U H with multi-instance flag extensions or with the CFs (communications processors), the cross-reference tool should be invoked with extra care; instance FBs reuse the same flag area by configuration.
Related Resources
- Siemens SIMATIC S5 ST programmable controller catalog (system overview)
- STEP 5 Basic Programming Manual (operations:
L, T, A, AX, JU, JC, -F, -G, -D) - STEP 5 Reference Manual - Integer and floating-point arithmetic
- S5-115U / 135U / 155U System Manual - CPU flags, DB layout, restart OB
Why does the status variable show KF+10 while the arithmetic 20 - 731 should yield -711?
The status variable view is a coherent snapshot taken at the end of OB 1, not at the moment of the subtraction. If any code path between the subtraction network and the next cycle termination has touched the accumulator or the carry bits, or has signed-extended from an earlier operation, the displayed KF value can lag or reflect a co-incidental value rather than the actual -F result. Always read the Status Block on the exact line of T FW 106 for the in-cycle truth.
How do I detect a double-write to FW 106 in STEP 5?
Use the cross-reference table (IST Editor > Cross References) on the absolute operand FW 106. The table will enumerate every T FW 106, every L FW 106, and every indirect reference. Any T to FW 106 outside the network you suspect is the culprit.
Is DW 35 always the same cell across the program?
Only within the data block that is currently open (A DB n or AX DB n). DW 35 in DB 4 and DW 35 in DB 7 are different cells. Before DW 35 is referenced, ensure the matching DB is opened, and check that no AX call swaps the DB register between the writer and the reader.
Should I prefer JU PB 65 over calling FB 65?
Unconditional jumps to PB blocks are legal but they bypass the parameter-passing interface and the local-merker scoping that FBs provide. They are usually a debugging convenience, not a production pattern. Convert PB callouts into JU FB 65 with parameter passing into a private DB once the logic stabilizes, and the double-write class of bug becomes much rarer.
What CC bits should I expect after -F with positive result, negative result, and zero?
Status bits CC 1 and CC 0 reflect the signed comparison of the result. For positive result (KF > 0): CC 1=0, CC 0=1. For negative result (KF < 0): CC 1=1, CC 0=0. For zero (KF = 0): CC 1=0, CC 0=0. For overflow on signed 16-bit (result outside -32768..+32767): CC 1=1, CC 0=1 and OV is set. If your observed status-word bits disagree with the math, you are looking at the wrong cycle end.