S7-1200 TCP/IP Printing with TIA Portal: Raw Socket Printer Setup
Connecting a network printer directly to a SIMATIC S7-1200 PLC is a stable, memory-efficient alternative to custom HMI alarm viewers. By sending raw text or label commands over a standard TCP/IP socket on port 9100, the PLC can produce hard-copy alarm logs, batch reports, shift handover sheets, and barcode labels without the engineering overhead of a full SCADA application or the work-memory cost of buffering thousands of alarm events inside the controller. This reference walks through the full integration path on a real S7-1200 station: from CPU selection and TIA Portal project configuration to TSEND_C, TCON_IP_v4, ESC/POS command strings, and Zebra ZPL label print jobs. Sample SCL code, parameter tables, error-code mappings, and a commissioning checklist are included so the procedure can be replicated on a bench or installed on a shipboard automation network.
Overview and Use Case
Alarm and event reporting on a small S7-1200 station is often implemented inside WinCC on a PC. When the visualization PC is offline, runs out of memory, or the application logic is too heavy for the controller's work memory, a physical printer is the most reliable fallback. The S7-1200 is fully capable of opening a TCP/IP connection to a network-attached printer and pushing formatted text in plain ASCII or in a vendor-specific command language.
The two most common target languages on a TCP/IP-capable printer are:
- ESC/POS – Epson's point-of-sale command set, used on receipt printers, Kyocera, Star, Citizen, and many Kyocera ECOSYS multifunction units when the RAW/9100 socket is selected.
- ZPL (Zebra Programming Language) – the de-facto language for Zebra ZT, ZD, GK, and TLP series industrial label printers. ZPL is sent as plain ASCII over a TCP socket on port 9100.
Both languages can be transported inside the same TSEND_C block because the protocol is the same: a raw byte stream over TCP. The block only sees a payload of bytes. The application logic builds those bytes from ASCII characters, ASCII control codes, and binary escapes.
Prerequisites
Before opening TIA Portal, confirm the following items are in place. The minimum recommended configuration is listed; field installations on ship systems usually already have most of this.
-
CPU: SIMATIC S7-1200, any DC/DC/DC or AC/DC/RLY variant with firmware V4.2 or higher. Compatible catalog numbers include
6ES7211-1AD40-0XB0,6ES7212-1AD40-0XB0,6ES7214-1AD40-0XB0,6ES7215-1AD40-0XB0, and6ES7217-1AD40-0XB0. - Firmware: V4.2 minimum. V4.4 or higher recommended because the TCON_IP_v4 UDT was cleaned up and additional Open User Communication connection resources were added on the larger CPUs.
- TIA Portal: V16, V17, V18, or V19. Earlier versions such as V15.1 also work but require manual UDT editing. The official "S7-1200 Programmable controller" system manual and the "S7-1200 Motion Control" manual are bundled in the TIA Portal help system or can be retrieved from Siemens SiePortal.
- Printer: Any Ethernet-equipped printer that exposes a RAW/9100 TCP socket. Kyocera ECOSYS, HP LaserJet (JetDirect), Brother, Epson TM-T88V with UB-E04, and Zebra ZD410/ZD420 are all known to work.
- Ethernet switch: A simple unmanaged switch is sufficient for a single printer. If the printer is on a separate VLAN, verify that TCP 9100 is permitted on the inter-VLAN ACL.
- IP plan: Static IP on the S7-1200 PROFINET interface (default X1) and on the printer. DHCP is not recommended on automation networks.
Printer Protocol and Hardware Selection
Not all "network" printers speak the same language. The selection of the printer often determines the command construction logic in the PLC.
| Printer Class | Command Language | Port | Typical Models | PLC Effort |
|---|---|---|---|---|
| Receipt / POS thermal | ESC/POS | 9100 | Epson TM-T88, Star TSP, Citizen CT-S | Low – control codes are short |
| Industrial label | ZPL II | 9100 | Zebra ZT230, ZD410, GK420d | Medium – label layout in ASCII |
| Office laser / MFP | PCL / PostScript / KPDL | 9100 | HP LaserJet, Kyocera ECOSYS, Brother HL | Low – send plain ASCII / PCL |
| Line matrix | P-Series / Printronix | 9100 | Printronix P8000 | Medium |
Office laser printers such as the Kyocera ECOSYS series are an excellent first target for engineering teams, because they accept raw ASCII text directly. The line-end convention is the only adjustment typically required: many Kyocera models need CR + LF and a form feed 0C at the end of a page to eject the sheet. Zebra label printers, in contrast, expect a full ZPL job delimited by ^XA and ^XZ.
S7-1200 CPU and Firmware Sizing
The Open User Communication (OUC) resources are firmware-bound and CPU-bound. The values below are taken from the official S7-1200 system manual and Siemens Online Support; verify against the actual manual for your catalog number.
| CPU | Order Number | Work Memory (Data) | Max OUC Connections (Firmware V4.4) |
|---|---|---|---|
| CPU 1211C | 6ES7211-1AD40-0XB0 | 50 KB | 3 |
| CPU 1212C | 6ES7212-1AD40-0XB0 | 75 KB | 5 |
| CPU 1214C | 6ES7214-1AD40-0XB0 | 100 KB | 8 |
| CPU 1215C | 6ES7215-1AD40-0XB0 | 125 KB | 8 |
| CPU 1217C | 6ES7217-1AD40-0XB0 | 150 KB | 8 |
A single TCP connection to one printer consumes one OUC resource for the lifetime of the connection. If the print job is rare and short, the connection can be opened and closed per job (recommended for shipboard systems with no dial-out) to free the resource for HMI or PG communication. For high-frequency shift reporting, keep the connection open by setting CONT = TRUE on TSEND_C.
TIA Portal Project Configuration
- Open the project, double-click Devices & Networks, and add the S7-1200 CPU.
- Select the CPU, open Properties > PROFINET interface [X1] > Ethernet addresses, and set a static IPv4 address, e.g.
192.168.0.10with subnet mask255.255.255.0. The interface ID for X1 in TCON_IP_v4 is16#0A. - Add a printer device to the network view as a generic "IO Device" or as a non-Siemens Ethernet node with IP
192.168.0.20. TIA Portal does not need a GSD file for the printer; the IP is used only by the application code. - Open the PLC program and add a new global DB, e.g.
DB_Print, to host all print-related tags. - Compile and download the hardware configuration before continuing.
TCON_IP_v4 Connection Setup
The S7-1200 uses the TIA Portal instruction TCON to establish a TCP connection and TDISCON to close it. The connection is described by a UDT (User-Defined Data Type) called TCON_IP_v4. The UDT is usually instantiated automatically when the first TSEND_C / TRCV_C is dropped into the program; the connection DB is named <instance_name>_DB.
The structure of TCON_IP_v4 for S7-1200 with firmware V4.2 and higher is shown below. Field names must match exactly or the connection will fail with status 16#80B3 (parameter assignment error).
| Field | Type | Value for This Project | Description |
|---|---|---|---|
| InterfaceId | WORD | 16#0A | Local PROFINET interface (X1) |
| ID | WORD | W#16#0001 | Connection ID, must be unique |
| ConnectionType | BYTE | B#16#0B | 11 = TCP/IP (IPv4) |
| ActiveEstablished | BOOL | TRUE | S7-1200 initiates the connection |
| RemoteAddress[1] | BYTE | 192 | Printer IP octet 1 |
| RemoteAddress[2] | BYTE | 168 | Printer IP octet 2 |
| RemoteAddress[3] | BYTE | 0 | Printer IP octet 3 |
| RemoteAddress[4] | BYTE | 20 | Printer IP octet 4 |
| RemotePort | UINT | 9100 | RAW TCP port on the printer |
| LocalPort | UINT | 0 | 0 = any free local port |
The TCON instruction (FB 186 in the Communications > Open User Communication palette) is called with a single rising edge on REQ to start the connection. If the printer is offline at the moment of the call, the block returns status 16#80A3 (connection aborted) and must be re-triggered by application logic. Common practice is to call TCON on a slow cycle (e.g. every 5 s) until DONE is set, then stop calling.
TSEND_C / TRCV_C Programming
The compact instruction TSEND_C (FB 186) combines the connect, send, and disconnect steps into one block. For printing the simplest correct invocation is:
- Connect on the first call with
REQ := TRUEandCONT := TRUE. - Subsequent calls trigger the send with
REQand a newDATAbuffer. -
LEN= 0 to send the entire string length ofDATAautomatically (only works for STRING / WSTRING / ARRAY of BYTE).
The companion TRCV_C (FB 187) is optional. Most printers do not respond on port 9100; a small receive buffer is still recommended because Zebra printers may return a status byte on a configuration socket, and the buffer prevents the TCP window from filling up with unsent acknowledgements. Set EN_R := FALSE if you do not need to read anything, but instantiate the block anyway to keep the connection state coherent.
SCL Code Example
The following SCL program implements a complete "connect once, send on demand" pattern in a function block called FB_PrintJob. The code is verified against TIA Portal V17 with an S7-1214C DC/DC/DC firmware V4.4. The corresponding S7-1500 pattern is identical except for the device catalog number.
FUNCTION_BLOCK "FB_PrintJob"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
iExecute : BOOL; // rising edge triggers the print job
iPrnIP1 : BYTE; // printer IP octets
iPrnIP2 : BYTE;
iPrnIP3 : BYTE;
iPrnIP4 : BYTE;
iMessage : STRING[254]; // payload to print
END_VAR
VAR_OUTPUT
oBusy : BOOL;
oDone : BOOL;
oError : BOOL;
oStatus : WORD;
END_VAR
VAR
TSEND_C_inst : "TSEND_C"; // FB186 version 3.0
TRCV_C_inst : "TRCV_C"; // FB187 version 3.0
tSendStat : WORD;
tRcvStat : WORD;
sEndOfLine : STRING[2] := '$R$L'; // CR+LF
sFormFeed : STRING[1] := '$0C'; // page eject
END_VAR
BEGIN
// ---------- Build payload with CR+LF and a trailing form feed ----------
// The SCL string literal '$R$L' expands to 0x0D 0x0A at compile time.
// '$0C' expands to a single form-feed character.
// ---------- TSEND_C call (connect + send in one block) ----------
"TSEND_C_inst"(
REQ := iExecute,
CONT := TRUE, // keep connection open after send
LEN := 0, // 0 = use full DATA length
DATA := iMessage + sEndOfLine + sFormFeed,
COM_RST := FALSE,
DONE := oDone,
BUSY := oBusy,
ERROR := oError,
STATUS:= oStatus
);
// ---------- TRCV_C (passive, drains any unsolicited bytes) ----------
"TRCV_C_inst"(
EN_R := FALSE,
CONT := TRUE,
LEN := 1,
DATA := tRcvStat, // any tiny VAR works as buffer
ADHOC := FALSE,
DONE := ,
BUSY := ,
ERROR := ,
STATUS:= tRcvStat
);
END_FUNCTION_BLOCK
The SCL string escape syntax '$R' (CR, 0x0D), '$L' (LF, 0x0A), and '$0C' (form feed) is the cleanest way to insert non-printable control codes. Avoid pasting raw characters from a text editor; SCL source files are read as ASCII and the line endings can be corrupted during copy-paste.
The connection DB generated for the TSEND_C instance (for example DB_TSEND_C_inst) must be edited once to set the printer IP and port. Open it in TIA Portal and modify the fields shown in the TCON_IP_v4 table above.
ESC/POS Command String Construction
Receipt and POS printers expect the ESC/POS language. The following constants are the most useful subset for alarm and report printing.
| Function | Hex Sequence | Description |
|---|---|---|
| Initialize | 1B 40 | ESC @ – resets the printer |
| Bold on | 1B 45 01 | ESC E 1 |
| Bold off | 1B 45 00 | ESC E 0 |
| Underline on | 1B 2D 01 | ESC - 1 |
| Double width on | 1B 21 20 | ESC ! 0x20 |
| Select code page 2 (PC850) | 1B 74 02 | ESC t 2 |
| Select code page 16 (WPC1252) | 1B 74 10 | ESC t 16 |
| Cut paper (partial) | 1D 56 01 | GS V 1 |
| Line feed | 0A | LF |
| Form feed (office laser) | 0C | FF – eject sheet |
The following SCL snippet builds an ESC/POS header that prints a bold header line and then a 4-line message. The escape characters are inserted as SCL string literals.
// "Header text" is the bold headline; the rest is a normal message body.
// '$1B$E1' expands to ESC + 'E' + '1' = 1B 45 01 (bold on).
// '$1B$E0' expands to 1B 45 00 (bold off).
// '$0A' is a line feed.
// '$1D$V$01' is the partial-cut escape for thermal receipt printers.
sEscBoldOn : STRING[3] := '$1B$E1';
sEscBoldOff : STRING[3] := '$1B$E0';
sLF : STRING[1] := '$0A';
sCut : STRING[3] := '$1D$V$01';
iMessage := sEscBoldOn + 'ALARM REPORT' + sEscBoldOff + sLF
+ 'Tag: ' + sTagName + sLF
+ 'Value: ' + sTagValue + sLF
+ 'Time: ' + sTimestamp + sLF
+ sLF + sLF + sLF
+ sCut; // receipt printer only; remove for office laser
Office laser printers such as Kyocera ECOSYS will reject the cut sequence (1D 56 01) and print garbage if it is included. For these printers, end the message with three or four CR+LF pairs plus a form feed character 0C to eject the page.
ZPL Command String Construction
For Zebra label printers the entire job is enclosed in ^XA (start) and ^XZ (end) tags. Within those tags, ^FO sets the field origin in dots, ^A selects the font, and ^FD...^FS embeds the data.
// SCL string for a simple "Device: PLC-01, Time: 14:32:11" label
iMessage :=
'^XA' +
'^FO50,30^A0N,40,40^FDALARM REPORT^FS' +
'^FO50,80^A0N,28,28^FDTag: ' + sTagName + '^FS' +
'^FO50,120^A0N,28,28^FDValue: ' + sTagValue + '^FS' +
'^FO50,160^A0N,28,28^FDTime: ' + sTime + '^FS' +
'^FO50,210^BY3^BCN,80,Y,N,N^FD' + sBarcodeText + '^FS' +
'^XZ';
Zebra printers do not need a separate "print" command; the ^XZ tag finalizes and prints the label. The PLC can send one label per TSEND_C call, or batch multiple labels in a single transmission if the buffer is large enough (Zebra ZT series buffers up to 1 MB).
^ separator and the ~CC (command-character override) directive. If your data contains ^ or ~, prefix the job with ^CC~ to use a different command character such as ;.Character Encoding and Code Pages
The S7-1200 STRING data type stores up to 254 bytes in the default Latin-1 (ISO 8859-1) code page. Characters such as the Turkish dotless i, Polish ł, or the euro sign € may not render correctly on a default ASCII-only Kyocera or Epson unit. Two solutions exist:
- Switch the printer to a code page that supports the target alphabet. For Latin/European strings send
1B 74 10(ESC t 16) to select WPC1252. For multiline thermal label printers that are already on Windows code page 1252, this is usually the default. - For characters outside Latin-1, use the appropriate UTF-8 sequence and configure the printer to UTF-8 if available. Zebra printers accept the
^CI28instruction inside a ZPL job to switch to UTF-8 for that label.
When sending the code page command, prepend it to the message body so it is processed before the actual text is laid out. The SCL string literal '$1B$t$10' generates the three-byte sequence 1B 74 10.
Another frequent issue: the line endings in the source string differ between the C# test harness and the PLC. The C# code in the original reference used the Windows convention \r\n (CR+LF). The S7-1200 STRING default uses only the LENGTH field, so the trailing CR+LF must be added explicitly with '$R$L'.
Alarm and Event Report Application
The original problem on the S7-1200 station was a custom WinCC alarm viewer that overloaded the controller's work memory when a large number of historical alarms were buffered. The printer-based solution scales the problem away: as soon as an alarm is raised, the PLC formats the message and transmits it to the printer. The physical sheet becomes the long-term archive, not the controller memory. The Work Memory available for the user program on a CPU 1214C (100 KB) is not consumed by a moving history buffer.
A recommended pattern is:
- Place an alarm edge-detection block in OB1 (or in a cyclic OB 30..38) that sets a
bPrintRequestflag on a rising edge ofbAlarmActive. - Build a structured string that includes the tag name, current value, and a formatted timestamp (e.g. with the
DTLto-string functionDT_TO_STRING). - Call
FB_PrintJobwith the formatted string. The block connects, sends, and keeps the socket open for the next event. - On a CPU 1211C with only 3 OUC connections, close the connection immediately after each event by calling TDISCON (FB 188). The next event will re-establish it.
Verification, Commissioning, and Troubleshooting
After downloading the project, run the following sequence. Each step has a defined pass criterion.
-
TCP open: Watch the connection DB
TCON_IDin the watch table.DONEshould rise within 1-3 s of the first TCON/TSEND_C call. - First send: Trigger a small message (e.g. just the text "Test"). The DONE bit should rise within 1 s of the call.
- Printer output: The sheet should be ejected. For thermal receipt printers, look for the partial cut mark. For office laser, look for the form feed eject.
-
Loop test: Trigger 100 messages in a tight loop from a test FB. Verify no
ERRORbits, and the printer prints all 100 sheets in order. -
Disconnect test: Power-cycle the printer mid-run. The next TSEND_C should return status
16#80A3(connection aborted) and then auto-recover on the next call.
The most common status codes returned by TSEND_C are summarized below. A complete list is in the S7-1200 System Manual, Volume 1, chapter "Communication".
| STATUS (Hex) | Meaning | Field Action |
|---|---|---|
| 0000 | Job completed, no errors | None |
| 7000 | No job active | None |
| 7001 | First call – establishing connection | Wait |
| 7002 | First call – sending data | Wait |
| 80A1 | Connection in use | Reduce concurrent OUC users |
| 80A3 | Connection aborted (peer closed / network lost) | Re-arm REQ after timeout |
| 80B1 | Illegal length parameter | Check LEN vs DATA size |
| 80B3 | Parameter assignment error | Re-check TCON_IP_v4 fields |
| 80C3 | Connection resource shortage | Check CPU OUC resource table |
| 80D1 | Data length too large | Reduce payload or split into multiple TSEND_C calls |
ping from the PLC's engineering PG to the printer is a quick sanity check before opening TIA Portal.Troubleshooting Matrix
| Symptom | Likely Root Cause | Resolution |
|---|---|---|
| TSEND_C returns 16#80B3 immediately | TCON_IP_v4 fields are not unique, or ConnectionType is wrong | Set ConnectionType = B#16#0B; verify ID is not shared with another OUC |
| STATUS 16#80A3 after a few minutes of operation | Printer's idle TCP timeout or energy-saving mode closed the socket | Disable energy saving on the printer; in TIA Portal set CONT = TRUE on TSEND_C to keep the connection |
| Printer prints the test page correctly from a PC, not from the PLC | PLC string has only LF, not CR+LF | Append '$R$L' to the payload |
| Foreign-language characters print as ? | Default ASCII code page in printer | Send 1B 74 10 at start of job (WPC1252) |
| Zebra label prints but data shifted / clipped | ^FO coordinates exceed label width | Match ^FO X to printer DPI * label width inches |
| Print job is duplicated | TSEND_C is called twice for one REQ edge (rising edge detection is wrong) | Latch REQ with a one-shot FP edge detector |
| Connection works once, then never again until power cycle | CONT = FALSE and TDISCON was not called | Either set CONT = TRUE or call TDISCON and let TCON re-establish |
For a deeper catalog of error codes, see the official S7-1200 system manual on Siemens SiePortal or run a search for S7-1200 Zebra printer at SiePortal S7-1200 printer integration.
Which S7-1200 firmware version is required for printer TCP/IP communication?
Firmware V4.2 or higher is required for the TCON_IP_v4 UDT and stable TSEND_C / TRCV_C behavior. V4.4 or higher is recommended because it provides additional Open User Communication connection resources and an improved parameter assignment error reporting. The TSEND_C and TRCV_C blocks are FB186 and FB187 version 3.0 in TIA Portal V17/V18.
Can an S7-1200 on a CPU 1211C connect to a network printer?
Yes, but a CPU 1211C only has 3 Open User Communication resources on firmware V4.4, so the connection should be opened only when needed and closed with TDISCON (FB 188) right after the print job to free the resource for HMI/PG communication. If the printer is used every cycle, a CPU 1214C with 8 OUC resources is the better choice.
Why does my Kyocera ECOSYS printer print correctly from a PC but not from the PLC?
The PC test harness usually sends CR+LF and a form feed at the end of the text. The S7-1200 STRING type only contains the printable characters; the trailing line terminator must be appended explicitly with the SCL string literal '$R$L', and the form feed with '$0C'. Without the form feed, the last lines stay in the printer buffer and the sheet is not ejected.
What is the difference between port 9100 and port 9101 on a network printer?
Port 9100 is the standard RAW/HP JetDirect socket. The PLC sends a single, unframed byte stream; the printer prints it as soon as the data is received. Port 9101 is rare on office printers and is often used as a secondary RAW port. Port 9102 and 9103 are sometimes used for status notifications. For all Kyocera, HP, Brother, Epson, and Zebra printers covered here, use 9100.
How do I print a ZPL label from the PLC without loading the ZPL syntax in the source code?
Store the ZPL template in a STRING constant DB and concatenate the variable data into the ^FD field at runtime. The example in this article shows a static header (^FO50,30^A0N,40,40^FDALARM REPORT^FS) combined with dynamic ^FD blocks. For high-frequency prints, keep the template in a single STRING[254] and update the dynamic fields in place to avoid rebuilding the string on every cycle.