Reading REAL Values from S7-400H DB via Modbus TCP/IP CP 443-1
When a Siemens S7-400H (H-System) is the Modbus TCP/IP server, an external client (SCADA, HMI, OPC UA gateway, or third-party PLC) can only read 16-bit holding registers. A 32-bit REAL value in a Data Block does not map to one Modbus register - it must be split into two consecutive 16-bit words, transmitted, and reassembled in the application layer. This article documents the exact wire format, the CP 443-1 Modbus configuration, the word-order pitfall that causes every wrong-value symptom in the field, and the STEP 7 STL swap block that resolves it.
1. Why Modbus Cannot Carry a REAL Directly
Modbus is fundamentally a 16-bit protocol. The original Modicon specification (1979) and the modern Modbus Application Protocol V1.1b3 define four data primitives:
- Coil (1 bit, read/write)
- Discrete Input (1 bit, read-only)
- Holding Register (16 bits, read/write)
- Input Register (16 bits, read-only)
Function codes FC 03 (Read Holding Registers), FC 04 (Read Input Registers), FC 06 (Write Single Register), FC 16 (Write Multiple Registers), and FC 23 (Read/Write Multiple Registers) all transport 16-bit words. A 32-bit IEEE 754 single-precision REAL therefore occupies exactly two consecutive Modbus registers, and a 64-bit LREAL occupies four.
This is the source of every "I read 0.0" or "I read garbage" symptom. The PLC stores the REAL correctly in the DB; the CP transmits the two halves correctly; but the client interprets the two halves in the wrong order, or treats them as separate INT values.
2. IEEE 754 Single-Precision (32-bit) Format
The S7-400H REAL data type is an IEEE 754 single-precision float. The IEEE Std 754-2008 layout is:
| Bit 31 | Bits 30-23 | Bits 22-0 |
|---|---|---|
| Sign (0=+, 1=-) | Exponent (bias 127) | Mantissa (implicit leading 1) |
Example reference values for field verification:
| REAL | Hex (32-bit) | Word 1 (high) Hex | Word 0 (low) Hex |
|---|---|---|---|
| 0.0 | 0x00000000 | 0x0000 | 0x0000 |
| 1.0 | 0x3F800000 | 0x3F80 | 0x0000 |
| 123.45 | 0x42F6E666 | 0x42F6 | 0xE666 |
| -1.0 | 0xBF800000 | 0xBF80 | 0x0000 |
| +Inf | 0x7F800000 | 0x7F80 | 0x0000 |
When the S7-400H stores a REAL at DB100.DBD4, the four bytes are laid out in little-endian byte order in physical memory. In the Modbus holding register space, this becomes:
- Modbus register N = bytes 0-1 (low-address) = low 16 bits of the REAL
- Modbus register N+1 = bytes 2-3 (high-address) = high 16 bits of the REAL
3. S7-400H Hardware, CP 443-1, and Required Firmware
The S7-400H redundant system (per the Siemens S7-400H Automation System Manual) uses CPUs such as CPU 412-3H, CPU 414-4H, CPU 416-4H, and CPU 417-4H on an SIMATIC UR2-H rack. Modbus TCP/IP server functionality is provided by the CP 443-1 Communication Processor, not the CPU itself.
Verified CP 443-1 part numbers supporting the Modbus/TCP server option:
| Article Number | Variant | Min Firmware | Modbus/TCP HSP |
|---|---|---|---|
| 6GK7 443-1EX30-0XE0 | CP 443-1 (4-port switch) | V3.0 | Required |
| 6GK7 443-1GX30-0XE0 | CP 443-1 IT | V3.0 | Required |
| 6GK7 443-1UX00-0XE0 | CP 443-1 OPC UA | V3.0 | Required |
| 6GK7 443-1EX20-0XE0 | CP 443-1 (legacy) | V2.x | Not supported |
Older CP 443-1 EX20/GX20 modules do not support the Modbus TCP/IP server option and cannot be used for this application. Confirm the firmware version of the installed CP in STEP 7 under PLC → Module Information before commissioning.
The Modbus/TCP server functionality is delivered via the Siemens HSP (Hardware Support Package) "Modbus/TCP PN-CPU" or "Modbus/TCP CP" depending on STEP 7 version. Install the HSP in STEP 7 V5.5 SP4 or later (or the equivalent package in TIA Portal V14+). The HSP adds the partner type "Modbus TCP server" to NetPro and the corresponding configuration dialogs.
4. Word Order: The Root Cause of Wrong REAL Readings
Three word-order conventions are seen in production Modbus TCP/IP deployments:
- Low word first (Siemens CP 443-1 default, Modicon TSX ETY): register N = low 16 bits, register N+1 = high 16 bits. Byte order within each register is big-endian (network byte order) for the wire.
- High word first (some Modicon Unity PRO mappings, some SCADA drivers): register N = high 16 bits, register N+1 = low 16 bits.
- Byte-swapped within word (rare, some Asian vendors): the bytes inside each 16-bit register are reversed on the wire.
When the client expects convention (2) but the S7-400H CP 443-1 sends convention (1), the decoded IEEE 754 value is:
- Zero, Inf, or NaN for most values, because the exponent field (which carries the magnitude information) is replaced by the mantissa and vice versa.
- Sign flip for some values, because the sign bit moves from bit 31 to bit 15 (interpreted as a negative INT or as part of the mantissa).
- Wildly wrong magnitude, often 2^16 or 2^-16 of the correct value.
5. Data Block to Modbus Register Mapping
Configure the CP 443-1 Modbus server in NetPro to map a contiguous range of the S7-400H memory (DB or Merker/Prozessabbild) to Modbus Holding Registers. The default starting address is 40001 (function code 3 offset 0). Example mapping for a 4-channel pressure / temperature block:
| S7-400H Address | IEC Type | Bytes | Modbus Register (FC 03) | Function Code |
|---|---|---|---|---|
| DB100.DBW0 | INT | 2 | 40001 | FC 03 / FC 06 |
| DB100.DBD2 | REAL | 4 | 40002 (low) + 40003 (high) | FC 03 |
| DB100.DBD6 | REAL | 4 | 40004 (low) + 40005 (high) | FC 03 |
| DB100.DBD10 | REAL | 4 | 40006 (low) + 40007 (high) | FC 03 |
| DB100.DBW14 | WORD | 2 | 40008 | FC 03 / FC 16 |
The CP 443-1 transmits Word 0 first (low word of the REAL) and Word 1 second (high word) for the default Siemens Modbus mapping. If the SCADA or third-party client expects high word first, swap the words on either side as described in sections 8 and 9.
6. Configuring the CP 443-1 Modbus TCP/IP Server
- Open the S7 project in STEP 7 V5.5 (or TIA Portal with the appropriate HSP).
- Open NetPro and right-click the CP 443-1 in the rack.
- Select Insert New Connection → partner type Modbus TCP server.
- Assign the CP IP address (e.g., 192.168.0.10) and TCP port 502 (default Modbus port).
- Open the CP's Properties → Modbus configuration dialog.
- Define the data area: starting address in the DB (e.g., DB100, byte 0), length in bytes, mapping to Modbus holding register base 40001.
- Set the byte/word order to Low word first (default) or High word first depending on the client expectation.
- Compile and download the configuration to the CP 443-1 (a full download may be required to activate the Modbus task).
- Cycle power on the CP if the firmware/HSP option is being activated for the first time.
7. Reading REAL: Step-by-Step Procedure
7.1 Prerequisites
- S7-400H with CPU 41x-4H, firmware V6.0 or later
- CP 443-1 EX30/GX30 with firmware V3.0 or later
- STEP 7 V5.5 SP4 (or TIA Portal equivalent) with Modbus/TCP HSP installed
- Target Data Block (DB) compiled and downloaded to the S7-400H
- Any conformant Modbus TCP/IP client (CAS Modbus Scanner, Modbus Poll, openMUC, libmodbus-based app, or another PLC)
7.2 Create the Data Block
In STEP 7, create DB100 with the following structure (Symbol Table or absolute addresses):
DATA_BLOCK DB100
STRUCT
Pressure : REAL; // 4 bytes, DBD0-DBD3
Temperature : REAL; // 4 bytes, DBD4-DBD7
Setpoint : REAL; // 4 bytes, DBD8-DBD11
Status : WORD; // 2 bytes, DBW12
ErrorCode : INT; // 2 bytes, DBW14
END_STRUCT
END_DATA_BLOCK
7.3 Configure CP 443-1 Modbus Mapping
Map DB100 byte 0 onward to Modbus holding register 40001 with the byte/word order matching the client.
7.4 Verify with a Modbus Master Tool
Use a Modbus TCP master to read 2 registers starting at register 1 (the REAL at DB100.DBD2 = Pressure):
MBAP Header: TxID=0001, ProtoID=0000, Length=0006, UnitID=01
PDU: Function=03, StartHi=00, StartLo=01, QtyHi=00, QtyLo=02
Expected PDU response: 01 03 04 [B0 B1 B2 B3] [CRC CRC]
Capture the four response bytes and decode manually:
- If
123.45is the value in the DB, expected hex (little-endian word) isE6 66 42 F6on the wire (4 bytes returned by FC 03 as a single 4-byte data block per the spec, but each pair of bytes is a Modbus register). - Reassemble: low word = 0x66E6, high word = 0xF642. Combined 32-bit = 0xF64266E6, which in IEEE 754 = 123.45 (verify with floating-point calculator).
7.5 Implement Word-Swap on the Server Side (STEP 7 STL)
If the client expects high word first, swap the words inside the S7-400H program before the CP reads them. Add a separate "shadow DB" that holds the swapped copy:
// OB1 cycle - swap REAL values for client readability
// Assume DB100 contains native REAL, DB200 contains swapped copy
L DB100.DBD 0 // Load Pressure (native low-word-first)
T DB200.DBD 0
TAW // Swap bytes within low word (Siemens TAW swaps bytes, not words)
L DB100.DBD 4 // Load Temperature
T DB200.DBD 4
TAW
// For FULL word swap (low word <-> high word), use:
L DB100.DBW 0 // Low word of Pressure
T DB200.DBW 2 // High word of swapped copy
L DB100.DBW 2 // High word of Pressure
T DB200.DBW 0 // Low word of swapped copy
7.6 Implement Word-Swap on the Client Side
If the client is a C/C++ application using libmodbus or a similar library:
// C code - reconstruct REAL from two Modbus holding registers
// Assuming little-endian host (x86, ARM Cortex, etc.)
#include <stdint.h>
#include <string.h>
float modbus_read_real(uint16_t reg_lo, uint16_t reg_hi) {
// Default Siemens CP 443-1: reg_lo is the low 16 bits of the REAL
uint32_t combined = ((uint32_t)reg_hi << 16) | reg_lo;
float value;
memcpy(&value, &combined, sizeof(float));
return value;
}
float modbus_read_real_swap(uint16_t reg_lo, uint16_t reg_hi) {
// For clients expecting high word first
uint32_t combined = ((uint32_t)reg_lo << 16) | reg_hi;
float value;
memcpy(&value, &combined, sizeof(float));
return value;
}
On a Modicon client (Unity PRO / EcoStruxure Control Expert), use the following Structured Text:
// Read 2 words from S7-400H CP 443-1 via Unity Modbus master
arrWords[0] := READ_HOLDING_REGISTERS(Slot := 0, Addr := 1, Qty := 2);
arrWords[1] := READ_HOLDING_REGISTERS(Slot := 0, Addr := 2, Qty := 1);
// If high-word-first expected:
arrSwapped[0] := arrWords[1];
arrSwapped[1] := arrWords[0];
rPressure := REAL_FROM_WORDS(arrSwapped[0], arrSwapped[1]);
8. Verification Procedure
- Force a known REAL value in the S7-400H DB using a VAT (Variable Table) in STEP 7: e.g.,
DB100.DBD0 = 123.45(use the float entry in the VAT, not a hex value). - Connect the Modbus master to the CP 443-1 IP and port 502.
- Issue FC 03 with starting register 1 and quantity 2.
- Capture the raw 4-byte response and verify hex against the IEEE 754 reference table in section 2.
- Confirm the client's decoded float matches 123.45 within 0.001.
- Test with 0.0, -1.0, 1.0, and a value near +Inf boundary (e.g., 1.0E+38) to verify sign and exponent handling.
- Test with at least one negative REAL to verify the sign bit is at bit 31 of the reassembled 32-bit value, not bit 15.
9. Troubleshooting Matrix
| Symptom | Likely Cause | Action |
|---|---|---|
| Client always reads 0.0 | Word order mismatch; low/high words swapped | Swap the two 16-bit words on client or server side; verify with 1.0 (0x3F800000) |
| Value reads as +Inf or NaN | Words combined in wrong order; exponent bits replaced by mantissa | Confirm word order; capture hex response and decode manually |
| Off by factor of 256 or 65536 | Only one word read; client misuses FC 03/04 quantity | Set Quantity = 2 for one REAL, 4 for two, etc. |
| Value appears negated | Sign bit (bit 31) interpreted as part of exponent or mantissa | Confirm 32-bit reassembly, not 16-bit INT interpretation |
| Intermittent connection drops | CP 443-1 keep-alive timeout too low; Modbus watchdog | Increase Watchdog in CP configuration; set TCP keep-alive on client |
| FC 03 returns exception 02 (Illegal Address) | DB number or offset not mapped in CP 443-1 Modbus config | Reconfigure Modbus data area in CP, recompile, download to CP |
| FC 03 returns exception 03 (Illegal Value) | Quantity not 1, 2, or > 125 words | Set Quantity to 2 for one REAL; 4 for two REALs, etc. |
| Value changes when CPU switches to backup | S7-400H redundancy not synchronized for the DB area | Verify DB100 is in the synchronized area; check LINK and RES redundant I/O |
| Hex response correct but client decodes as little-endian DWORD | Client assumes 32-bit register; misuses byte order | Force the client to read 2x 16-bit and combine in client code |
| One REAL is correct, next REAL is shifted by 1 word | DB has an INT between REALs that was not skipped in mapping | Reconcile DB byte layout with CP mapping table; use a continuous REAL block |
10. IEEE 754 Edge Cases in Modbus Transports
Some REAL values round-trip incorrectly through 16-bit Modbus registers when one of the two words is dropped, masked, or out of order. The following edge cases should be explicitly tested in commissioning:
- 0.0 (0x00000000): all bits zero. Reads correctly through any byte or word order, so a zero value is not a good test for word order.
- -0.0 (0x80000000): sign bit set, all others zero. Reads correctly only if the sign bit ends up in bit 31 after reassembly.
- +Inf (0x7F800000) and -Inf (0xFF800000): if the words are swapped, these become NaN (0x7F80xxxx or 0xFF80xxxx with non-zero mantissa), which most clients display as an error or zero.
- NaN (any 0x7Fxxxxxx with mantissa != 0): bit pattern changes non-deterministically under word swap; a stable NaN cannot be guaranteed across the wire.
- Denormals (exponent = 0, mantissa != 0): the smallest non-zero REALs. If either 16-bit word is misread as zero, the value collapses to 0.0.
Always validate the installation with a non-zero, non-Infinity, non-NaN test value (for example, 123.45) before declaring the Modbus path operational.
11. Function Code Reference for REAL Traffic
| Function Code | Mnemonic | Use for REAL | Notes |
|---|---|---|---|
| 01 | Read Coils | No | 1-bit data only |
| 02 | Read Discrete Inputs | No | 1-bit data only |
| 03 | Read Holding Registers | Yes - read 2+ consecutive | Primary code for DB-served REAL values |
| 04 | Read Input Registers | Yes - read 2+ consecutive | Used when source is PIW (analog input image) |
| 05 | Write Single Coil | No | 1-bit data only |
| 06 | Write Single Register | No | REAL requires 2 registers; use FC 16 |
| 15 (0F hex) | Write Multiple Coils | No | 1-bit data only |
| 16 (10 hex) | Write Multiple Registers | Yes - write 2+ consecutive | Standard write path for one or more REALs |
| 23 (17 hex) | Read/Write Multiple Registers | Yes | Atomic read+write; rare in S7-400H CP 443-1 |
12. S7-400H Redundancy Considerations
Because the S7-400H is a hot-standby system with two CPUs running in parallel, the DB area mapped to the CP 443-1 must be part of the synchronized data. Siemens documentation specifies that DBs in the "non-synchronized" or "CPU-local" area are not guaranteed to be consistent across a failover. If the CP is wired to the primary rack only, it will lose connection for the duration of the switchover (typically < 100 ms). If the CP is wired to both racks (redundant CP configuration), the Modbus client should see no interruption provided the keep-alive timeout is longer than the switchover time.
Recommendations:
- Map only synchronized DBs to the Modbus server.
- Configure both CPs in redundant mode if 100% Modbus availability is required.
- Set client TCP keep-alive to at least 1000 ms to absorb a single switchover.
- Use Modbus function code 03 (read-only) for control-critical process values to avoid split-brain writes during failover.
Why does my Modbus client always read 0.0 for every REAL value?
The most common cause is the client assembling the two 16-bit registers in the wrong order. The Modbus Application Protocol V1.1b3 does not standardize word order for multi-register values. Swap the low and high words on the client side, or confirm the CP 443-1 Modbus configuration is set to the byte/word order your client expects. Verify with a known value like 1.0 (0x3F800000) before commissioning.
Can I read or write a REAL with Function Code 06 (Write Single Register)?
No. FC 06 writes a single 16-bit register. To write a REAL, use FC 16 (Write Multiple Registers) with a quantity of 2, sending both the low and high 16-bit words in a single transaction. Reading a REAL also requires FC 03 or FC 04 with a quantity of 2.
What is the difference between Function Code 03 and Function Code 04 for REAL values?
Function Code 03 reads Holding Registers (read/write data). Function Code 04 reads Input Registers (read-only data, typically mapped from analog input process image). Both return 16-bit words. The S7-400H CP 443-1 with the Modbus/TCP HSP typically maps user-configured DB areas to FC 03; FC 04 is used when the source is a PIW (Periphery Input Word) or directly from the analog input module.
How do I swap the word order of a REAL in STEP 7 STL?
Use a manual two-load/two-transfer sequence to move the low 16-bit word to the high position and the high word to the low position in a shadow DB. The TAW (Swap Bytes within Word) instruction swaps bytes inside a single 16-bit word, not words across a 32-bit REAL. The example STL in section 7.5 shows the correct sequence. Alternatively, use the SWAP_I / SWAP_DWORD function from the IEC 61131-3 standard library on a Modicon client.
Does the CP 443-1 need a special firmware option for Modbus TCP/IP server mode?
Yes. The Modbus TCP/IP server functionality on the CP 443-1 requires the Siemens HSP (Hardware Support Package) for "Modbus/TCP CP" and a CP 443-1 EX30 or GX30 with firmware V3.0 or later. Older CP 443-1 EX20/GX20 modules do not support the Modbus TCP/IP server function and must be replaced. After installing the HSP, cycle power on the CP to activate the new functionality.