Problem Definition
When integrating a third-party Modbus TCP energy analyzer with SIMATIC WinCC Flexible Runtime, attempting to bind a 32-bit IEEE 754 floating-point value to a Modbus input register (function code 04, address range 3xxxx) fails at the tag editor: the %IW address field is disabled whenever the tag data type is set to Real (REAL, 32-bit). The same editor allows %MW addressing for floating-point tags. Reading the same register as a 16-bit INT or WORD at consecutive %IW addresses returns only the high or low 16-bit half of the 32-bit value, producing incorrect scaled or zero data. Inserting an OPC server (for example KEPwareEX) between the energy analyzer and WinCC Flexible resolves the data type issue but introduces 200-500 ms update latency per polling cycle, which is unacceptable for real-time energy monitoring.
Reported field configuration:
- HMI software: SIMATIC WinCC Flexible Runtime (PC or panel-based)
- Driver: Modicon Modbus TCP/IP (WinCC Flexible built-in protocol)
- Target PLCs: Schneider Electric Modicon Premium (TSX P57 series) and Modicon Micro (TSX 37 series)
- Source device: third-party energy analyzer publishing 32-bit float in input register 30218 (function code 04, 3xxxx address space)
- Network: 10/100 Mbps Ethernet, Modbus TCP/IP port 502
Observed Tag Editor Behavior
| Tag Data Type | %IW Field | %MW Field | Driver Read Behavior |
|---|---|---|---|
| BOOL, INT, UINT, WORD | Enabled | Enabled | Single 16-bit register read |
| REAL, DINT, DWORD | Disabled (greyed out) | Enabled | Two consecutive 16-bit registers, reassembled to 32 bits |
INT or WORD to REAL. The tag editor will not accept a 32-bit binding at any %IW-prefixed address, regardless of the input register number.Root Cause Analysis
The Modicon Modbus TCP/IP driver inside WinCC Flexible enforces a hard-coded separation between 16-bit and 32-bit bindings on the Modicon memory model:
- 16-bit data types (INT, UINT, WORD, BOOL): the tag editor allows binding to either %IW (Input Word) or %MW (Memory Word). The driver issues a single Modbus function code 04 (Read Input Registers) or 03 (Read Holding Registers) and presents the 16-bit payload as the tag value.
- 32-bit data types (REAL, DINT, DWORD): the tag editor permits binding only to %MW. The driver reads two consecutive 16-bit registers and reassembles the bytes into a 32-bit value in the correct IEEE 754 or signed/unsigned integer layout. The %IW area is intentionally excluded because the Modicon convention reserves %IW for physical input modules, which are intrinsically 16-bit.
- Source area mismatch: when the data originates in the 3xxxx (input register) Modbus space, no direct 32-bit binding path exists in the tag editor. The driver does not provide a "float at %IW" option.
This behavior is a design constraint of the driver and tag editor, not a bug. It cannot be removed by project configuration. Three independent constraints produce it: the tag editor's data-type-to-address-area binding table, the driver's atomic 32-bit read implementation, and the Modicon hardware convention that ties %IW to discrete 16-bit module inputs.
Modbus Memory Model and Modicon Addressing
Per the Modbus Application Protocol specification, the protocol defines four primary address spaces:
| Prefix | Name | Function Code | Access | Bit Width |
|---|---|---|---|---|
| 0xxxx | Coils | 01, 05, 15 | Read/Write | 1 bit |
| 1xxxx | Discrete Inputs | 02 | Read-only | 1 bit |
| 3xxxx | Input Registers | 04 | Read-only | 16 bits |
| 4xxxx | Holding Registers | 03, 06, 16 | Read/Write | 16 bits |
A 32-bit IEEE 754 single-precision float occupies two consecutive 16-bit registers. The high word is transmitted first on the wire (Modbus is big-endian by default). For input register 30218 containing a float, the full payload is 30218 (high word) and 30219 (low word).
Modicon Symbol Syntax
In Modicon / Schneider Electric PLCs, the %-prefixed symbol notation distinguishes memory areas:
| Symbol | Meaning | Modbus Source |
|---|---|---|
| %MW | Memory Word (internal RAM) | Holding registers (4xxxx) |
| %IW | Input Word | Input registers (3xxxx) |
| %QW | Output Word | Output coils/registers (0xxxx, 4xxxx write) |
| %M | Bit (internal memory) | Internal coils |
| %I | Bit (input) | Discrete inputs (1xxxx) |
The WinCC Flexible Modicon Modbus TCP/IP driver maps these symbols onto Modbus address ranges. The default mapping is:
- %MW0 ↔ Modbus holding register 40001
- %IW0 ↔ Modbus input register 30001
- %MD0 covers %MW0 and %MW1 (32-bit atomic access)
For a 32-bit REAL at %MW100, the driver reads Modbus registers 40101 and 40102 and reassembles them as an IEEE 754 float. The same 32-bit reassembly is not offered at %IW because the %IW area is exposed as a stream of 16-bit values only.
Why 16-bit %IW Cannot Carry a 32-bit Float in This Driver
Three independent constraints converge to produce the observed behavior:
-
Tag editor constraint: the dialog box hard-codes the address area based on data type. Selecting
REALforces %MW and disables %IW. There is no user setting to override this. - Driver runtime constraint: the 32-bit read path issues two back-to-back function code 04 requests for consecutive registers and expects the result to be written into a 32-bit-coherent %MW location. The %IW area is a 16-bit stream without a guaranteed 32-bit atomicity contract.
- Modicon convention: %IW historically refers to physical input module words on Modicon Premium/Micro racks (TSX DEY/DIY/DIY16 modules). These are 16-bit by hardware, and the symbol set was carried into the Modbus driver to maintain naming parity with the rack I/O convention.
None of these constraints can be relaxed in the project. Workarounds must respect the binding rule: 32-bit types must land in %MW, even if the original Modbus source is in 3xxxx.
Solution Paths Overview
Four practical approaches resolve the issue. They are listed in order of increasing hardware complexity:
| # | Approach | Modifies PLC | Adds Hardware | Update Latency | Best For |
|---|---|---|---|---|---|
| 1 | Read as two 16-bit %IW tags, combine in VBScript | No | No | 250 ms (HMI cycle) | Small systems, single energy meter |
| 2 | PLC reads input register, mirrors to %MD | Yes (Unity Pro) | No | 100-200 ms (PLC scan) | Existing Premium/Micro PLC, multiple tags |
| 3 | Modbus gateway remaps 3xxxx to 4xxxx | No | Yes (gateway) | 50-100 ms (gateway) | Many 3xxxx devices, transparent mapping |
| 4 | OPC server with built-in float handling | No | Yes (OPC server) | 200-500 ms (OPC) | Large fleets, central SCADA |
For most field deployments where an OPC server is too slow, Solution 1 (VBScript combination) is the fastest to deploy, and Solution 2 (PLC-side mirroring) is the most robust for long-term operation.
Solution 1: Two %IW Tags Combined in VBScript
This approach reads the energy analyzer's 3xxxx input register as two separate 16-bit INT tags at consecutive %IW addresses, then combines them in a WinCC Flexible VBScript into a single REAL tag. No PLC changes are required and no OPC server is introduced.
Prerequisites
- SIMATIC WinCC Flexible 2008 SP2 or later (Runtime or Engineering)
- Configured Modicon Modbus TCP/IP connection to the energy analyzer
- Energy analyzer exposing 32-bit IEEE 754 float at input register 30218 (0-based offset 217)
- VBScript license activated in the HMI project
Step-by-Step Procedure
Step 1: Add the High-Word INT Tag
- Open the WinCC Flexible project in the engineering software.
- Navigate to Communication → Tags and add a new tag named
Energy_HiWord. - Select the Modicon Modbus TCP/IP connection as the source.
- Set the data type to
Int(16-bit signed). - Set the address to
%IW217(input register 30218, 0-based offset). - Set acquisition mode to Cyclic continuous, 250 ms update cycle.
- Save the tag and download the project to the HMI.
Step 2: Add the Low-Word INT Tag
- Add a second tag named
Energy_LoWord. - Set the data type to
IntorWord. - Set the address to
%IW218(input register 30219, 0-based offset). - Match the acquisition cycle of the high-word tag.
- Save and download.
Step 3: Add the Combined REAL Tag
- Add a new tag named
Energy_kWwith data typeReal. - Bind it to the Internal area (no driver connection). The value will be written by VBScript.
- Set acquisition mode to Cyclic continuous, 250 ms update cycle.
Step 4: Write the VBScript Combination Function
Create a new VBScript function CombineWordsToFloat in the project's script library. The implementation handles Modbus standard big-endian word order:
Function CombineWordsToFloat(hiWord, loWord)
' Combine two 16-bit Modbus words into a 32-bit IEEE 754 float.
' Word order: Modbus big-endian (high word first, low word second)
Dim longValue, signBit, exponent, mantissa, result
' Reassemble 32-bit unsigned integer from two 16-bit words
longValue = (CLng(hiWord) And &HFFFF&) * 65536
longValue = longValue + (CLng(loWord) And &HFFFF&)
' Extract IEEE 754 single-precision fields
signBit = (longValue And &H80000000) / &H80000000
exponent = (longValue And &H7F800000) / &H800000
mantissa = (longValue And &H007FFFFF) / &H800000
' Decode
If exponent = 0 Then
result = 0
ElseIf exponent = 255 Then
result = 0 ' Inf/NaN: substitute 0 to avoid script abort
Else
result = (2 ^ (exponent - 127)) * (1 + mantissa)
If signBit = 1 Then result = -result
End If
CombineWordsToFloat = result
End Function
If the energy analyzer publishes the float in little-endian word order (low word first), swap the operands at the call site. The IEEE 754 fields above assume Modbus-standard big-endian word ordering per the Modbus Application Protocol Specification V1.1b3.
Step 5: Schedule the Combination
- In WinCC Flexible, open Schedules.
- Add a new schedule named
UpdateEnergywith a 250 ms cycle. - Link the schedule to a VBScript action that calls
CombineWordsToFloat(SmartTags("Energy_HiWord").Value, SmartTags("Energy_LoWord").Value)and writes the result toSmartTags("Energy_kW").Value.
Step 6: Bind the Result to the HMI Screen
- Open the energy display screen.
- Add an Output field bound to the
Energy_kWtag. - Format the field with one decimal place (e.g.,
999.9).
Solution 2: PLC-Side Mirroring in Modicon Premium / Micro
For installations with a Modicon Premium or Micro PLC already present, the PLC can act as a Modbus TCP master to the energy analyzer and write the reassembled float into its own %MW / %MD area. The HMI then reads the float directly from a 32-bit %MW location, eliminating the script-based workaround.
Step 1: Configure the PLC Ethernet Port
- Open the project in Unity Pro (now branded EcoStruxure Control Expert) for Modicon Premium/Micro.
- Add the Ethernet communication module (TSX ETY 110/120/4103 for Premium, TSX ETZ 410/510 for Micro).
- Configure IP address, subnet mask, and gateway to match the plant network.
- Enable the Modbus TCP server on port 502.
Step 2: Add a Modbus TCP Master Read Block
In Unity Pro, drop a READ_VAR function block into the MAST task. Configure it as follows:
| Parameter | Value |
|---|---|
| Slave IP | Energy analyzer IP address |
| Slave Unit ID | 255 (typical for Modbus TCP) |
| Function Code | 4 (Read Input Registers) |
| Starting Register | 217 (0-based offset for 30218) |
| Number of Registers | 2 (one 32-bit float) |
| Destination | %MW100:2 (two consecutive words) |
| Management Parameter | Word at %MW200 for status |
Step 3: Reassemble the Float at the PLC
The %MW area is byte-addressable in Modicon PLCs. To combine the two 16-bit words into a 32-bit float:
- Use the
REAL_CONVor equivalent floating-point conversion function block to read the 32-bit value from %MW100:%MW101 as a single %MD100 location. - Alternatively, write the reassembled float back into a separate %MD (e.g., %MD110) using a MOVE block in Structured Text or Ladder.
- For Modicon Micro (TSX 37) using PL7 Junior/Pro, the equivalent operation uses the floating-point arithmetic block, which consumes two consecutive %MW words and produces a %MF (Memory Float) result.
Step 4: Configure the WinCC Flexible Tag for Direct Float Read
- Add a new tag named
Energy_kWin WinCC Flexible. - Set the data type to
Real. - Set the address to
%MD110(or %MW110, depending on driver interpretation; verify with the driver help). - The driver reads the 32-bit float directly from the Modicon PLC's %MD area via a single function code 03 holding register read.
Step 5: Verify End-to-End
- Force a value on the energy analyzer (e.g., 100.0 kW).
- Watch
%MD110in Unity Pro's animation table. Expect 100.0. - Watch the
Energy_kWtag in WinCC Flexible. Expect 100.0.
Solution 3: Modbus Gateway / Protocol Converter
If neither VBScript nor PLC-side mirroring is acceptable, a standalone Modbus gateway can remap the energy analyzer's input registers into a virtual Modbus slave's holding registers. The HMI then reads floats from the holding register area using the standard float tag binding.
Supported Hardware
- HMS Anybus X-gateway Modbus TCP
- Moxa MGate MB3170 / MB3270 series
- Schneider EGX300 / Link150 gateway
- Red Lion Data Station Plus
Configuration Example (Moxa MGate MB3170)
- Set the MGate as a Modbus TCP server (downstream to the HMI).
- Configure the upstream connection to the energy analyzer as a Modbus TCP client.
- Define a mapping rule: input register 30218-30219 → holding register 40001-40002 on the virtual server.
- Point the WinCC Flexible Modicon Modbus TCP/IP driver to the MGate's IP address as the slave.
- Read the float at
%MW0(which now transparently carries the energy analyzer's 3xxxx float payload).
Verification Procedure
After implementing any of the three solutions, run the following checks before sign-off:
1. Static Value Test
- Force the energy analyzer to a known value (e.g., 1234.56 kW).
- Check the HMI display matches within ±0.01 kW.
- Cross-check the raw
Energy_HiWordandEnergy_LoWordvalues against the IEEE 754 hex encoding:
| Decimal Value | IEEE 754 Hex | High Word (dec) | Low Word (dec) |
|---|---|---|---|
| 0.0 | 0x00000000 | 0 | 0 |
| 1.0 | 0x3F800000 | 16256 | 0 |
| 1234.56 | 0x449A51EC | 17562 | 20972 |
| -100.0 | 0xC2C80000 | 49824 | 0 |
| 1.0E+38 | 0x7F7FFFFF | 32639 | 65535 |
2. Range Sweep
- Sweep the energy analyzer input from 0.0 to full scale.
- Check for linear response with no sign flip, no scale error, and no dead band.
3. Negative Value Test
- If the energy analyzer reports negative values (e.g., export power in a PV system), force -100.0.
- Verify the sign is preserved end-to-end through the binding, the driver, and the HMI display.
4. Endianness Check
- Compare the HMI value against the energy analyzer's web interface or local display.
- If the value reads as 0.0000, a very large number (~1.7E+38), or a very small number (~1.2E-38), the word order is reversed. Swap the high and low word arguments in the VBScript or check the gateway mapping table.
5. Polling Latency Check
- Trigger a step change on the energy analyzer.
- Measure the time from the step event to the HMI display update.
- Acceptable latency for energy monitoring dashboards: 1-2 seconds.
Troubleshooting Matrix
| Symptom | Likely Cause | Resolution |
|---|---|---|
| %IW field greyed out for float tag | Driver design (by design) | Apply Solution 1, 2, or 3 |
| Value reads as 0.0000 | Word order reversed | Swap high and low words in the script |
| Value reads as ~1.2E-38 | Exponent bits misread, sign handling off | Confirm function code is 04 (Read Input Registers) |
| Value reads as ~1.7E+38 | Exponent all-ones, mantissa non-zero | Verify the input register base address (off-by-one error between 0-based and 1-based) |
| Value oscillates between two readings | Polling cycle too short, two reads not atomic | Increase the poll cycle to 500 ms or use PLC-side atomic read (Solution 2) |
| Connection drops intermittently | TCP keepalive mismatch | Enable Modbus TCP keepalive on the gateway / PLC Ethernet port |
| Value stable but wrong by a factor of 10 | Modbus register address offset wrong | Verify 0-based vs 1-based addressing (30218 → 217 or 218) |
| %MW field accepts float but reads garbage | Holding register (4xxxx) misread as 3xxxx | Reconfigure the driver connection or use the correct prefix |
| VBScript runtime error: overflow | Integer overflow when shifting by 16 | Use CLng() before shifting, mask with &HFFFF |
| Driver returns Modbus exception code 02 (Illegal Data Address) | Energy analyzer does not have the requested register | Verify the energy analyzer's register map against the requested %IW address |
| Driver returns Modbus exception code 04 (Slave Device Failure) | Energy analyzer internal error, unsupported function | Check energy analyzer logs; verify function code 04 is supported |
Reference Tables
Modbus Register Address Offset (0-based vs 1-based)
A common source of off-by-one errors in field deployments is the offset between Modbus protocol's 0-based register numbering and the documentation's 1-based numbering:
| Documented Register | 0-based Offset (Driver) | 1-based Offset (Documentation) |
|---|---|---|
| 30001 | 0 | 1 |
| 30218 | 217 | 218 |
| 40001 | 0 | 1 |
| 49999 | 9998 | 9999 |
WinCC Flexible's Modicon driver uses 0-based offsets. Input register 30218 in the energy analyzer's documentation corresponds to %IW217 in the driver. Verify by reading a known register (e.g., a firmware version word) before scaling out the full register map.
IEEE 754 Quick Reference
| Format | Sign | Exponent | Mantissa | Bias | Total Bits | Modbus Registers |
|---|---|---|---|---|---|---|
| Single (REAL) | 1 | 8 | 23 | 127 | 32 | 2 |
| Double (LREAL) | 1 | 11 | 52 | 1023 | 64 | 4 |
| Half (REAL16) | 1 | 5 | 10 | 15 | 16 | 1 |
Modbus applications use single-precision (32-bit) as the standard float format. Double-precision is rare in process instrumentation; half-precision is essentially never used in Modbus.
IEEE 754 Single-Precision Decoding Formula
For a 32-bit unsigned integer raw reconstructed from two Modbus words:
sign = (raw AND 0x80000000) / 0x80000000 ' 0 or 1
exponent = (raw AND 0x7F800000) / 0x00800000 ' 0-255
mantissa = (raw AND 0x007FFFFF) / 0x00800000 ' 0.0 - ~0.9999
if exponent == 0:
value = 0
elif exponent == 255:
value = NaN or Inf
else:
value = (-1)^sign * 2^(exponent - 127) * (1 + mantissa)
This formula is the reference for the VBScript implementation in Solution 1. See the National Instruments Modbus Protocol Reference for additional background on Modbus data encoding and endianness conventions.
Quick Reference: Solution Selection
| Criterion | Solution 1 (VBScript) | Solution 2 (PLC Mirror) | Solution 3 (Gateway) |
|---|---|---|---|
| HMI tags required | 2 INT + 1 REAL | 1 REAL | 1 REAL |
| HMI tag addresses | %IW217, %IW218, internal | %MD110 | %MW0 (via gateway) |
| PLC programming | None | READ_VAR + float block | None |
| Additional hardware | None | None | Modbus gateway |
| Update latency | 250 ms (HMI cycle) | 100-200 ms (PLC scan) | 50-100 ms (gateway) |
| Engineering effort | Medium | High | Low |
| Field reliability | Good (script-based) | Excellent (PLC-native) | Excellent (transparent) |
| Recommended for | 1-3 meters, fast deployment | Existing Premium/Micro PLC, many tags | Many 3xxxx devices, central HMI |
FAQ
Why does the %IW address field grey out when I select a Real (float) data type in WinCC Flexible?
The Modicon Modbus TCP/IP driver in WinCC Flexible binds 32-bit data types (REAL, DINT, DWORD) to %MW only. The %IW area is reserved for 16-bit input words, reflecting the Modicon hardware convention where %IW maps to physical 16-bit input modules. This is a design constraint of the driver, not a project setting that can be changed.
Can I read a 32-bit float from a Modbus input register (3xxxx) directly into a WinCC Flexible float tag?
No, not directly through the %IW path. You must either (1) read two consecutive %IW addresses as 16-bit INT tags and combine them in a VBScript into a REAL, (2) have the Modicon PLC read the input register and mirror the reassembled float into its %MD area, or (3) deploy a Modbus gateway that remaps 3xxxx into 4xxxx holding registers.
What is the correct Modbus register offset for input register 30218 in WinCC Flexible?
WinCC Flexible's Modicon Modbus TCP/IP driver uses 0-based offsets. Register 30218 in the device documentation corresponds to %IW217 in the driver. The next consecutive word is %IW218. The high word is at the lower %IW address because Modbus transmits big-endian: high word first, low word second.
Why does the float read as 0.0000 or as a very large number (~1.7E+38)?
Almost always a word-order issue. Modbus big-endian puts the high word at the lower register address. If the VBScript receives the words in the wrong order, the IEEE 754 exponent field ends up in the wrong bit position, producing either 0 (exponent = 0) or the maximum representable value (exponent = 255 with non-zero mantissa). Swap the operands at the call site and re-test.
Is the OPC server approach (KEPwareEX, Matrikon) faster than direct Modbus TCP for this use case?
No. OPC DA introduces 200-500 ms of update latency per poll cycle, and OPC UA adds 100-300 ms even on a local network. Direct Modbus TCP from WinCC Flexible to the energy analyzer cycles in 100-250 ms. For real-time energy monitoring, the VBScript combination approach (Solution 1) or PLC-side mirroring (Solution 2) is significantly faster than OPC.