Siemens S7 R_STRG to OPC Converting Real Numbers to Readable

David Krause17 min read
S7-300SiemensTroubleshooting
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

Siemens S7 R_STRG to OPC: Converting Real Numbers to Readable Strings

The Siemens STEP 7 function block FC30 (R_STRG) converts REAL values into STRING format, but the output is always rendered in fixed scientific notation. When this string is exposed through an OPC server to a third-party traceability system or SCADA, the result is an awkward display value such as +0.18 instead of the expected 1.83. The defect is not in the FC30 function and not in the OPC communication link—both are operating per specification. The issue is the selection of representation: FC30 was designed for legacy operator panels that pre-date floating-point tag support, not for OPC clients that expect decimal notation.

This article examines the underlying string format, the OPC data-type boundary, and four field-proven solutions. Complete STEP 7 ladder, FBD, and SCL code samples are provided, along with verification procedures, OPC UA data-type mapping notes, and a diagnostic matrix for tracing similar string-handling defects in production cells.

1. Problem Description

A STEP 7 (S7-300 / S7-400) user program calls FC30 R_STRG to convert a REAL measurement (for example, 1.8324) into a STRING that is then transmitted to an external traceability system via OPC. The conversion produces a 24-byte internal string with the layout +0.1832400E+01. When the OPC server exposes this block to a third-party OPC client, the client typically reads the first 5 to 8 ASCII characters for display, yielding +0.18—a value that is numerically meaningless to a human operator or a downstream system.

1.1 Symptom Summary

Element Observed Value
Source REAL (DB15.DBD48) 1.8324
FC30 internal string buffer (DB5, String[24]) '+0.1832400E+01' (14 visible characters + length bytes)
OPC tag exposed as DB2.string5 (5-char view) '+0.18'
Expected OPC tag value '1.83' or '0.00' (decimal fixed-point)
Downstream consumer Traceability MES expecting ASCII decimal

1.2 Environment

  • PLC: SIMATIC S7-300 (CPU 315-2 DP/PN or equivalent) or S7-400 (CPU 414/416).
  • OPC server: SIMATIC NET OPC server (S7-200 PC Access, S7-1200/S7-1500, or legacy S7-300/400), Kepware KEPServerEX, or a third-party gateway such as Ignition's Siemens driver.
  • OPC client: a third-party traceability system that consumes ASCII STRING data (e.g., MES, line-tracking software).
  • Transport: Industrial Ethernet (PROFINET) on TCP/IP port 102 (S7 communication) or OPC UA on port 4840.
Scope note. This article covers STEP 7 V5.x for S7-300/400. The TIA Portal S7-1200/1500 platform uses different functions (FC30 is replaced by built-in conversions and the new DINT_TO_STRING / REAL_TO_STRING with format specifiers). String handling and OPC UA String data type are discussed in section 8.

2. Root Cause Analysis

FC30 (R_STRG) is part of the standard STEP 7 conversion library (Standard Library → TI-S7 Converting Blocks). The block accepts a 32-bit REAL input and writes an ASCII representation into a STRING buffer. The function does not accept any format specifier; the output layout is hard-coded as scientific notation with the following template:

[sign]0.dddddddE[sign]ee

This template is fixed for the following reasons:

  1. Legacy compatibility with 4-line text displays (TD17, OP7, OP17). Early Siemens operator panels could not render floating-point values directly. The firmware in those panels called the same conversion function. To keep a single source of truth, the format was fixed.
  2. Deterministic string length. A fixed scientific format guarantees the output always fits in the 14-character body of a String[16] or larger buffer. Format specifiers would risk overflow.
  3. Lossless round-trip. Scientific notation preserves the full IEEE 754 precision. Truncating the mantissa or rounding to a fixed decimal would lose accuracy for traceability records.

When the STRING is exposed to OPC, the data-type boundary is crossed. The S7 STRING data type has a 2-byte header (maximum length, current length) followed by ASCII bytes. The OPC UA String data type, as defined in the OPC UA specification (Part 3, section 8.21), is a Unicode UTF-8 byte sequence with no header. The OPC server must perform the translation. Most servers strip the S7 header and expose only the ASCII body. The OPC client then sees an opaque byte sequence and simply renders the leading characters. With a 5-character view of a 14-character scientific-notation string, the rendered value is meaningless.

Defect chain summary: The choice of FC30 enforces scientific notation → the OPC client cannot interpret a 14-byte scientific string as decimal → the truncated display is mathematically incorrect → the traceability system receives unparseable data.

3. Solution Decision Matrix

Four engineering approaches resolve the defect. Each has different cost, code footprint, and migration risk. The matrix below is the basis for selecting an approach for a given installation.

Solution Code in PLC Code in OPC client Latency Migration risk Best for
1. Expose REAL; format in OPC client None Format string Lowest Low (only SCADA change) SCADA-only consumption, no MES
2. Use STEP 7 conversion library variants Replace FC30 with FC39, FC16, FC17 None Low Low (block swap) Integer-only data with leading zero suppression
3. Build decimal string manually in S7 FC30 + custom string-build None Medium Medium (custom code) Strict decimal format, fixed width, traceability
4. Use S5 conversion blocks (FC93-100) FC93-FC100 string conversions None Medium High (legacy blocks) S5 migrations, asymmetric formats
Recommendation hierarchy. Solution 1 is preferred when the downstream system is a SCADA/HMI that has a format function. Solution 2 is the cheapest PLC-only fix. Solution 3 is the correct choice for traceability/MES with rigid string contracts. Solution 4 is reserved for S5-to-S7 migration projects.

4. Solution 1: Expose REAL Directly and Format in the OPC Client

The cleanest fix is to remove the FC30 conversion entirely and expose the 32-bit REAL value as a native OPC tag. The OPC client (SCADA, HMI, or MES) is responsible for formatting the number into a human-readable string using its built-in display function.

4.1 STEP 7 Configuration

Remove the FC30 call. Expose DB15.DBD48 as a 4-byte REAL OPC tag. The DB must be non-optimized (classic DB) so the OPC server can map the tag by absolute address. In a STEP 7 DB definition, mark the relevant area as:

REAL   "MeasuredValue";   // DB15.DBD48

In the SIMATIC NET OPC server, the tag is configured as S7:[S7 connection_1]DB15,REAL48 (byte-offset form) or as the symbolic name MeasuredValue. The OPC client receives a VT_R4 / IEEE 754 32-bit float. Formatting is then a client-side operation.

4.2 OPC Client Format Examples

Most OPC clients have a format-string function. Common patterns:

  • WinCC / TIA Portal HMI: Output field property → Format pattern: 999.99 or 0.00. The runtime converts REAL to text per the format specifier.
  • Ignition: Bind the OPC tag to a Label component; set Format String to {:.2f} (Python format specifier). Two decimal places are enforced.
  • C# OPC client (OPC Foundation .NET Standard):strong> use value.ToString("0.00", CultureInfo.InvariantCulture) to guarantee locale-independent decimal output.
  • Python (OpenOPCUA / asyncua): f'{value:.2f}' returns a string with two decimal places.

Trade-off: This is the cleanest engineering fix but requires the downstream MES or traceability system to support REAL data. If the traceability vendor contract mandates a STRING, this approach is not viable.

5. Solution 2: Use the STEP 7 Standard Conversion Library

If the OPC tag must remain a STRING, but the source data is a DINT or INT (not a floating-point REAL), use the integer-to-string functions in the same TI-S7 library. The function set is summarized below.

Block Name Input type Output format Notes
FC16 I_STRNG INT (16-bit) '-32768' to '32767' with leading sign 6-character max output
FC17 DI_STRNG DINT (32-bit) '-2147483648' to '2147483647' 11-character max output
FC30 R_STRNG REAL (32-bit float) '+0.dddddddE+ee' (always scientific) 14-character output, fixed format
FC39 STRING_DI STRING → DINT Reverse of FC17 String-to-DINT parser
FC40 STRING_R STRING → REAL Reverse of FC30 String-to-REAL parser

For the case where the source is a scaled integer (e.g., 18324 represents 1.8324 with implicit 1e-4 scaling), FC17 DI_STRNG produces a clean decimal string '18324'. The OPC client then adds the decimal point per the scale factor. This is a common practice in weight and length measurements where fixed-point scaling is used.

5.1 Ladder Logic Example (FC17 DI_STRNG)

The call interface is identical to FC30:

NETWORK 1: Convert scaled DINT to STRING
CALL   "DI_STRNG"
  IN    :=DB15.DBD48      // DINT 18324
  RET_VAL:=DB5.STRING2     // '18324'

Then the OPC client (or a small SCADA script) inserts the decimal point. Example Python:

raw = await opc_tag.read()    # '18324'
val = float(raw) / 10000.0      # 1.8324
formatted = f'{val:.2f}'        # '1.83'

6. Solution 3: Build the Decimal String Manually in STEP 7

When the MES contract demands a fixed-width ASCII decimal string, the only fully deterministic solution is to build the string character-by-character in the S7 user program. The algorithm decomposes the REAL into integer and fractional parts, then writes ASCII codes 0x30..0x39 (the digits '0'..'9') plus a decimal separator (typically 0x2E for '.' or 0x2C for ',' per locale) into a DB string buffer.

6.1 Algorithm Overview

  1. Multiply the REAL by 10^N (where N is the number of decimal places desired). For 1.8324 with N=2, this becomes 183.24.
  2. Apply TRUNC (FC at address 0x00, built-in in STEP 7) to obtain the integer 183.
  3. Extract hundreds, tens, and units digits using DIV 100, MOD 10, etc.
  4. Add 48 (0x30) to each digit to produce the ASCII code.
  5. Insert a decimal separator character at the correct position.
  6. Write the resulting characters into the STRING buffer, set the length byte, and zero the remainder.

6.2 SCL (Structured Control Language) Implementation

SCL is the most concise option for this algorithm. The function below builds a 6-character decimal string in the form X.YY (one integer digit, decimal point, two fractional digits). Adjust the constants for different widths.

FUNCTION FC100 : VOID
VAR_INPUT
  rValue : REAL;        // 1.8324
  iDecimals : INT := 2;    // precision
END_VAR
VAR_IN_OUT
  sOut : STRING[8];       // target buffer
END_VAR
VAR_TEMP
  rScaled : REAL;
  diScaled : DINT;
  iIntPart : DINT;
  iSign : INT;
  arrBytes : ARRAY[1..8] OF BYTE;
  i : INT;
END_VAR
BEGIN
  // Handle sign
  IF rValue < 0.0 THEN
    iSign := 1;
    rScaled := -rValue;
  ELSE
    iSign := 0;
    rScaled := rValue;
  END_IF;

  // Scale to integer
  rScaled := rScaled * 10.0 ** iDecimals;
  diScaled := DINT_TO_DINT(TRUNC(rScaled + 0.5));

  // Build digits into a temporary byte array
  FOR i := 1 TO 8 DO arrBytes[i] := 0; END_FOR;
  arrBytes[2] := B#16#2E;  // '.' separator at position 2

  diScaled := DINT_TO_DINT(DI_MOD(IN:=diScaled, OUT:=diScaled));  // safety

  // Integer part (one digit) and fractional part
  iIntPart := diScaled / 100;
  arrBytes[1] := INT_TO_BYTE(iIntPart + 48);
  arrBytes[3] := INT_TO_BYTE(DI_MOD(IN:=diScaled/10, OUT:=iIntPart) + 48);
  arrBytes[4] := INT_TO_BYTE(DI_MOD(IN:=diScaled, OUT:=iIntPart) + 48);

  // Sign prefix if needed
  IF iSign = 1 THEN
    arrBytes[1] := B#16#2D;  // '-'
  END_IF;

  // Copy to STRING buffer (header + body)
  sOut[0] := 0;  // S7 STRING header: max length (set by editor)
  sOut[1] := 4;  // actual length = 4 (e.g., '1.83')
  FOR i := 1 TO 4 DO
    sOut[i+1] := CHAR_TO_BYTE(CHAR(arrBytes[i]));
  END_FOR;
END_FUNCTION
STRING memory layout in S7. An S7 STRING[N] occupies N+2 bytes. Byte 0 is the maximum length, byte 1 is the current length, and bytes 2..N+1 are the ASCII characters. Direct byte-write access must respect this header. Failing to set byte 1 correctly is a common cause of the OPC client receiving stale or garbage characters.

6.3 Why the Custom Function Is Necessary

FC30 has no format specifier, no decimal-place parameter, and no way to suppress the scientific notation. The standard library does not include a "REAL to decimal string with N places" block. The only Siemens function that provides this is the legacy S5 conversion block set (FC93 through FC100, S5-S7 Converter), which has a different call interface and is not always installed. Writing the conversion in SCL or in STL is the practical solution.

7. Solution 4: Use S5 Legacy Conversion Blocks

For S5-to-S7 migration projects, the S5 conversion library provides fixed-point output blocks. The relevant blocks are:

Block Function Input Output format
FC93 KI to string INT (16-bit) Right-aligned, leading spaces
FC94 KD to string DINT (32-bit) Right-aligned, leading spaces
FC95 KF to string REAL (32-bit) Right-aligned, leading spaces, no exponent
FC96 KG to string REAL (floating-point) Right-aligned, with decimal point, no exponent

FC96 KG_STRING is the closest analog to a "decimal REAL to STRING" function. Its output is a fixed-width, right-aligned decimal representation without scientific notation. The block is installed in the Standard Library under "S5-S7 Converting Blocks". Migrating existing S5 code that already calls FC95/FC96 is straightforward: include the library in the STEP 7 project, copy the block, and call it with the same parameter pattern.

Trade-off: The blocks are deprecated and not supported on S7-1200/1500. They should only be used to preserve existing logic, not for new development.

8. OPC UA String Data Type Mapping

When the OPC server is OPC UA (not classic OPC DA), the S7 STRING must be mapped to the OPC UA String data type. The OPC UA specification defines String in Part 3, section 8.21, as a sequence of Unicode characters encoded in UTF-8, with no header bytes.

The OPC UA standard does not include a "fixed-point REAL" data type. Floating-point values are exposed as Float (IEEE 754 32-bit) or Double (64-bit). Clients that need a decimal string must format the value themselves.

OPC UA built-in type Identifier (numeric) Identifier (string) S7 equivalent
Boolean 1 Boolean BOOL
SByte 2 SByte INT (low byte)
Int16 4 Int16 INT
Int32 6 Int32 DINT
Float 10 Float REAL
String 12 String STRING (header stripped)
DateTime 13 DateTime DATE_AND_TIME
Header stripping is server-dependent. SIMATIC NET OPC UA server strips the 2-byte S7 STRING header automatically. Kepware KEPServerEX does the same. Some older OPC DA servers expose the header bytes as part of the array, which produces a 2-character offset in the displayed string. Always verify the byte layout using an OPC client browse function before assuming a clean ASCII string.

9. Verification Procedure

After implementing one of the solutions above, perform the following verification steps in the order given.

9.1 STEP 7 Online Watch Table

  1. Open the project in STEP 7, connect online to the PLC (TCP/IP via NetPro).
  2. Open a VAT (Variable Table) and monitor the source REAL, the FC30 (or alternative) output, and the STRING buffer's length byte.
  3. Force the source REAL to known test values: 0.0, 1.8324, -0.001, 12345.6789, -12345.6789.
  4. Confirm the STRING length byte reflects the correct ASCII count.

9.2 OPC Client Browsing

  1. Open the OPC client (e.g., OPC Scout V10 for SIMATIC NET, UA Expert for OPC UA, or the KEPServerEX Quick Client).
  2. Browse to the tag. Confirm the data type matches the expected type (String, Float, etc.).
  3. Read the current value. Confirm the value matches the expected display.
  4. For STRING tags, use a hex viewer (e.g., UA Expert → DataType View → Show as Hex) to verify the byte sequence.

9.3 End-to-End Trace

  1. Trigger a known test value from the PLC (e.g., write 1.8324 to DB15.DBD48).
  2. Capture the value at the OPC server (log to a CSV file for 5 seconds).
  3. Capture the value at the OPC client.
  4. Compare all three values (PLC source, OPC server, OPC client). They must be numerically equal.

9.4 Round-Trip Test

For traceability systems, perform a round-trip test: write a STRING from the OPC client back to the PLC, parse it with FC40 STRING_R, and confirm the resulting REAL matches the original. This validates the complete data chain including the parser's tolerance of the decimal separator (',' vs '.').

10. Troubleshooting Matrix

Observed symptom Likely cause Verification Resolution
OPC tag shows '+0.18' for 1.8324 FC30 scientific output truncated by client display width Check STRING length byte (should be 14, not 5) Switch to Solution 1, 2, or 3
OPC tag shows garbage characters at the start S7 STRING header (length bytes) not stripped by server Hex view of OPC tag value Configure server to strip header, or use offset 2 in client
OPC tag shows empty string Length byte in S7 STRING is 0 VAT monitoring Re-trigger FC30; check the RET_VAL parameter is the STRING buffer pointer, not the STRING variable itself
OPC client cannot browse STRING tags Server does not support S7 STRING data type Server documentation; tag data type in OPC browser Use Solution 1 (REAL exposure) and format on client
String contains '.' but downstream expects ',' Locale-specific decimal separator in FC30 Hex view; check for 0x2E vs 0x2C Format string in client with locale-aware formatter
String length exceeds OPC server limit Server truncates at 80 or 255 bytes Server documentation Reduce string width; use multiple tags for long values
Downstream system cannot parse the string Trailing nulls or padding characters Hex view of last 2 bytes Set length byte to actual character count; do not include null terminator

11. Best Practices for S7 STRING and OPC Integration

  1. Avoid converting REAL to STRING in the PLC unless the downstream contract mandates it. Expose the REAL natively and let the SCADA/MES format the value. This eliminates FC30 format limitations and locale issues.
  2. Reserve the STRING data type for legacy MES contracts only. If a string is required, build it in a structured way (Solution 3) rather than relying on FC30's scientific output.
  3. Always set the S7 STRING length byte (byte 1) explicitly. A wrong length byte causes the OPC server to expose incorrect characters, even if the body bytes are correct.
  4. Use FC30 only when the downstream panel or system specifically requires scientific notation. For all other cases, use integer conversion (FC16/FC17) with implicit scaling, or a custom decimal function.
  5. Confirm the OPC server strips the S7 STRING header. SIMATIC NET, Kepware, and Ignition do; some older servers do not. Always verify with a hex view.
  6. Use locale-invariant decimal separators. Build strings with '.' (0x2E) in the PLC; let the client handle locale conversion if needed.
  7. For TIA Portal projects on S7-1200/1500, use the built-in REAL_TO_STRING with format specifiers. The TIA environment does not have FC30; the modern function allows controlled precision without scientific notation.

12. Migration Path: STEP 7 to TIA Portal

For sites migrating from S7-300/400 to S7-1200/1500, the FC30 issue disappears entirely. The TIA Portal runtime supports the REAL_TO_STRING function in SCL with a format-string parameter:

// TIA Portal SCL
sOut := REAL_TO_STRING(rValue);  // default format
sOut := LREAL_TO_STRING(rValue, 0, 2);  // explicit: width 0, 2 decimals

The modern function produces a decimal string directly, without scientific notation. When migrating, replace the FC30 call with the TIA equivalent and remove any OPC client workarounds that compensated for the FC30 format.

OPC UA on TIA Portal. The S7-1500 CPU has a built-in OPC UA server. STRING tags are exposed as the OPC UA String data type with no header. The integration is much cleaner than the SIMATIC NET-based S7-300/400 path. Sites planning an OPC UA upgrade should consider the S7-1500 transition as part of the architecture refresh.

13. References and Standards

  • Siemens STEP 7 V5.5 Standard and System Function Reference Manual (entry ID 1214574 on the Siemens Industry Online Support portal) — defines FC30, FC16, FC17, FC39, FC40 and the STRING data type layout.
  • Siemens SIMATIC NET OPC Server Manual (S7-300/400) — documents the S7 STRING to OPC UA String mapping, including the header-stripping behavior.
  • OPC Unified Architecture, Part 3: Address Space Model, section 8.21 — String data type definition, identifiers, and case-sensitivity rules. Available at the OPC Foundation specification repository.
  • Siemens Industry Online Support portal — the primary source for STEP 7, TIA Portal, and SIMATIC NET manuals, firmware notes, and application examples.

Why does FC30 always output scientific notation?

FC30 is a legacy conversion function designed for operator panels that pre-date floating-point display support. The output format is hard-coded as ‘+0.dddddddE+ee’ with a fixed 14-character body. The function does not accept a format parameter; there is no way to change the output within FC30 itself. To get decimal output, use a different conversion block, build the string manually in SCL, or format the value in the OPC client.

Can I configure FC30 to output decimal format?

No. FC30 has no input parameters for format, decimal places, or width. The output is always scientific notation. The only way to produce decimal output in the PLC is to use a different block (e.g., FC96 from the S5-S7 library) or to write a custom conversion function in SCL or STL using TRUNC, MOD, and direct byte writes to the STRING buffer.

Why does the OPC tag show only 5 characters?

OPC tag definitions typically specify a fixed width (e.g., 5 characters for a 5-character display). When the underlying STRING is 14 characters long, the OPC server exposes only the first 5 bytes to fit the tag definition. The fix is either to expand the tag width to 14 (and accept the scientific notation) or to change the data type / value to a decimal string that fits the 5-character limit. Most installations choose the latter.

Does the OPC server strip the S7 STRING header?

Modern servers (SIMATIC NET, Kepware KEPServerEX, Ignition) strip the 2-byte S7 STRING header automatically and expose only the ASCII body. Older servers, especially legacy OPC DA servers, may not. The S7 STRING layout is: byte 0 = max length, byte 1 = current length, bytes 2..N+1 = ASCII characters. If the header is not stripped, the OPC client receives a 2-character offset. Always verify with a hex view of the OPC tag value.

Is there a TIA Portal equivalent of FC30?

Yes, the TIA Portal S7-1200/1500 environment uses the built-in conversion function REAL_TO_STRING (in SCL) with explicit format parameters. The TIA function supports decimal notation directly, with a configurable number of decimal places. The TIA equivalent is therefore not a 1:1 drop-in for FC30 — the migration usually produces cleaner output and removes the need for OPC-side workarounds.

Back to blog