S7-1200 MB_Master Modbus Hex to Decimal Address Conversion

David Krause14 min read
SiemensTechnical ReferenceTIA Portal
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

S7-1200 MB_Master Modbus Hex to Decimal Address Conversion

1. Overview

The Siemens S7-1200 and S7-1500 CPUs communicate with Modbus RTU slaves through serial communication modules such as the CB1241 (RS485, no termination) or the CM1241 RS422/485 module. The user program calls the MB_MASTER instruction (FB) from the “Modbus” library in TIA Portal (V13 SP1 and later). Unlike most third-party Modbus masters where the function code, slave address, and starting register are independent parameters, the S7-1200 implementation conflates the function code with the Data_ADDR input through a leading-numeral convention borrowed from the legacy Modicon 984 memory map.

This means every register address passed to MB_MASTER must start with a prefix that simultaneously selects the function code and the Modbus memory area. When the device documentation only provides hexadecimal register numbers, you must:

  1. Convert the hex value to decimal.
  2. Add the appropriate leading-numeral prefix based on which Modbus function code the slave expects.
  3. Select a matching MODE value in MB_MASTER.

The protocol-level address transmitted in the Modbus RTU frame is the lower portion of Data_ADDR; the leading numeral itself is stripped before the address bytes are placed on the wire. According to National Instruments’ knowledge base article kA00Z0000019LT6SAM, hexadecimal register values in device manuals must first be matched to the correct address range (input, holding, coil, or discrete) before any decimal conversion is performed.

Design Note: The MB_MASTER block intentionally does not expose a dedicated “function code” input. The function code is derived from the leading digit of Data_ADDR and the MODE selection. Field engineers migrating from non-Siemens platforms (Codesys, Wago PFC200, Beckhoff TwinCAT) frequently trip on this because their masters accept a literal FC value.

2. Modbus Function Code to Memory Area Mapping

The Modbus protocol defines four primary memory areas, each tied to specific function codes. The Modbus specification itself does not impose a numbering convention; the 0xxxx/1xxxx/3xxxx/4xxxx prefixes are a de facto legacy from the Modicon 984 PLC family. Siemens adopted this convention for MB_MASTER to keep the user-facing address format familiar to Modicon-trained personnel.

Memory Area Prefix Constant Read Function Code Write Function Codes Typical Use
Coils 0xxxx (e.g., 000001) FC 01 — Read Coils FC 05 (single), FC 15 (multiple) Binary outputs, R/W
Discrete Inputs 1xxxx (e.g., 100001) FC 02 — Read Discrete Inputs None (read-only) Binary inputs, RO
Input Registers 3xxxx (e.g., 300001) FC 04 — Read Input Registers None (read-only) 16-bit analog inputs, RO
Holding Registers 4xxxx (e.g., 400001) FC 03 — Read Holding Registers FC 06 (single), FC 16 (multiple), FC 23 (R/W multiple) 16-bit analog values, configuration, R/W

Critical insight: The leading numeral itself is never transmitted on the wire. The MB_MASTER block uses the leading digit only to select the function code and to construct the correct Modbus Application Data Unit (ADU). The two-byte register address field in the actual Modbus RTU frame is the zero-based index derived from the lower portion of Data_ADDR (i.e., Data_ADDR – prefix_constant).

3. Hexadecimal to Decimal Conversion Procedure

Converting a hex register address to decimal is a positional base-16 calculation. For a four-digit hex value 0xh3h2h1h0:

decimal = (h3 × 163) + (h2 × 162) + (h1 × 161) + (h0 × 160)

Example A: 0x331A → decimal

0x331A = (3 × 4096) + (3 × 256) + (1 × 16) + (10 × 1)
0x331A = 12288 + 768 + 16 + 10
0x331A = 13082 decimal

Example B: 0x9013 → decimal

0x9013 = (9 × 4096) + (0 × 256) + (1 × 16) + (3 × 1)
0x9013 = 36864 + 0 + 16 + 3
0x9013 = 36883 decimal

Handling Hex Values Above 0x270F (9999 decimal)

The legacy prefix constants 40001, 30001, 10001, 00001 only cover register numbers 1–9999. For modern field devices (solar charge controllers, smart power meters, industrial drives) register numbers routinely exceed 9999. In this case the prefix expands to a six-digit constant:

Memory Area Short Prefix (1–9999) Long Prefix (>9999)
Holding Registers 40001 400001
Input Registers 30001 300001
Discrete Inputs 10001 100001
Coils 00001 000001

4. Zero-Based vs. One-Based Addressing

Modbus documentation is ambiguous about whether register numbers in the manual correspond to:

  • Zero-based protocol addresses — the byte value transmitted in the RTU frame.
  • One-based human-readable numbers — legacy Modicon convention where register “40001” transmits address 0.

The widely accepted interpretation is:

  • Hex addresses in device manuals are typically zero-based (i.e., they match the wire value).
  • Leading-numeral addresses like 40001 are one-based (i.e., 40001 transmits address 0).

Given this, the DATA_ADDR formula for an MB_MASTER call is:

DATA_ADDR = prefix_constant + decimal_value_of_hex_address

If the device manual explicitly states its hex values are 1-based, subtract 1 before adding the prefix. If you receive error 16#8383 from MB_MASTER (data address out of range) or the slave returns an “Illegal Data Address” exception (Modbus exception code 02), shift the address by ±1 and retry.

5. Worked Conversion Examples

The table below consolidates the conversion logic for registers documented in hex.

Hex Address (from manual) Decimal Value Memory Type FC Required DATA_ADDR Input MB_MASTER MODE Wire Address Sent
0x331A 13082 Input Registers (3xxxx) 04 313082 0 0x331A
0x9013 36883 Holding Registers (4xxxx) 03 436883 0 or 4 0x9013
0x0001 1 Holding Registers (4xxxx) 03 400002 0 or 4 0x0001
0x0100 256 Input Registers (3xxxx) 04 300257 0 0x0100
0x0000 0 Coils (0xxxx) 01 000001 2 0x0000
0x0064 100 Discrete Inputs (1xxxx) 02 100101 9 0x0064

Verification tip: After entering the value, capture the wire frame with a Modbus sniffer (or the Siemens “Trace” feature in TIA Portal V17+ when the CM/CB has a diagnostic port) and confirm the second byte of the function code response equals the function code you expected. For DATA_ADDR = 313082 the frame should contain 04 33 1A 00 03 (FC 04, address 0x331A, length 3) followed by the CRC.

6. MB_Master MODE Reference

The MODE input selects the read/write operation type. The leading numeral of Data_ADDR independently selects the memory area; together they fully determine the function code on the wire. The MODE constants shipped in the Modbus library depend on the FB version in use:

MODE (Dec) Operation Function Code on Wire Required Prefix Notes
0 Read Holding Registers FC 03 4xxxx Most common read; supports wide register ranges
1 Read Coils FC 01 0xxxx Binary outputs only
2 Read Discrete Inputs FC 02 1xxxx Binary inputs only
3 Read Holding Registers (alternative) FC 03 4xxxx Alias for MODE 0 in some FB revisions
4 Read Input Registers FC 04 3xxxx Read-only analog input
5 Write Single Coil FC 05 0xxxx Force single bit
6 Write Single Holding Register FC 06 4xxxx 16-bit preset
7 Write Multiple Coils FC 15 0xxxx Force bit array
8 Write Multiple Holding Registers FC 16 4xxxx Preset register array
9 Read/Write Multiple Registers FC 23 4xxxx Not supported by all slaves
101 / 102 Diagnostic variants FC 03 4xxxx Used with extended status flags

Note: The MODE constants above align with the “Modbus” library version 3.x used in TIA Portal V15.1 through V18. Earlier library versions (V1.x, V2.x) shipped with S7-1200 in TIA V13 SP1 used slightly different MODE numbering; Siemens consolidated these in V3.x. Always verify against the TIA Portal online help for your specific FB version.

7. Step-by-Step Conversion Procedure

  1. Identify the function code. Read the device manual and determine which FC number is required to access the target data block (FC 01/02/03/04/05/06/15/16).
  2. Identify the memory area. Cross-reference the FC with the memory area table in Section 2 (Coils, Discrete Inputs, Input Registers, Holding Registers).
  3. Convert the hex address to decimal. Use the positional calculation or a calculator. Example: 0x331A → 13082; 0x9013 → 36883.
  4. Apply the leading-numeral prefix.
    • FC 03/06/16 → prefix 4xxxx
    • FC 04 → prefix 3xxxx
    • FC 01/05/15 → prefix 0xxxx
    • FC 02 → prefix 1xxxx
  5. Adjust for zero/one-based offset if required. If the manual states “registers numbered from 1,” subtract 1 from the decimal value before adding the prefix. Otherwise use the value as-is.
  6. Select the MODE. Match the MODE table in Section 6 to the FC.
  7. Wire up DATA_PTR. Provide an ARRAY OF BYTE or ARRAY OF WORD sized to (DATA_LEN × 2) bytes.
  8. Set BLOCKED_PROC_TIMEOUT. Default 3.0 s is appropriate for sub-1-second poll cycles. Increase to 10–30 s for slow slaves (some solar charge controllers sleep between requests).
  9. Trigger REQ and monitor status. A rising edge on REQ initiates one transaction.

8. Error Code Reference

MB_MASTER returns standardized status codes via its DONE, BUSY, and ERROR outputs and the STATUS word. The most common errors encountered during hex-to-decimal addressing problems are:

STATUS (Hex) STATUS (Dec) Meaning Likely Cause Remedy
0x0000 0 No error Transaction idle None
0x80C9 32969 Blocked_Proc_Timeout Slave did not respond within timeout; or wrong baudrate/parity; or A/B wires reversed Swap A/B if not done; verify parity (None, Even, Odd); increase BLOCKED_PROC_TIMEOUT to 10–30 s
0x8383 33667 Error in the data address or address outside the valid range of DATA_PTR DATA_PTR is too small for DATA_LEN; or DATA_ADDR prefix does not match MODE Enlarge DATA_PTR array; verify prefix digit matches the required function code
0x80D1 32977 Parity error from the receiver Baudrate/parity mismatch or line noise Verify parity on PTP parameters; check shielding and termination
0x80D2 32978 Framing error from the receiver Baudrate mismatch Verify baudrate (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200)
0x80D5 32981 Timeout on receive Slave did not respond Check slave address (1–247); verify wiring
0x80E0 32992 Buffer overflow DATA_LEN too large Reduce DATA_LEN; most slaves cap at 125 registers per request
0x80F8 33016 Slave returned Modbus exception 02 (Illegal Data Address) Address does not exist on the slave Try ±1 offset on decimal value; verify prefix matches FC expected by slave
0x80F9 33017 Slave returned Modbus exception 03 (Illegal Data Value) Quantity out of range or unsupported sub-function Reduce DATA_LEN; check write value range
Tip: Errors 0x80F8 and 0x80F9 are unique because they confirm the slave received the request and rejected it semantically. This rules out wiring and timeout problems and localizes the fault to the address mapping itself.

9. Common Pitfalls and Field-Proven Caveats

9.1 Wire Swapping on RS485

RS485 is polarity-sensitive at the physical layer: “A” (Data+) and “B” (Data–) must not be reversed, although some vendors label them “+” / “–” or “D1” / “D0” instead. A swapped pair produces 0x80C9 (Blocked_Proc_Timeout) followed by 0x80D5 (Timeout on receive) even though the slave is present on the bus. Always verify with a Modbus sniffer first.

9.2 One vs. Two-Byte Address Padding

Some manufacturers specify their register map with leading zeros (e.g., “0x0331A” for 5-digit registers). When the prefix 4 is added, the resulting 6-digit value must still be inside the INT range. If a 32-bit integer overflow occurs, this is a symptom of incorrectly concatenating the prefix rather than adding it (e.g., using “43xxxx” as a literal instead of 400001 + xxxx).

9.3 MODE Mismatch with Prefix

The MODE input must be consistent with the leading numeral. If MODE = 4 (Read Input Registers) but DATA_ADDR = 413082 (4xxxx prefix), the block will either reject the combination with 0x8383 or transmit a frame with the wrong FC. The MODE value cannot force a different function code than the prefix dictates; they are anded together internally.

9.4 DATA_PTR Array Sizing

DATA_PTR must be declared as ARRAY [0..n-1] OF BYTE where n ≥ 2 × DATA_LEN. If n = DATA_LEN (instead of 2 × DATA_LEN), MB_MASTER reports 0x8383 because it cannot fit the response bytes.

9.5 32-Bit Values and IEEE-754 Floats

Many sensors pack a 32-bit float or a 32-bit signed integer into two adjacent 16-bit registers. The MB_MASTER response data must be re-assembled and converted to IEEE-754 single-precision float using the standard formula:

sign = (raw >> 31) & 0x01
exponent = ((raw >> 23) & 0xFF) − 127
mantissa = 1 + ((raw & 0x7FFFFF) / 8388608.0)
float = (−1)sign × mantissa × 2exponent

Per Schneider Electric FAQ FA406976, the two 16-bit register words must be combined with the high-order word first (big-endian / Modbus word order). On S7-1200 SCL this conversion is most easily done with the standard library function WORD_TO_REAL after manual byte-swap, or by enabling the “Byte Swap” parameter on the receiving block when available.

9.6 Negative Number Handling

16-bit registers transmitting signed integers use two’s complement. A raw value of 0xFFFE (65534 decimal) is −2, not 65534. Apply DINT_TO_REAL or the equivalent two’s-complement conversion in your application code when interpreting negative temperatures, currents, or signed counts.

10. Verification Checklist

  1. Confirm the wire frame: open the TIA Portal online & diagnostics view of the CB1241 (right-click → “Online & diagnostics” → “Port statistics”) or attach a Modbus RTU sniffer such as the open-source “ModbusTools” or the Wireshark Modbus dissector. Verify the FC byte equals the value in Section 2.
  2. Confirm the slave response: a successful FC 04 read returns bytes equal to 2 × DATA_LEN. For DATA_LEN = 3, expect 6 bytes of payload plus the slave address, FC, length, and CRC.
  3. Confirm STATUS = 0x0000 after DONE pulses high. Any non-zero STATUS means the transaction failed; cross-reference Section 8.
  4. Confirm the payload values match the device manual within expected scaling (some sensors apply a 0.1 or 0.01 multiplier).
  5. Confirm cyclic execution: the DONE flag must pulse every MB_MASTER cycle. If BUSY remains low, the request edge was missed.

11. Troubleshooting Matrix

Symptom First-Check Second-Check Resolution
STATUS = 0x80C9 immediately A/B wire swap Baudrate / parity Swap wires; verify PTP parameters match slave
STATUS = 0x80C9 after a few seconds BLOCKED_PROC_TIMEOUT Slave response delay Increase timeout to 10–30 s; reduce poll rate
STATUS = 0x8383 DATA_PTR array size Prefix/MODE consistency Enlarge DATA_PTR; align prefix digit with MODE
STATUS = 0x80F8 (exception 02) Hex offset by ±1 Wrong prefix (3 vs. 4) Try DATA_ADDR ± 1; verify FC against manual
STATUS = 0x80F9 (exception 03) DATA_LEN limit Write value out of range Reduce quantity; check slave’s max register count
STATUS = 0x80D1 (parity) Parity setting Line noise / grounding Match parity; check shield grounding at one end only
STATUS = 0x80D5 (receive timeout) Slave address (1–247) Termination resistor Verify slave ID; install 120 Ω termination at bus ends
Garbage payload values Byte order 32-bit interpretation Apply big-endian word swap; check IEEE-754 conversion

12. Migration Notes: S7-1200 to Codesys/Wago

Engineers frequently migrate Modbus master code from the S7-1200 platform to a Codesys-based controller (Wago PFC200, Wago CC100, Beckhoff CX) because Codesys Modbus libraries expose the function code as an explicit input. If you are porting an MB_MASTER call to Codesys:

  1. Drop the leading numeral. Use only the zero-based decimal address.
  2. Pass the function code explicitly (e.g., FUNCTION_CODE := 4).
  3. Configure the slave address separately (e.g., SLAVE_ADDR := 1).
  4. Re-order bytes if migrating 32-bit values; Codesys Modbus_Slave / Modbus_Master handle byte order differently than Siemens’ byte-swap convention.

This explicit structure makes the addressing scheme self-documenting and eliminates the leading-numeral confusion entirely. The trade-off is more parameters per call.

13. FAQ

How do I convert Modbus hex address 0x331A to the Data_ADDR value for S7-1200 MB_Master when FC 04 is required?

Convert 0x331A to decimal (13082), then add the input-register prefix 300001 to obtain Data_ADDR = 313082. Set MODE = 0. The wire frame will transmit function code 04 with register address 0x331A.

What does MB_Master error 16#80C9 (Blocked_Proc_Timeout) mean?

The slave failed to respond within the BLOCKED_PROC_TIMEOUT window (default 3.0 s). Typical causes are swapped A/B RS485 wires, mismatched baudrate or parity, or a slave that is sleeping between requests. Increase the timeout to 10–30 s and verify wiring before assuming an addressing problem.

What does MB_Master error 16#8383 mean and how is it fixed?

Status 0x8383 indicates either that the Data_PTR array is too small for the requested DATA_LEN, or that the leading digit of Data_ADDR is inconsistent with the MODE value. Enlarge Data_PTR to 2 × DATA_LEN bytes and ensure the prefix matches the function code the slave expects.

Why does S7-1200 MB_Master refuse function code 10 when I want to write the RTC?

Function code 10 (decimal) is FC 0A in hex and is not part of the standard Modbus read/write set; MB_Master does not implement a MODE value for it. To write the RTC, use MODE 6 (FC 06 single register) or MODE 8 (FC 16 multiple registers) with a 4xxxx prefix. If the slave documentation truly requires FC 10, you must use the low-level MB_SLAVE/USS library or a third-party Modbus master block.

How do I handle 32-bit Modbus float values from two 16-bit registers on the S7-1200?

Read the two adjacent 16-bit registers with MB_Master into an ARRAY OF BYTE, swap the bytes to big-endian word order if necessary, concatenate into a 32-bit DWORD, then convert using IEEE-754 single-precision math. Reference Schneider Electric FAQ FA406976 for the canonical conversion procedure.

Is the leading-numeral convention (3xxxx, 4xxxx) transmitted on the Modbus wire?

No. The MB_Master block strips the leading digit before constructing the ADU. The wire frame contains only the lower portion of Data_ADDR as a 2-byte big-endian address. This is why MB_Master cannot poll addresses above 65535 in a single call without using extended register addressing (which most slaves do not support).

Back to blog