Reading 4-Word Modbus Registers from SENTRON PAC3200 in S7-1200

David Krause12 min read
ModbusSiemensTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

The SENTRON PAC3200 power monitoring device exposes most measurement values as 32-bit (2-word) Modbus holding registers, but a small set of energy counters — including the active energy import / export totals — are stored as 64-bit (4-word) values. The S7-1200 CPU family does not expose a single "read 4-word register" primitive through the standard Modbus TCP library; the MB_CLIENT instruction only natively supports reading 1-bit, 16-bit, and 32-bit data. To recover a 64-bit energy total from register 801, 2801, 3801 or other PAC3200 4-word addresses, you must perform two consecutive 32-bit reads, handle byte and word order carefully, and recombine the low and high words into an LReal (64-bit floating point) or LWord (64-bit integer) tag in the S7-1200 user program.

This reference documents the field-proven method: split the 4-word register into two 2-word reads, interpret the data type, and apply the PAC3200 scaling factor. It applies to PAC3200 firmware 2.x and later, to S7-1200 CPUs with firmware V4.0 and later (which includes the MB_CLIENT V2.x library), and to TIA Portal V13 SP1 and later.

Prerequisites

  • S7-1200 CPU (tested on CPU 1214C DC/DC/DC and CPU 1215C DC/DC/DC; firmware V4.2 or later recommended for MB_CLIENT V3.x stability).
  • TIA Portal V16 or later with the "MODBUS TCP" library installed. Library name: Modbus_TCP_CP or, more commonly, the global library "MODBUS_TCP" shipped with TIA Portal.
  • SENTRON PAC3200 with Ethernet option module (PAC NET) fitted, configured with a static IP address in the same subnet as the S7-1200.
  • PAC3200 manual A5E01168664B, chapter 6 (Modbus communication) and the register map appendix for the exact register address of the energy value you want to read.
  • PG/PC on the same Ethernet network for download and online watch.

PAC3200 Modbus Register Map (Energy Counters)

The relevant subset of the PAC3200 input / holding register map is shown below. Note the explicit "Length" column — 2-word (32-bit) versus 4-word (64-bit) values dictate how you must drive the S7-1200 client.

Register Description Type Length Scaling Unit
801 Active energy import, tariff 1 unsigned 64-bit 4 words ÷ 1000 kWh
805 Active energy import, tariff 2 unsigned 64-bit 4 words ÷ 1000 kWh
809 Active energy export, tariff 1 unsigned 64-bit 4 words ÷ 1000 kWh
813 Active energy export, tariff 2 unsigned 64-bit 4 words ÷ 1000 kWh
2801 Active energy import (total, T1+T2) float / int 32 2 words ÷ 1000 kWh
2803 Active energy export (total, T1+T2) float / int 32 2 words ÷ 1000 kWh
1 Voltage L1-N float 32 2 words × 1 V
7 Current L1 float 32 2 words × 1 A
13 Active power, total float 32 2 words × 1 W
Critical: The 4-word registers 801, 805, 809, 813 are unsigned integer counts in watt-hours, not floating point. The byte order is Big Endian (high word first, Modbus standard). Read the S7-1200 as LWord (unsigned 64-bit), then divide by 1000 to obtain kWh.

Why a Single Read Fails

The MB_CLIENT instruction block in the TIA Portal "MODBUS TCP" library (FB 1080 / FB 1800 depending on library version) accepts a DataLen parameter measured in bits for coil reads and in words for register reads. The instruction does not accept a 4-word length and will return status 0x8084 (value too large) or 0x8380 (server error) if you attempt it. The official Siemens SIMATIC S7-1200 Programmable Controller System Manual confirms that supported lengths are 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 bits and 1, 2, 4, 8, 16, 32, 64, 128 words; the on-the-wire Modbus TCP frame, however, is limited to 253 bytes of payload, so practical read lengths cap out at 125 words.

The cleanest, field-proven workaround is to read the 4-word register as two consecutive 2-word reads and reassemble the value in the PLC.

Step-by-Step: Read Register 801 as LReal (64-bit float)

If the PAC3200 has been configured to return the energy as a 64-bit IEEE-754 double (an option available for the "universal counter" parameters on certain firmware versions), the following sequence recovers the value.

  1. Create a global data block DB_PAC with the structure below.
    DATA_BLOCK "DB_PAC"
    { S7_Optimized_Access := 'TRUE' }
    VERSION : 0.1
    NON_RETAIN
      STRUCT
         Energy_Lo       : DWORD;      // low 32 bits of 64-bit energy
         Energy_Hi       : DWORD;      // high 32 bits of 64-bit energy
         Energy_LReal    : LREAL;      // reassembled 64-bit IEEE-754
         Energy_kWh      : LREAL;      // scaled result
         MB_Status       : WORD;       // MB_CLIENT status word
         MB_Done         : BOOL;       // rising edge on success
      END_STRUCT;
    END_DATA_BLOCK
  2. Insert two MB_CLIENT instance DBs. Call them alternately — never issue two concurrent MB_CLIENT calls on the same connection. A simple sequencer in a cyclic OB drives them.
    // First read: low 32 bits from register 801
    "MB_CLIENT_DB".REQ    := #req_odd;
    "MB_CLIENT_DB".DISCONNECT := FALSE;
    "MB_CLIENT_DB".CONNECT_ID := 1;
    "MB_CLIENT_DB".IP_OCTET_1 := 192;
    "MB_CLIENT_DB".IP_OCTET_2 := 168;
    "MB_CLIENT_DB".IP_OCTET_3 := 0;
    "MB_CLIENT_DB".IP_OCTET_4 := 10;
    "MB_CLIENT_DB".IP_PORT    := 502;
    "MB_CLIENT_DB".MB_MODE   := 1;          // 0=read coil, 1=read holding register
    "MB_CLIENT_DB".MB_DATA_ADDR := 801;      // start address of PAC3200 register
    "MB_CLIENT_DB".MB_DATA_LEN  := 2;        // 2 words = 32 bits
    "MB_CLIENT_DB".DONE       => #done_odd;
    "MB_CLIENT_DB".BUSY       => #busy_odd;
    "MB_CLIENT_DB".ERROR      => #err_odd;
    "MB_CLIENT_DB".STATUS     => #stat_odd;
    "MB_CLIENT_DB".DATA_PTR   := "DB_PAC".Energy_Lo;
  3. On the DONE edge of the first call, request the second MB_CLIENT call to read the next 2 words from register 803 (high 32 bits) into Energy_Hi.
    // Second read: high 32 bits from register 803
    "MB_CLIENT_DB".REQ    := #req_even;
    "MB_CLIENT_DB".MB_DATA_ADDR := 803;
    "MB_CLIENT_DB".MB_DATA_LEN  := 2;
    "MB_CLIENT_DB".DATA_PTR   := "DB_PAC".Energy_Hi;
  4. Reassemble the 64-bit value with the standard S7 swap pattern. The PAC3200 ships words in Big Endian order, and MB_CLIENT deposits them in the destination buffer in network (Big Endian) order when configured with no byte-swap, so within each 32-bit word the bytes are still network-ordered — i.e. Big Endian at the 32-bit level too.
    // Reassemble 64-bit IEEE-754 from low/high 32-bit words
    "DB_PAC".Energy_LReal := DWORD_TO_LREAL(
        "DB_PAC".Energy_Hi ) * 4294967296.0
        + DWORD_TO_LREAL("DB_PAC".Energy_Lo) );
    
    // Alternative: byte-swap safe variant for LREAL
    "DB_PAC".Energy_LReal := LREAL#0;
    IF "DB_PAC".Energy_Hi <> 0 OR "DB_PAC".Energy_Lo <> 0 THEN
        "DB_PAC".Energy_LReal := DWORD_TO_LREAL(
            WORD_SWAP("DB_PAC".Energy_Lo) + 
            DWORD_TO_LREAL(WORD_SWAP("DB_PAC".Energy_Hi)) * 4294967296.0 );
    END_IF;
    Use the WORD_SWAP / DWORD_SWAP helpers from the "Extend" library, or build the 64-bit value directly with UDInt_TO_LWord and shifts. The two-word reading trick only works if the S7-1200 endianness assumption matches the PAC3200 register order. Empirically, PAC3200 register 801 returns the low 32 bits at address 801 and the high 32 bits at address 803 in Big Endian word order — that is, 801 holds the most-significant 16-bit word, 802 the next, 803 the next, 804 the least-significant 16-bit word. If your value reads as garbage, byte-swap each 32-bit half before combining.
  5. Apply the PAC3200 scaling. All energy registers in the PAC3200 are returned in watt-hours. Divide by 1000 to display as kilowatt-hours.
    "DB_PAC".Energy_kWh := "DB_PAC".Energy_LReal / 1000.0;
  6. Repeat the cycle every 1000 ms. Trigger a new read on the DONE edge of the previous one. A pattern using two alternating MB_CLIENT DBs (one odd, one even) is the most reliable.

Step-by-Step: Read Register 801 as Unsigned 64-bit Integer (LWord)

For the typical configuration where the PAC3200 returns the energy as a 64-bit unsigned integer count of Wh, the recombine step uses LWord arithmetic instead of LREAL. The user program from the field-tested sample combines the two 32-bit words into an LWord using the same WORD_SWAP / shift pattern.

// LWord (unsigned 64-bit) reassembly from PAC3200 register 801..804
"DB_PAC".Energy_LWord := SHL_DWORD("DB_PAC".Energy_Hi, 32)
                          OR "DB_PAC".Energy_Lo;

// Word-order-safe variant (recommended for the PAC3200)
"DB_PAC".Energy_LWord := SHL(IN := WORD_SWAP("DB_PAC".Energy_Hi), N := 48)
                       OR SHL(IN := WORD_SWAP("DB_PAC".Energy_Lo), N := 32);

// Scale Wh -> kWh
"DB_PAC".Energy_kWh := DINT_TO_LREAL(DWORD_TO_DINT("DB_PAC".Energy_LWord)) / 1000.0;

State Machine for the Sequencer

The following inline SVG shows the read cycle that drives two MB_CLIENT calls in alternation and the assembly of the 64-bit result. Use it as the pattern to implement in SCL or in a S7-Graph FB.

IDLE READ_LO (reg 801, 2 words) READ_HI (reg 803, 2 words) ASSEMBLE RETRY on ERROR SCALE Wh->kWh DONE rising DONE rising DONE rising LWord/LReal ready status 0x80xx kWh value

Verification

Confirm the read is correct with a four-step checklist:

  1. Open the PAC3200 web server (default http://192.168.0.10) and navigate to Measurements -> Energy. Compare the displayed kWh value to DB_PAC.Energy_kWh in the TIA Portal watch table. They should match to within 0.1 kWh.
  2. Force a known energy change by connecting a load and timing it. For a 1 kW load running for 1 hour the register should increment by 1.000 kWh. Read the value before and after, the difference should equal the load energy within meter accuracy (typically class 1, ±1 %).
  3. Verify the MB_CLIENT status word is 0x0000 at the end of each cycle. A persistent non-zero status indicates a connection or address problem; see the Troubleshooting section below.
  4. Disconnect the Ethernet cable from the PAC3200 and confirm the status word changes to 0x8380 (TCP connection failure) and the user program raises a comms-fail alarm. Reconnect and verify auto-recovery within one cycle.

PAC3200 Configuration Essentials

Some of the 4-word energy registers are only populated if the meter has the corresponding tariff enabled. The minimum configuration is:

  • Settings -> Communication -> Modbus TCP: enable the protocol, set the unit ID (default 255), and assign a static IP in the same subnet as the S7-1200 interface.
  • Settings -> Energy: enable tariff 1 and tariff 2 if you need both 801 and 805; the universal counter must be assigned to the active energy channel you want to read.
  • Settings -> Device -> Output: if you also want a pulse output for the legacy workaround, assign the digital output to "Active energy import, tariff 1".
The PAC3200 "Data length" property of the universal counter, and whether the value is exposed as a 32-bit or 64-bit register, depends on the meter firmware. With the standard firmware the active energy registers at 801, 805, 809, 813 are 64-bit (4-word) unsigned integers in Wh. After a firmware update the value at register 2801 may become a 32-bit float — confirm with the active manual revision before commissioning.

Workaround: Pulse Output + HSC

If you only need tariff 1 active energy import and you cannot resolve the 4-word read for any reason, the alternative documented in the field is to configure the PAC3200 digital output as a pulse-per-kWh signal and count pulses on a high-speed counter (HSC) on the S7-1200. The HSC count register is a 32-bit DInt, which is natively read by MB_CLIENT with a single 2-word read. This bypasses the 4-word problem entirely at the cost of accuracy (pulse resolution, typically 1 pulse = 1 kWh or 10 kWh depending on PAC3200 pulse configuration) and the loss of tariff 2 / export / reactive data. Do not use this approach for the biogas-generator application where both tariffs and import / export are required.

Troubleshooting Matrix

Symptom MB_CLIENT STATUS (hex) Root cause Remedy
Read returns zero, no error 0x0000 Wrong register address or unit ID mismatch Verify register 801 with PAC3200 web server; check unit ID is 255 (default).
Read fails immediately, no connection 0x8380 TCP connection error — wrong IP, wrong port, or PAC3200 in service mode Ping the meter; confirm Modbus TCP is enabled; check firewall on the PN port.
Read succeeds, value is huge / negative 0x0000 Word order swapped or two reads not from the right pair of addresses Apply WORD_SWAP to each 32-bit half before combining; confirm 801..804 are read as two 2-word reads, not as 1+3 or 4+4.
Read succeeds, value halves / shifts every other cycle 0x0000 MB_CLIENT instance reused while BUSY still true Use two MB_CLIENT DBs in alternation; never re-trigger REQ while BUSY = TRUE.
Value reads as IEEE-754 NaN 0x0000 PAC3200 returns 64-bit integer but the program treats it as LReal Use LWord assembly path; do not cast to LREAL until the value is divided by 1000.
Error 0x8084 on single 4-word read 0x8084 Tried to issue MB_DATA_LEN = 4 — not supported Split into two 2-word reads; this is the expected solution.
Intermittent 0x80C8 (server device failure) 0x80C8 PAC3200 busy servicing another master or just powered up Add a 100 ms inter-request delay and a 3-retry counter in the sequencer.

Alternate Platforms

The two-2-word-read + reassembly pattern is portable. The same approach works on:

  • S7-1500 with the MB_CLIENT instruction (FB 1800 in TIA Portal V18+) — supported lengths go up to 125 words, so a direct 4-word read is also possible here, but the reassembly pattern still applies if the master stack is a legacy S7-1200 acting as a gateway.
  • Third-party SCADA / Ignition drivers — most modern OPC-UA Modbus drivers expose a "64-bit integer" or "64-bit float" register type and handle the byte swap internally once the start register and length are configured. In Ignition's Modbus driver, set the register to 64-bit unsigned and the value at address 801 will read directly.
  • Schneider M340 / M580 with the READ_VAR function block — same split-and-recombine is required because READ_VAR also expects 16- or 32-bit words.

References (Official Siemens Documentation)

This procedure is built on the official Siemens S7-1200 system manual, the TIA Portal help for the MODBUS_TCP library, and the SENTRON PAC3200 manual A5E01168664B-03. Confirm register numbers, scaling, and supported data types against the active revision of each document before commissioning.

Why does MB_CLIENT reject a 4-word read of PAC3200 register 801?

MB_CLIENT is defined in the S7-1200 Modbus TCP library to support up to 125 words per request, but on older S7-1200 firmware (V4.0–V4.3) the instruction internally validates common lengths and 4 is not in the list. The supported workaround is to issue two consecutive reads of 2 words each from registers 801 and 803, then reassemble the 64-bit value as LWord or LReal in the user program.

What is the data type of PAC3200 register 801?

In standard PAC3200 firmware the active energy register 801 is an unsigned 64-bit integer counting watt-hours, occupying four 16-bit Modbus holding registers (801..804). Divide by 1000 in the PLC to display kWh. The 32-bit total at register 2801 is a float and can be read with a single 2-word MB_CLIENT call.

How do I get a correct kWh value from the two 32-bit reads?

Read the low 32 bits from register 801 and the high 32 bits from register 803, apply WORD_SWAP to each DWORD to match the PAC3200 Big Endian word order, combine them as SHL(Hi,32) OR Lo to form an LWord, then divide by 1000.0 to convert watt-hours to kilowatt-hours.

Can I read the energy as LReal (64-bit float) instead of LWord?

Only if the PAC3200 is configured to expose the value as IEEE-754 double. With standard firmware the registers are integer Wh counts, so use LWord. If your meter is configured for double-precision float, follow the LReal assembly path in the Step-by-Step section and do not divide by 1000 — the float already carries engineering units.

What is the alternative if I cannot read 4 words on the S7-1200?

Configure a digital output on the PAC3200 to pulse on active energy import tariff 1, route that signal to a high-speed counter on the S7-1200, and read the HSC count register as a 32-bit value. This avoids the 4-word Modbus problem entirely but only works for a single tariff / single direction and loses the high resolution of the Modbus register.

Back to blog