How to Fix the Codesys Modbus Byte Swap Issue (U16 to S32)
2.45e-41).When integrating third-party energy meters or inverters into a PLC, the Codesys Modbus byte swap swap is an unavoidable rite of passage. You make the connection just fine but instead of a clean 230.5V your monitoring variable shows garbage value like 324560001.5e-41 astronomically
Variable: Type: Value:
Raw_Reg_1 WORD 16#4366
Raw_Reg_2 WORD 16#8000
Combined_Value REAL 2.45e-41 (Expected: 230.5)This is not a wiring issue; it is an Endianness mismatch. The Modbus protocol inherently only defines 16-bit registers (WORDs / U16). It completely lacks standardization for how 32-bit data (DWORDs, REALs, or S32) should be sequenced. When the field device transmits a 32-bit value split across two registers, Codesys reconstructs it based on its native architecture (usually Little-Endian). If the field device is Big-Endian, the High Word and Low Word get reversed.
Step 1: Identify the Byte Order
Before writing any code, you must determine what the field device is actually sending. There are four possible byte sequence combinations for a 32-bit float: ABCD, CDAB, BADC, and DCBA.
Roughly 90% of industrial power meters (like Eastron) and solar inverters transmit data in a Big-Endian Word Swap format (CDAB). This means the bytes inside each WORD are correct, but the two WORDs themselves are reversed. You simply need to swap Register 1 with Register 2.
Step 2: The Structured Text (ST) Solution
In Codesys, you can safely reconstruct the 32-bit value using bitwise operations (SHL and OR). Read the raw Modbus data into an array of WORDs, and then combine them into a DWORD.
// Variables Declaration VAR ModbusData : ARRAY[0..1] OF WORD; // Data pulled from Modbus Swapped32Bit : DWORD; // The corrected 32-bit variable FinalFloat : REAL; // Final human-readable value END_VAR // ST Code: Word Swap (Low Word first, High Word second) // Convert WORD to DWORD, shift the High Word 16 bits left, and merge. Swapped32Bit := (WORD_TO_DWORD(ModbusData[1]) SHL 16) OR WORD_TO_DWORD(ModbusData[0]); // STRICT RULE: Do not use REAL_TO_DWORD! Use ADR/POINTER mapping for raw bits. SysMem.SysMemCpy(ADR(FinalFloat), ADR(Swapped32Bit), SIZEOF(FinalFloat));
DWORD_TO_REAL). This will corrupt the mantissa and the exponent logic. Use bitwise shifts and direct memory pointer copies (SysMemCpy) always..Executing this ST block will reconstruct the raw hexadecimal segments into the correct 32-bit format, instantly converting your garbage numbers into readable data.
⚠️ The Real Nightmare: Managing 30+ Devices in Codesys
The ST code above works perfectly for a handful of devices. However, if you are integrating a daisy-chain of 30+ power meters or solar inverters, Byte Swapping is the least of your problems. Your real enemy is the RS485 physical layer.
When using standard Codesys Modbus Master FBs across a slow 9600bps serial bus, polling 30 devices sequentially can take over 3 seconds. Worse, if just one slave goes offline, the Modbus Timeout (typically 200-500ms) will stall the entire polling queue, causing massive data lag across your system.
Stop Using Your PLC as a Serial Polling Engine
For large-scale multi-device networks, industrial integrators decouple the physical polling layer from the PLC logic. See how Valtoris Storage Gateways autonomously cache entire RS485 networks, feeding your PLC data instantly.
- PLC waits on slow 9600bps serial responses.
- High vulnerability to serial bus collisions.
- One unresponsive slave stalls the entire PLC polling block.
- Hardware-Level Auto Polling: The gateway constantly polls and stores field registers in the background.
- Zero PLC Wait Time: Codesys reads cached raw registers via Modbus TCP in under 3ms.
- Clean Logic: Execute your ST Byte-Swap instantly on localized memory arrays.
