Overview
This technical reference covers the complete integration of a Zebra ZT411 industrial label printer (model ZT41142-T4E0000Z) with a Siemens SIMATIC S7-1500 CPU programmed in TIA Portal V16. The link between the PLC and the printer is built on standard TCP/IP socket communication (Open User Communication, OUC), which the S7-1500 supports natively without any additional CP or software.
The integration solves four concrete engineering problems reported in the field:
- Triggering a print job from the PLC (cycle start, button on HMI, completion signal of a machine step).
- Embedding dynamic data into the printed label (part number, batch ID, date, time, operator).
- Receiving the printer status back into the PLC (online/offline, error, ribbon out, head open).
- Reading the printer clock or supplying date/time when the ZT411 internal RTC drifts.
The driver stack in the ZT411 is Zebra's PrintServer II / ZebraNet which exposes a raw TCP socket on port 9100 (default). Any ASCII string sent to this socket that conforms to ZPL II is executed as a print job. No proprietary Siemens block is required; only the standard OUC instructions TCON, TDISCON, TSEND_C and TRCV_C from the TIA Portal basic instructions library.
T4E0000Z decodes as Thermal print technology, 4-inch print width, 203 dpi (also available as 300 dpi in the ZT411 family), internal ZebraNet 10/100 Ethernet PrintServer II with wired Ethernet on the standard 9100 socket. No additional PrintServer card is required for TCP/IP.System Architecture and Prerequisites
Hardware List
| Component | Specification |
|---|---|
| PLC | S7-1500 CPU (any firmware variant compatible with TIA V16, e.g. CPU 1511-1 PN / CPU 1515-2 PN / CPU 1516-3 PN/DP) |
| Firmware | CPU firmware V2.6 or higher (required for full TSEND_C/TRCV_C function set in V16) |
| Engineering station | SIMATIC Field PG or PC with TIA Portal V16 Update 6 or higher |
| Printer | Zebra ZT41142-T4E0000Z with ZebraNet wired Ethernet enabled |
| Network | Managed or unmanaged 100 Mbit switch, Cat5e/Cat6 cabling, IP subnet shared by PLC and printer |
Software Prerequisites
- TIA Portal V16 (with HSP 0263 or later if using a recent CPU).
- S7-1500 CPU firmware V2.6 or newer loaded on the target PLC.
- Optional: ZebraDesigner 3 or Zebra Setup Utilities for offline label layout generation and ZPL string export.
- ZPL II Programming Guide (Volume I and II) from Zebra for command reference.
IP Addressing Plan
Use a private subnet dedicated to the printer network. A typical layout:
| Device | IP Address | Subnet | Port |
|---|---|---|---|
| S7-1500 PN interface (X1) | 192.168.0.3 | 255.255.255.0 | 2000 (local OUC port) |
| Zebra ZT411 | 192.168.0.8 | 255.255.255.0 | 9100 |
195.168.0.x, which is not a valid RFC1918 private range. Use 192.168.0.x as documented above. The ZT411 must be reconfigured to 192.168.0.8 through the front panel (Menu > Networks > IP Address) or via Zebra Setup Utilities over USB.Zebra ZT411 Network Configuration
- Power on the ZT411 and open the front LCD panel.
- Navigate to Menu → Networks → Wired IP.
- Set the IP address to
192.168.0.8, subnet mask255.255.255.0, gateway192.168.0.1. - Navigate to Menu → Networks → Print Server → Port 9100 and confirm the raw socket is enabled.
- Set the active print language to ZPL via Menu → Settings → Print Language (do not leave it on hybrid).
- Print a configuration label: hold the Feed key while powering on, or use Menu → Settings → Print Info. Confirm the IP is shown on the test label.
- Ping the printer from a Windows command prompt:
ping 192.168.0.8. A successful reply confirms the Ethernet stack.
Detailed firmware and driver downloads for the ZT411 family are available on the Zebra ZT411 support and downloads page.
TIA Portal V16 Project Configuration
Adding the S7-1500 Station
Open TIA Portal V16 and create a new project. Add a SIMATIC S7-1500 station that matches the physical CPU. Open the device configuration, set the PROFINET interface X1 IP address to 192.168.0.3 with subnet 255.255.255.0. Compile and download the hardware configuration.
Adding the Printer to the Network Topology (Optional)
Strictly speaking the ZT411 is not added to the device configuration as a slave because it is not a PROFINET device; it is a pure TCP/IP terminal on the same subnet. However, TIA Portal V16 allows you to drop an unspecified Ethernet node on the network view for documentation purposes. The OUC connection is configured entirely in the user program, not in the hardware configuration.
Adding the Connection DB
Insert a new global DB called dbZebraConnection. It must contain a TCON_IP_V4 structure (system data type). The minimum fields to populate:
| Field | Symbol / Tag | Value |
|---|---|---|
| InterfaceId | LocalPLCInterface | 64#00000001 (PN interface X1, hex, per system constant for the local PROFINET interface) |
| ID | ConnectionId | 1 (must match the ID input on TSEND_C / TRCV_C / TCON / TDISCON) |
| ConnectionType | ConnectionType | 16#0B (TCP/IP, see TIA help on TCON_IP_V4) |
| ActiveEstablished | ActiveEstablished | TRUE (PLC is the active partner) |
| RemoteAddress | RemoteAddress | ARRAY[0..3] OF BYTE = 192,168,0,8 |
| RemotePort | RemotePort | UINT = 9100 |
| LocalPort | LocalPort | UINT = 2000 (any unused local port) |
| LocalAddress | LocalAddress | ARRAY[0..3] OF BYTE = 192,168,0,3 |
Reference the system constants for the local PROFINET interface ID via System constants → <CPU> → Local Interface → Local PROFINET interface.
Adding the Print String DB
Create a second global DB called dbPrintstring with a STRING[1024] tag called Printstring plus separate STRING tags for each dynamic field (sPartNumber, sBatchID, sDate, sTime, sOperator). The maximum ZPL II script length for a single label is well below 1024 bytes; the S7-1500 string type has a max length of 254 characters per default STRING, so size it to STRING[1024] or use an ARRAY OF BYTE for safety.
PLC Program: Connection, Send and Receive Blocks
Block Selection
For a single TCP partner the combined instruction TSEND_C and TRCV_C is the cleanest approach because they handle the TCON / TDISCON state machine internally. The legacy TCON + TSEND + TRCV triplet is recommended only when you need fine-grained control over connection lifecycle (e.g., scheduled re-establishment after a line stop).
Pattern: Single FB fbZebraPrint
Place the OUC blocks in an SCL Function Block. The following pattern covers print trigger, status request, and reset of the connection.
// SCL - fbZebraPrint instance DB
REGION Connection and I/O
// TSEND_C: send a ZPL script on demand
#tsendPrinter(
REQ := #i_bPrintTrigger AND #bPrinterOnline,
CONT := TRUE,
LEN := INT_TO_UINT(LEN(#dbPrintstring.Printstring)),
CONNECT := "dbZebraConnection".TCON_IP_V4,
DATA := #dbPrintstring.Printstring,
COM_RST := #bComReset,
DONE => #bSendDone,
BUSY => #bSendBusy,
ERROR => #bSendError,
STATUS => #wSendStatus);
// TRCV_C: receive the printer response (ZPL status / ~HS answer)
#trcvPrinter(
EN_R := TRUE,
CONT := TRUE,
LEN := 0, // 0 = take all data received
CONNECT := "dbZebraConnection".TCON_IP_V4,
DATA := #stRecvBuffer,
COM_RST := #bComReset,
VALID => #bRecvValid,
BUSY => #bRecvBusy,
ERROR => #bRecvError,
STATUS => #wRecvStatus,
LEN => #iRecvLen);
END_REGION
STATUS output of TSEND_C / TRCV_C follows the pattern 0x_xy where the lower byte indicates the local bus state and the upper byte the partner state. A common success code after a print is 16#0001 (DONE after one cycle) or 16#7000 (BUSY no error). A persistently reported 16#80C1 indicates the connection has been aborted by the partner - the ZT411 closes the socket after each print job, which the next TSEND_C handles by automatically re-establishing.ZPL II Command Reference for the ZT411
The ZT411 interprets Zebra Programming Language II (ZPL II). A complete label is a single ASCII stream terminated by ^XZ. The minimum useful print job looks like:
^XA
^FO50,50^A0N,40,40^FDHello ZT411^FS
^XZ
The command structure is ^<letter> for format commands, ~<letter> for immediate-action commands, and ^FD<data>^FS for field data delimited by ^FS. Below are the commands used most often on the S7-1500 line.
| Command | Function | Notes |
|---|---|---|
^XA |
Start of label format | Always begin a job with this |
^FO x,y |
Field origin in dots (203 dpi: 1 dot = 0.125 mm) | Positions subsequent fields |
^A0N,h,w |
Built-in font, normal, height h, width w in dots | Use ^A0N,40,40 for a 4 mm font at 203 dpi |
^FD<text>^FS |
Field data block | Carries the actual label content |
^BCN,,Y,N |
Code 128 barcode | Follow with ^FD<value>^FS
|
^BY3 |
Default bar width for barcode | Must precede barcode command |
^BCN,80,Y,N |
Code 128 with height 80 dots, human-readable printout | Common for shipping labels |
^XZ |
End of label / print | The ZT411 prints as soon as ^XZ is received |
~HS |
Return host status string (ZPL II) | Sent alone, returns multi-line status block |
^PRp,s |
Print rate (speed) p inches/sec, slew s | Use ^PR4 for 4 ips |
^MMT |
Set media type to thermal transfer (ribbon) | Use ^MMK for direct thermal |
^MDn |
Set darkness n (0-30) | Increase if printing is too light |
~TA |
Test print / form feed | Handy for ribbon calibration |
Printer Status Request (~HS)
To read the printer state, send only ~HS as a one-byte-per-line job:
~HS
The ZT411 replies with a multi-line ASCII block on the same TCP socket. Typical response:
PRINTER STATUS
ERRORS:
WARNING:
IDLE
Other valid values inside the response are PRINT HEAD OPEN, MEDIA OUT, RIBBON OUT, PAUSE, HEAD TOO HOT, HEAD COLD. Parse this string in the PLC to drive an HMI status display.
Embedding the Printer Clock
ZPL II can insert the printer's internal RTC into a field. The format is set by ^CF / ^CT:
^XA
^FO50,50^A0N,30,30^FDDate: ^FSD ^FS
^FO50,90^A0N,30,30^FDTime: ^FST ^FS
^XZ
Where ^FSD writes the configured date format and ^FST writes the configured time format. Configure both via ^CDF:YYYY-MM-DD and ^CTF:HH:MM:SS.
^FSD / ^FST. Instead format the date/time string in the S7-1500 using the CPU's DTL data and inject it as plain ^FD content. This removes the dependency on the printer clock entirely and guarantees the timestamp matches the machine cycle time.Building Dynamic Print Strings in SCL
The original Siemens example uses VAL_STRG to convert integers to formatted strings. A cleaner, locale-independent approach is to use the DTL to STRING conversion plus concatenation of ZPL fragments.
Sample FB: fbBuildPrintstring
// SCL - build a ZPL II label with PLC-side date/time
FUNCTION_BLOCK "fbBuildPrintstring"
VAR
#i_dtLocalTime : DTL; // connect to CPU RD_SYS_T (returns DTL)
END_VAR
BEGIN
// ZPL header
#dbPrintstring.Printstring := '';
Concat := CONCAT(IN1 := #dbPrintstring.Printstring,
IN2 := '^XA^FO50,50^A0N,40,40^FDPN: ');
Concat := CONCAT(IN1 := Concat, IN2 := #sPartNumber);
Concat := CONCAT(IN1 := Concat, IN2 := '^FS');
// Date line, formatted in PLC
Concat := CONCAT(IN1 := Concat,
IN2 := '^FO50,110^A0N,30,30^FDDate: ');
Concat := CONCAT(IN1 := Concat, IN2 := DTL_TO_STRING(#i_dtLocalTime));
Concat := CONCAT(IN1 := Concat, IN2 := '^FS');
// Code 128 with serial number from PLC tag
Concat := CONCAT(IN1 := Concat,
IN2 := '^FO50,170^BY3^BCN,80,Y,N');
Concat := CONCAT(IN1 := Concat, IN2 := '^FD');
Concat := CONCAT(IN1 := Concat, IN2 := #sSerialNumber);
Concat := CONCAT(IN1 := Concat, IN2 := '^FS');
// End of label / print trigger
Concat := CONCAT(IN1 := Concat, IN2 := '^XZ');
#dbPrintstring.Printstring := Concat;
END_FUNCTION_BLOCK
If DTL_TO_STRING yields the locale-dependent form 2026-01-15-13:45:22, strip the dashes and colons with REPLACE if you want a flat format such as 20260115 134522.
Manual Integer-to-String Formatting (matches the field-tested example)
// Day as two-digit decimal
VAL_STRG(IN := UINT_TO_INT(#i_dtLocalTime.DAY),
SIZE := 2,
PREC := 0,
WIDTH := 0,
P := 1,
OUT => #sDay);
#dbPrintstring.Printstring[LEN := ...].dateField := #sDay;
The VAL_STRG instruction pads with leading blanks if WIDTH is 0; set WIDTH > 0 to pad with leading zeros on positive values.
Status Polling and Parsing
The ZT411 closes the TCP socket after each command. The PLC must handle this gracefully; TSEND_C / TRCV_C do this automatically because CONT := TRUE keeps the connection state alive across sends.
Recommended Polling Cycle
- Every 2 seconds, send
~HSas a separate OUC job on the same connection. - Wait for
VALID := TRUEonTRCV_C. - Search the receive buffer for the keywords
PRINTER STATUS,IDLE,PAUSE,HEAD OPEN,MEDIA OUT,RIBBON OUT. - Drive Boolean tags (
bPrinterReady,bPrinterError,bHeadOpen) based on the keyword matches. - Display the raw buffer on HMI for diagnostics.
Receive Buffer Sizing
The ZT411 ~HS response is under 200 bytes. A STRING[512] receive buffer is sufficient. Avoid LEN := 0 on TRCV_C if you want a hard cap; set LEN := 512 to fix the maximum block size and prevent buffer overruns if the printer firmware produces a larger response.
Complete Working Cycle (Step-by-Step)
-
Compile and download the hardware configuration. Confirm
192.168.0.3is reachable from the engineering station. - Configure the ZT411 as described above; print a config label and verify IP.
-
Ping both directions:
ping 192.168.0.8from the engineering station, then trigger a one-shotTSEND_Cfrom the PLC with a known string (e.g.~HS) and confirmDONE := TRUEwith status word16#0001within one cycle. - Enable the connection DB in Properties → Connection → Active connection establishment on PLC side if you are using TCON directly. With TSEND_C, this is implicit.
-
Load the FB block
fbZebraPrintand thefbBuildPrintstringinto the S7-1500 CPU. -
Trigger a print from the PLC by setting
i_bPrintTrigger := TRUEfor one cycle, or use an HMI button wired to the same tag. The label should advance through the printer within 1-2 seconds. -
Verify date/time on the printed label. If blank or wrong, check whether you used
^FSD(depends on printer clock) or a literal^FD<string>^FS(depends on PLC tag). -
Force a fault (open the print head) and confirm the next
~HSpoll returns theHEAD OPENstring. This validates the receive path.
Verification Checklist
| Check | Expected |
|---|---|
| PLC → printer ping | Replies from 192.168.0.8 |
| TSEND_C DONE | TRUE one cycle after REQ |
| TSEND_C STATUS after success | 16#0001 or 16#7000 |
| Printer LCD online indicator | Steady green |
| Triggered label printed | Matches the ZPL template |
| Date on label | Equals PLC RD_SYS_T date (when using PLC-formatted string) |
TRCV_C receives ~HS response |
VALID := TRUE within 2 s |
| Head open status updates on HMI | bHeadOpen := TRUE after opening head |
Troubleshooting Matrix
| Symptom | Likely Cause | Diagnosis | Resolution |
|---|---|---|---|
| TSEND_C STATUS 16#80C1 | Connection aborted by partner | ZT411 closes the socket after each job - normal | Keep CONT := TRUE; next REQ re-establishes |
| TSEND_C STATUS 16#80A1 | Connection could not be established (TCP) | Ping 192.168.0.8 from engineering station | Fix IP/subnet, disable Windows firewall briefly for test |
TRCV_C never receives ~HS reply |
ZPL language not active, or print server in P9100 mode disabled | Send ~HS from a Windows telnet 192.168.0.8 9100 session |
Set ZT411 print language to ZPL; enable P9100 raw socket |
| Printer receives data but does not print | Missing ^XZ or job inside a larger buffer with leading non-ZPL bytes |
Capture a Wireshark trace on the network | Strip any non-ZPL prefix; verify stream ends with CRLF + ^XZ
|
| Date or time is blank on label | Used ^FSD / ^FST but printer clock not set |
Print a config label, look at the RTC | Set clock from front panel, or use PLC-formatted string as shown above |
| Date format wrong | Different ^CDF set on printer |
Send ^CDF:YYYY-MM-DD at the top of every job |
Embed ^CDF and ^CTF lines in the ZPL stream |
| Label prints once, then no further prints | TSEND_C REQ stuck TRUE |
Watch REQ in online mode | Use edge detection: REQ := printTrigger AND NOT printTriggerOld
|
| Label feeds but no image | Print mode is direct thermal, ribbon is loaded | Check ^MT setting |
Add ^MMT at start of ZPL or reconfigure printer |
| Barcode does not scan | Bar width too narrow or quiet zone missing | Inspect label under a scanner | Use ^BY3,2,100 and add 10-dot quiet zone with ^FO
|
| Connection ID conflict | Two OUC blocks share the same ID | Online → OUC diagnostics | Use unique IDs: 1 for TSEND_C, 2 for TRCV_C (or use combined blocks) |
| Compile error: TCON_IP_V4 invalid type | CPU firmware too old for TIA V16 block | Check CPU firmware in online diagnostics | Update CPU firmware to V2.6 or higher |
Performance Notes
- Round-trip time for a single
~HSpoll: typically 50-100 ms on a 100 Mbit subnet. - Print cycle of a 4-inch by 2-inch label at 203 dpi: ~1 s after the ZPL stream is fully sent.
- Maximum ZPL stream throughput: the 9100 socket on the ZT411 does not flow-control well above ~50 KB/s; for very large labels (>20 KB ZPL) split the job or buffer the receive side with a 200 ms TSEND_C spacing.
- PLC program OB1 cycle overhead for one TSEND_C + one TRCV_C: ~0.5 ms; well within the budget of any S7-1500 CPU.
Safety and Operational Notes
COM_RST := TRUE for one cycle to clear the internal state machine of TSEND_C, then release it. Without this reset the S7-1500 OUC block can hold a half-open state.Reference Architecture Diagram
FAQ
Do I need to add the Zebra ZT411 to the TIA Portal hardware configuration?
No. The ZT411 is a pure TCP/IP terminal on the same Ethernet subnet, not a PROFINET or PROFIBUS device. Open User Communication on the S7-1500 establishes the socket at runtime using TCON_IP_V4 inside a connection DB. The hardware configuration only contains the S7-1500 station and its IP address.
Which OUC block should I use: TSEND_C/TRCV_C or TCON + TSEND + TRCV?
Use TSEND_C / TRCV_C for a single printer with no scheduled disconnect. The combined blocks manage the TCON state machine automatically and reduce code volume. Use the TCON / TDISCON / TSEND / TRCV triplet when you need to disconnect on every cycle (e.g., to release the local port) or when two parallel OUC channels share one connection DB.
Why does my printed label show no date or time?
ZPL II has two ways to print a timestamp: the printer clock (^FSD / ^FST) and a literal string (^FD<text>^FS). If the printer clock is unset, ^FSD / ^FST print blank. Build the date/time string in the S7-1500 using RD_SYS_T and DTL_TO_STRING and concatenate it as a plain ^FD value to eliminate the dependency on the ZT411 RTC.
What TCP port does the ZT411 listen on?
Default is port 9100 (raw TCP). The ZT411 also supports ports 9101, 9102 etc., as configured under Menu → Networks → Print Server → Port. Confirm the active port via a configuration label or a successful telnet test from a Windows command prompt.
How do I confirm the printer is online from the PLC?
Send the ZPL command ~HS as a separate TSEND_C job on a 2-second cycle. The ZT411 replies with a multi-line ASCII status block. Parse it on the PLC for keywords such as IDLE, PAUSE, HEAD OPEN, MEDIA OUT, RIBBON OUT. A successful TRCV_C VALID within 2 s also confirms the TCP path is alive.
Where do I find the official ZPL command reference for the ZT411?
The ZPL II Programming Guide (Volumes I and II) is published on the Zebra ZT411 support page. For S7-1500 OUC programming, use the TIA Portal V16 system manual and the S7-1500 Communication Function Manual available from Siemens SiePortal.