S7-1200 TSEND_C: Send Real, Int, and String Data Over TCP/IP

David Krause12 min read
S7-1200SiemensTutorial / How-to
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 TSEND_C: Sending Real, Int, and String Data Over TCP/IP to a PC Application

Engineers integrating a SIMATIC S7-1200 PLC with a PC-based data acquisition or test application (e.g. NI LabWindows/CVI, LabVIEW, Python, .NET) frequently hit the same wall: the example program in TIA Portal uses a 10-element Array of Char, the data round-trips perfectly through HyperTerminal, and the moment the developer switches the data type to Real, Int, or String, the receiver reports "junk". This is not a bug in TSEND_C — it is a misunderstanding of what the instruction actually moves on the wire. TSEND_C is a transparent byte-pipe: it copies the contiguous byte image of the DATA tag to the TCP socket and tells the receiver the length. The CPU performs no conversion. If the PC application expects ASCII characters but the PLC is shipping the IEEE-754 bit pattern of a floating-point value, the terminal will display garbage. The fix is to convert on the PLC side, convert on the PC side, or move to a higher-level protocol.

This reference walks through the engineering discipline required to make S7-1200 ↔ PC communication deterministic, including firmware prerequisites, TSEND_C/TRCV_C parameter layouts, byte-order conventions, conversion instruction selection, and a working STL/SCL pattern that ships Real, Int, and String values to a LabWindows/CVI TCP client without data loss.

1. What TSEND_C Actually Does

Per the SIMATIC S7-1200 manual, TSEND_C ("Send and receive data using Ethernet") establishes a TCP or ISO-on-TCP connection, transmits a data block, and (optionally) terminates the connection in a single call. Its companion TRCV_C accepts bytes from the partner and writes them into a configured data tag. Both instructions sit on top of the TCON connection description block (specified through the IDB/connection parameters), and both copy raw bytes — not typed values — into the transmit buffer.

The instruction signature is:

Parameter Direction Type Description
REQ Input Bool Rising edge initiates the send/receive operation
CONT Input Bool TRUE = keep the connection open after transmission completes
LEN Input UInt Number of bytes to send; set to 0 for automatic length detection on String tags
DATA InOut VARIANT Pointer to the tag to transmit (any elementary or complex type)
ID InOut CONN_OUC Reference to the TCON connection (HW ID)
DONE Output Bool Set for one scan when the job completes successfully
BUSY Output Bool TRUE while the job is in progress
ERROR Output Bool TRUE if the job terminated with an error
STATUS Output Word Detailed error/status code (see Section 8)

The crucial point: DATA is a VARIANT pointer. The instruction does not inspect the element type; it reads LEN bytes starting at the address of DATA. Therefore a Real tag occupies 4 bytes of IEEE-754 little-endian, an Int occupies 2 bytes, a DInt 4 bytes, and a String[20] occupies 22 bytes (2-byte length header + 20-byte payload). The PC must reconstruct the value from those exact bytes.

2. Firmware and Software Prerequisites

Component Minimum Recommended Notes
CPU firmware (S7-1200) V4.0 V4.5 / V4.6 TSEND_C/TRCV_C fully supported from V4.0; V4.4+ adds enhanced ISO-on-TCP keep-alive
TIA Portal V13 SP1 V17 / V18 Sample program in source uses V11 SP2; modernise to V16+ for current conversion libraries
STEP 7 Basic/Professional Same as TIA Portal — Required for SCL or LAD/FBD editing
PC TCP stack Winsock 2.0 OS-native LabWindows/CVI uses TCP/IP Library (ni5289) or standard Berkeley sockets
Ethernet cabling Cat 5e Cat 6A Direct or via managed switch; PLC and PC must share subnet
Firmware compatibility: S7-1200 CPUs with firmware V4.0+ expose the full TSEND_C/TRCV_C instruction set under "Communication > Open User Communication". Firmware V3.0 supports only a subset (no keep-alive, no ISO-on-TCP for TSEND_C — TCON is required as a separate block). Always verify the firmware version under Online & Diagnostics > CPU Information before commissioning.

3. The Data-Type Problem: Why the PC Sees "Junk"

The S7-1200 stores values in little-endian byte order, with the following on-wire footprints:

TIA Data Type Bytes on Wire Example (Decimal 1234.5) Hex (LE) on Wire
Bool 1 TRUE 0x01
Int (16-bit) 2 1234 0xD2 0x04
DInt (32-bit) 4 1234 0xD2 0x04 0x00 0x00
Real (32-bit IEEE-754) 4 1234.5 0x00 0x00 0x9A 0x45
LReal (64-bit) 8 1234.5 0x00 0x00 0x00 0x00 0x00 0x4D 0x94 0x40
String[20] 22 "Hello" 0x05 0x00 [0x48 0x65 0x6C 0x6C 0x6F] + 0x00 padding
Char / Array of Char n 'A' 'B' 'C' 0x41 0x42 0x43

When the PC application uses HyperTerminal or a generic printf/recv call, the C runtime interprets each received byte as an ASCII code point. 0x00 0x00 0x9A 0x45 (the IEEE-754 image of 1234.5) becomes four NUL, NUL, non-printable, 'E' characters — exactly the "junk" reported in the source thread. Three options resolve the issue:

  1. Convert on the PLC to ASCII before sending. Use S_CONV / REAL_TO_STRING / INT_TO_STRING instructions to produce a String tag, then transmit the string. The PC receives printable characters and parses with atof() or strtod().
  2. Transmit raw bytes and decode on the PC. Send a REAL tag directly with LEN=4; the PC reads 4 bytes and reinterprets them as a little-endian IEEE-754 float using memcpy.
  3. Switch to a higher-level protocol. Use Siemens Open User Communication framing, OPC UA, Modbus TCP, or the S7 communication protocol — each carries typed data without manual byte manipulation.

4. Recommended Approach: ASCII Framing for Maximum Compatibility

For a PC application written in C (LabWindows/CVI, Visual Studio) or Python, the lowest-friction solution is to convert every numeric value to a fixed-width ASCII string on the PLC, optionally append delimiters, and let the PC parse the line with standard strtok / sscanf. This mirrors how industrial serial protocols (Modbus RTU ASCII, NMEA 0183) have worked for 40 years and avoids endian, padding, and alignment concerns.

4.1 PLC Data Block Definition

DATA_BLOCK "DB_Comms"
  STRUCT
    bTriggerSend   : Bool;        // Pulse to start a send cycle
    rTemperature   : Real;        // 22.5  °C
    rPressure      : Real;        // 1013.2 mbar
    iCount         : Int;         // 1234 pulses
    sSerial        : String[20];  // "SN-A12345"
    sPayload       : String[64];  // Assembled ASCII line
    sReceiveBuf    : String[128]; // TRCV_C target
    iRxLen         : UInt;        // Bytes actually received
  END_STRUCT;
END_DATA_BLOCK

4.2 SCL Build Code for the ASCII Payload

// "DB_Comms".sPayload := 'T=' + REAL_TO_STRING("DB_Comms".rTemperature)
//                      + 'P=' + REAL_TO_STRING("DB_Comms".rPressure)
//                      + 'N=' + INT_TO_STRING("DB_Comms".iCount)
//                      + 'S=' + "DB_Comms".sSerial
//                      + '$R$L';

Note that REAL_TO_STRING returns a string of length up to 14 characters (sign, 10 digits, decimal point, exponent). For a deterministic byte count, convert the real to a fixed-format string using String format instructions (TIA V16+) or, if unavailable, use S_CONV with explicit scaling:

iTempInt := REAL_TO_INT("DB_Comms".rTemperature * 10.0);
"DB_Comms".sPayload := 'T=' + INT_TO_STRING(iTempInt) + '/10;';

4.3 Sending the ASCII String

Parameter Value Reason
REQ "DB_Comms".bTriggerSend (rising edge) One-shot per trigger
CONT TRUE Keep TCP connection alive between sends
LEN 0 Auto-detect String length (header + chars)
DATA "DB_Comms".sPayload String VARIANT pointer
ID "DB_Comms".iConnId From TCON parameter block
LEN = 0 magic value: For String data, set LEN = 0 in TSEND_C so the instruction transmits only the populated characters (current length from the String header), not the entire 66-byte buffer. The PC receives exactly what was written.

5. Alternative Approach: Raw Binary Transfer

If you need maximum throughput (e.g. 1 kHz waveform streaming) and the PC application can handle a binary protocol, the most efficient path is to concatenate a fixed-format frame and transmit it with a known length. Define a structure with no padding (use STRUCT with packed layout) and send it raw.

TYPE "UDT_Telemetry"
  STRUCT
    rTemperature : Real;   // 4 bytes
    rPressure    : Real;   // 4 bytes
    iCount       : DInt;   // 4 bytes
    byStatus     : Byte;   // 1 byte
    sId          : String[8]; // 10 bytes (length + 8 chars)
  END_STRUCT;
END_TYPE

Transmit with LEN := SIZEOF("UDT_Telemetry"). On the PC side (C example):

struct Telemetry {
    float  temperature;   // 4 bytes, little-endian
    float  pressure;      // 4 bytes, little-endian
    int32_t count;        // 4 bytes, little-endian
    uint8_t status;       // 1 byte
    uint16_t id_len;      // 2 bytes
    char    id[8];        // 8 bytes
};
// Total = 23 bytes per frame
// recv(sock, &frame, sizeof(frame), MSG_WAITALL);
Endianness warning: S7-1200 is little-endian. x86/x64 PCs are little-endian — the memcpy/recv pattern works without htonl/ntohl swaps. If the PC target is big-endian (rare, e.g. some network processors), use Siemens SWAP instructions or PC-side bswap.

6. Receiving on the PC: LabWindows/CVI Pattern

LabWindows/CVI provides the TCP/IP Library. A minimal client loop that parses ASCII frames from the S7-1200:

int CVICALLBACK TCPClientCallback(unsigned handle, int event,
                                  int error, void *callbackData) {
    char rxBuf[256];
    int  nRead = 0;
    switch (event) {
        case TCP_DATAREADY:
            nRead = ClientTCPRead(handle, rxBuf, sizeof(rxBuf)-1, 1000);
            rxBuf[nRead] = '\0';
            // Parse payload e.g. "T=22.5;P=1013.2;N=1234;S=SN-A12345\r\n"
            float T, P; int N; char S[32];
            sscanf(rxBuf, "T=%f;P=%f;N=%d;S=%31s", &T, &P, &N, S);
            // Update GUI / log
            break;
        case TCP_DISCONNECT:
            // Reconnect with ConnectToTCPServer
            break;
    }
    return 0;
}

For binary telemetry, replace the sscanf line with a memcpy into a C struct and read sizeof(struct Telemetry) per frame using the MSG_WAITALL flag.

7. TCON Connection Configuration (TIA Portal Step-by-Step)

  1. Open the device view of the S7-1200 CPU and double-click the PROFINET interface.
  2. Set the IP address and subnet mask (e.g. 192.168.0.10 / 255.255.255.0). Match the PC subnet.
  3. Add a new Open User Communication connection block (right-click the CPU → Properties → Open User Communication). Configure:
    • Connection type: TCP
    • Partner IP address: 192.168.0.20 (PC running LabWindows)
    • Partner port: e.g. 2000
    • Local port: any (e.g. 0 = dynamic)
    • Active connection establishment: enable on the PLC side (TSEND_C is an active client)
  4. Compile and download the hardware configuration.
  5. Create a global DB holding the connection ID (Word) and a TCON_PARAM instance, or use the system-supplied instance DB created when you drop TSEND_C into a network.

8. Status and Error Codes

TSEND_C/TRCV_C return a 16-bit STATUS word. The high byte (bits 15…8) maps to the protocol class, the low byte to the actual error. The most common values encountered when sending wrong data types:

STATUS (hex) Meaning Remedy
0x0000 No error —
0x7000 No job active Trigger a rising edge on REQ
0x7001 Job starting Wait for DONE/BUSY cycle
0x7002 Job in progress Normal during transmission
0x8085 LEN = 0 and DATA is not a String Set LEN to byte count, or change DATA to String
0x80A1 Connection not established / partner refused Verify partner TCP port is open and firewall rule
0x80C3 All connection resources in use Reduce simultaneous TCON count (max 8 on S7-1200)
0x80C4 Temporary communications error, partner reset Implement retry logic on REQ
0x80B1 Invalid DATA pointer (VARIANT = NULL) Check pointer to DB / tag
0x80BB LEN exceeds available data Reduce LEN; for Strings use 0

9. Verification Procedure

  1. Online watch table: Place "DB_Comms".sPayload, TSEND_C.DONE, and TSEND_C.STATUS in a watch table with trigger on bTriggerSend.
  2. Wireshark capture: Run Wireshark on the PC with filter tcp.port == 2000. Confirm the byte count equals the populated String length.
  3. HyperTerminal round-trip: A 22-character string with LEN=0 must produce exactly 22 bytes in the capture.
  4. Raw-Real verification: Send a Real tag with value 1234.5 and LEN=4. The 4-byte payload must be 00 00 9A 45 on the wire.
  5. Connection state: Monitor TCON.DONE and TCON.STATUS after a CPU RUN↔STOP cycle to confirm auto-reconnect logic.

10. Troubleshooting Matrix

Symptom Likely Cause Resolution
PC receives only printable ASCII, no numeric values DATA is String after conversion — expected behaviour Parse with sscanf / strtok on the PC
PC sees non-printable characters instead of Real DATA is Real; PC is interpreting bytes as ASCII Convert to String on PLC, or use memcpy into a float on the PC
TSEND_C reports STATUS 0x8085 LEN=0 used on a non-String tag Set LEN to exact byte count
STATUS 0x80A1 after power-up Partner TCP listener not yet started Add retry / delay before first REQ
Data length received mismatches expected LEN parameter includes the 2-byte String header Use LEN=0 for String to send only populated chars
CPU goes to STOP on bad reception TRCV_C writing into a String with LEN > declared length Clamp LEN to max String capacity - 2
Communication works for 1 hour then drops Keep-alive not configured; switch/firewall closes idle socket Set "Keep-alive" option in TCON to 30 s

11. When to Use a Higher-Level Protocol

If the PC application needs typed data without parsing, the engineering effort of conversion on both sides — the original complaint in the field report — becomes unjustified. For greenfield projects, prefer:

  • OPC UA: The S7-1200 firmware V4.4+ supports OPC UA server. The PC consumes typed variables directly via any OPC UA client SDK (Siemens, .NET, Python opcua, LabVIEW DataFinder).
  • Modbus TCP: Use the MB_CLIENT instruction (S7-1200 firmware V4.0+). Register mapping handles integer and float values natively; dozens of PC libraries exist.
  • S7 Communication: The PC uses libnodave, Snap7, or the official Siemens S7 protocol to read DBs directly without a custom byte protocol.

For the specific use case of "send a few strings of size 20 and a few real values" described in the source, the ASCII-framing approach in Section 4 yields the shortest development time and the fewest moving parts. For 100+ tags or sub-100 ms update rates, move to OPC UA or S7 communication.

12. Frequently Asked Questions

Can TSEND_C on the S7-1200 send Real, Int, and DInt data types directly, or only Char?

TSEND_C is byte-transparent and accepts any VARIANT pointer, including Real, Int, DInt, and String. The instruction does not convert the value — it copies the raw memory image to the socket. The PC application must know the byte layout (little-endian IEEE-754 for Real, 2 bytes for Int) and decode accordingly, or the PLC must convert the value to an ASCII string first.

Why does my PC application display garbage characters when I send a Real value?

The PC is interpreting the 4-byte IEEE-754 little-endian representation as ASCII code points. For a value of 1234.5, the wire bytes are 0x00 0x00 0x9A 0x45, which appear as two NUL characters, a non-printable glyph, and 'E'. Convert the Real to a String on the PLC using REAL_TO_STRING or by scaling to an Int (e.g. × 10 for one decimal) and converting with INT_TO_STRING, then send the String with LEN=0.

What value should I use for the LEN parameter when sending a String tag?

Set LEN = 0 in the TSEND_C block. The instruction then reads the current length field of the String header and transmits exactly that many characters, excluding the 2-byte length header itself and any trailing pad bytes. This prevents the PC from receiving garbage from the unused String capacity.

What is the maximum number of TSEND_C connections an S7-1200 can handle simultaneously?

Up to 8 Open User Communication connections (TCP or ISO-on-TCP) can be active concurrently on a standard S7-1200 CPU, depending on firmware and CPU type. Each TCON consumes a connection resource; STATUS 0x80C3 indicates the limit has been reached. Consolidate tags into one frame per direction when possible.

Is TSEND_C a TCP client or server, and how does that affect the LabWindows CVI side?

TSEND_C is the active partner and initiates the TCP connection. In TIA Portal, enable "Active connection establishment" on the TCON configuration. The LabWindows/CVI PC application must therefore act as a TCP server using the RegisterTCPServer / TCPServerCallback functions from the TCP/IP Library, listening on the partner port defined in the PLC connection block (e.g. port 2000).

Back to blog