简介:这份PDF教程面向使用西门子S7-1200 PLC的自动化工程师与设备调试人员,解决通过以太网TCP通信控制霍尼韦尔或斑马标签打印机的实际问题。内容围绕霍尼韦尔PX240S等带网口打印机的参数设置展开,包括将指令语言切换为ZSim以兼容斑马ZPL-II指令、配置打印机IP与通信端口(需小于5000,避开默认9000+)、借助Zebra Designer设计标签并导出ZPL指令码,以及在博图环境中使用TSEND_C指令完成连接建立与数据发送。打印程序部分对比了单字符与string字符串两种发送方式,并给出数据存储DB去优化访问、中间转存DB存放不同标签格式指令、通过触摸屏选择格式代号等实现思路,还涉及编码位数修改后的程序调整。资源为1个PDF文件,约721KB,已有1648人学习,适合需要快速打通PLC与打印机通信链路的读者参考。
1. 西门子 PLC 走 TCP 控制标签打印机:从 IP 配置到 ZPL 指令落地的完整链路
车间里经常遇到这种需求:产线末端一台标签打印机,要跟着 PLC 的节拍实时打码,编码还得随工单动态变。很多人第一反应是找打印机厂商的驱动或中间件,结果发现西门子 1200/1500 的以太网口跟打印机根本对不上话。其实这条路是通的——只要打印机带以太网口、支持 ZPL-II 指令集,用博图的 TSEND_C 指令直接发字符串就能打。这篇笔记拆的就是这条链路:霍尼韦尔 PX240S 这类工业打印机怎么把指令语言切到 ZSim、端口号为什么要从默认的 9000 改到 5000 以下、博图里 TSEND_C 的连接参数怎么填、ZPL 指令码怎么从 Zebra Designer 里导出来塞进 DB 块。适合手里有 1200/1500 PLC、需要做动态标签打印的电气和自动化从业者,新手照着步骤能跑通,熟手可以重点看端口和寻址那几个坑。
2. 硬件接线与打印机侧配置:端口号不改,后面全白搭
2.1 为什么必须走 ZSim 指令语言
霍尼韦尔 PX240S 出厂默认的指令语言是它自家的体系,跟斑马打印机的 ZPL-II 不兼容。而博图这边能发出去的就是裸字符串,没有驱动层做协议转换,所以打印机必须能直接“听懂”ZPL-II。PX240S 在系统设置里提供了一个 ZSim 模式,本质上是把指令解析器切换成兼容 ZPL-II 的引擎。这一步不做,后面 PLC 发什么都是乱码或者直接不响应。
操作路径是:触摸屏进入系统设置 → 常规 → 命令语言 → 选择 ZSim。选完退出时会问是否保存,必须选“是”,否则重启后回到默认语言。这个设置只影响指令解析层,不影响打印机的网络协议栈,所以改完不需要重启网络。
2.2 以太网参数与端口号的硬约束
打印机通过网线直连电脑或接入同一交换机,浏览器输入打印机 IP 进入 Web 配置页。测试环境里打印机 IP 设为 192.168.2.88,这个地址要和 PLC 的以太网口在同一网段,或者经过路由可达。重点在端口号:西门子以太网通信的本地端口范围是 0–5000,而打印机默认的 RAW 打印端口通常是 9000 以上。两边对不上,TCP 连接根本建不起来。
在打印机 Web 页的通信配置里,把端口号改成小于 5000 的值,比如 9100 不行就改 3000 或 2000。改完保存,打印机侧就准备好了。这里有个细节:改端口号后,如果之前电脑上装过打印机驱动,驱动里的端口配置也要同步改,否则电脑测试打印会失败,但 PLC 通信不受影响。
提示:端口号改完后,先用电脑的 telnet 或网络调试助手测一下能不能连上,确认打印机在监听新端口,再往下做 PLC 组态。
2.3 用 Zebra Designer 生成 ZPL-II 指令码
标签的排版和编码规则不在博图里做,而是用 Zebra Designer 2 或 Zebra Designer PRO 设计好标签,然后导出成 ZPL-II 指令文本。设计时注意几点:编码选择固定式,字体和大小按客户要求调,条码类型和位置在画布上拖好。设计完成后点打印,但不要真的打到打印机上,而是勾选“打印到文件”,生成一个 .prn 或 .txt 文件。
用记事本打开这个文件,里面就是完整的 ZPL-II 指令码。典型结构长这样:
^XA ^FO50,50^A0N,40,40^FD{{CODE}}^FS ^FO50,120^BY3^BCN,100,Y,N,N^FD{{CODE}}^FS ^XZ^XA和^XZ是标签的开始和结束,^FO定位,^A设字体,^FD是数据字段,^BC是条码。实际导出的指令里,数据字段是写死的示例值,需要把那个位置替换成 PLC 要动态写入的变量占位。常见做法是先把整段指令存进 DB 块,运行时用 STL 或 SCL 把占位符替换成实际编码,再发给打印机。
2.4 硬件清单与连接确认
整套链路需要的硬件不多:一台带以太网口的西门子 1200 或 1500 PLC、一台支持 ZSim 的霍尼韦尔 PX240S(或其他兼容 ZPL-II 的机型)、一根标准网线、一台用于配置的电脑。软件侧是博图 TIA Portal(版本不限,TSEND_C 指令在 V13 以上都有)、Zebra Designer、以及一个网络调试助手用来验证端口。
接线顺序建议:先给打印机上电,网线连电脑,配好 IP 和端口,用浏览器确认 Web 页能打开;然后电脑上用调试助手连打印机的 IP 和端口,手动发一段 ZPL 指令,确认能打出一张标签;最后再把 PLC 接进来。这个顺序能避免 PLC 侧调了半天发现是打印机端口没改。
3. 博图 TSEND_C 组态:连接参数与状态码解读
3.1 TSEND_C 指令的引脚含义
博图里做 TCP 客户端发送,最顺手的是 TSEND_C。它一个指令包了建立连接、发送数据、断开连接三件事,不用像老式 CP 模块那样分开调。指令的引脚不多,但每个都关键:
| 引脚 | 含义 | 典型填法 |
|---|---|---|
| REQ | 上升沿触发发送 | 用一个按钮或周期脉冲 |
| CONT | 是否保持连接 | 填 1,保持长连接 |
| CONNECT | 连接参数 | 指向一个 TCON_IP_v4 结构 |
| DATA | 要发送的数据 | 指向 DB 块中的字符串 |
| DONE | 发送完成 | 接一个变量观察 |
| ERROR | 错误标志 | 接一个变量观察 |
| STATUS | 状态码 | 接一个 Word 变量 |
CONT 填 1 表示连接建立后不主动断开,适合连续打码的场景。如果每次打码间隔很长,也可以填 0,让指令每次发送完自动断开,下次 REQ 来了再重连,但重连有延迟,节拍紧的产线不建议。
3.2 CONNECT 参数的填法
CONNECT 引脚需要指向一个 TCON_IP_v4 类型的结构体,通常在 DB 块里定义。关键字段是:
- InterfaceId:PLC 以太网口的硬件标识符,在设备组态里能看到,一般是 64 或 65 这样的数字。
- ID:连接 ID,自己编一个,比如 1。
- ConnectionType:填 16#0B 表示 TCP。
- ActiveEstablished:填 1 表示主动建立连接(PLC 做客户端)。
- RemoteAddress:打印机的 IP,比如 192.168.2.88。
- RemotePort:打印机改过的端口号,比如 3000。
- LocalPort:本地端口,填 0 让系统自动分配即可。
这些参数在博图的指令配置向导里可以直接填,填完自动生成 CONNECT 结构。注意 RemotePort 必须和打印机 Web 页里设的一致,差一个数字都连不上。
3.3 状态码 7004 和常见错误码
TSEND_C 的 STATUS 引脚输出的是十六进制状态码。连接建立成功后,状态码会变成 7004,含义是“连接已建立,等待发送作业”。这时候 REQ 来一个上升沿,数据就发出去了。
常见的错误码和排查方向:
- 7002:连接正在建立中,等一会儿再看。
- 7003:连接已断开,检查 CONT 是否被置 0 或网络断了。
- 8085:远程地址或端口不对,重点查 RemotePort 和打印机实际端口。
- 8087:连接被对方拒绝,通常是打印机端口没在监听,或者端口号超了 5000 范围。
- 8090:InterfaceId 填错,回设备组态里核对硬件标识符。
注意:状态码是十六进制显示的,博图里如果变量定义成 Word,看到的是 16#7004 这种格式。别把它当成十进制数去查手册。
3.4 发送数据的组织方式
DATA 引脚指向的 DB 块里存的是要发的字符串。这里有个选择:用 char 数组还是 string。char 数组的优势是每个字符独立寻址,改编码时直接按索引改就行,缺点是写入时要逐个字符赋值,代码冗长。string 的优势是整体赋值方便,但寻址时要用中间变量转换。
测试里用的是 string 变量,配合一个中间转存 DB。具体做法是:建一个 DB 块,里面放一个 String 类型的变量,长度按最长 ZPL 指令估,一般 200 字节够用。再建一个中间 DB,存不同标签格式的 ZPL 模板。运行时根据触摸屏选的格式代号,把对应模板拷到发送 DB,再替换占位符。
关键点:DB 块必须去掉“优化的块访问”属性。在 DB 属性里取消勾选“优化的块访问”,这样变量才有绝对地址,才能用指针或间接寻址去改字符串里的某一段。不去优化,后面想动态改编码位数会非常麻烦。
4. 打印程序编写:DB 块设计与编码动态替换
4.1 数据块的结构规划
整个打印程序涉及三个 DB 块:模板库 DB、发送缓冲 DB、以及一个控制参数 DB。模板库 DB 里按格式代号存多段 ZPL 指令,每段是一个 String,比如 Format_1 到 Format_10。发送缓冲 DB 里就一个 String,长度取模板里最长的那个。控制参数 DB 存当前选中的格式代号、当前编码值、以及一个发送触发位。
模板库 DB 的结构可以这样定义:
-- 在博图 DB 编辑器里定义 Format_1 : String[200]; -- 标签格式1的ZPL模板 Format_2 : String[200]; -- 标签格式2的ZPL模板 Format_3 : String[200]; -- 标签格式3的ZPL模板 CurrentFormat : Int; -- 当前选中的格式代号 CurrentCode : String[20];-- 当前要打印的编码 SendTrigger : Bool; -- 发送触发每个模板里的 ZPL 指令,把数据字段的位置留成占位符,比如^FD@@@@@@@@@^FS,其中 @ 的个数对应编码位数。运行时用 REPLACE 指令把 @ 替换成 CurrentCode。
4.2 用 SCL 做占位符替换
替换逻辑用 SCL 写最清晰。下面这段代码把模板里的占位符替换成实际编码,然后拷到发送缓冲:
// 假设模板存在 "TemplateDB".Format_1,发送缓冲在 "SendDB".Buffer // CurrentCode 是当前编码,比如 "123456789" #tempTemplate := "TemplateDB".Format_1; // 取出模板 #pos := FIND(IN1 := #tempTemplate, IN2 := '@@@@@@@@@'); // 找占位符位置 IF #pos > 0 THEN #tempResult := DELETE(IN := #tempTemplate, L := 9, P := #pos); // 删掉占位符 #tempResult := INSERT(IN1 := #tempResult, IN2 := "TemplateDB".CurrentCode, P := #pos); // 插入实际编码 "SendDB".Buffer := #tempResult; // 写入发送缓冲 END_IF;这段代码的逻辑是:先找到占位符在模板里的起始位置,把 9 个 @ 删掉,再在同样的位置插入当前编码。编码位数变了,就把 L 的参数从 9 改成对应的位数,同时模板里的 @ 个数也要同步改。这就是为什么前面强调编码位数更改后程序要跟着改——占位符长度和删除长度必须匹配。
4.3 编码生成与唯一性保证
测试里编码是用简单累加生成的,每个打印周期加一。实际产线上,编码往往来自 MES 或工单系统,PLC 只负责接收和转发。如果 PLC 自己生成,要保证唯一性,常见做法是用日期时间加流水号拼接,比如YYMMDD+HHMMSS+0001。累加计数在断电后会丢失,需要配合保持性存储区或者把当前值写到 MES。
触摸屏上可以做一个格式选择控件,把格式代号写到 CurrentFormat,然后程序根据代号从模板库 DB 里取对应的模板。这样一条产线切换不同客户或不同标签时,不用改程序,只改触摸屏选项就行。
4.4 发送时序与触发逻辑
TSEND_C 的 REQ 需要一个上升沿。如果直接用 SendTrigger 的常开触点,每次置位都会触发一次发送,但连续发送时要在 DONE 之后才能再次触发。稳妥的做法是用一个周期脉冲,比如 1 秒的时钟存储器位,配合一个“允许发送”标志。当 DONE 为 1 且 SendTrigger 为 1 时,下一个时钟上升沿触发 REQ,发送完成后 DONE 复位,等待下一次。
如果产线节拍很快,比如每 2 秒打一张,那发送和打印的时间要算进去。ZPL 指令发出去后,打印机解析和走纸需要时间,PLC 这边不能连续发,否则打印机会缓冲溢出或丢标签。一般建议在 DONE 之后延时 200–500ms 再允许下一次发送,具体看打印机型号和标签复杂度。
5. 避坑与排查:端口、寻址、指令格式的五个血泪经验
5.1 端口号超范围导致连接被拒
现象:TSEND_C 的 STATUS 报 8087,连接建立不起来,但电脑用调试助手能连上打印机。
原因:打印机默认端口 9100,超过了西门子以太网通信的本地端口上限 5000。PLC 侧发起连接时,本地端口和远程端口都要在 0–5000 范围内,远程端口超了就直接被协议栈拒绝。
解决:进打印机 Web 配置页,把 RAW 打印端口改成 3000 或 2000,保存后重新用电脑验证端口能通,再回博图改 CONNECT 里的 RemotePort。
5.2 DB 块没去优化导致间接寻址失败
现象:程序编译不报错,但运行时改编码没效果,打印出来的还是模板里的占位符。
原因:DB 块默认是“优化的块访问”,变量没有绝对地址,用指针或间接寻址去改字符串时找不到目标地址。
解决:在 DB 属性里取消勾选“优化的块访问”,重新编译下载。注意取消后 DB 的偏移量会变,如果程序里用了绝对地址,要同步更新。
5.3 ZPL 指令里的占位符长度和替换长度不匹配
现象:打印出来的编码少几位或者多出乱码。
原因:模板里写了 9 个 @,但替换时 DELETE 的 L 参数填了 10,或者编码实际只有 8 位但按 9 位处理。
解决:模板里的 @ 个数、DELETE 的 L 参数、INSERT 的编码长度三者必须一致。编码位数变更时,三个地方同步改。建议在触摸屏上做一个编码位数设置项,程序里用变量控制 L 参数,避免硬编码。
5.4 打印机指令语言没保存导致重启后失效
现象:配置完 ZSim 后测试正常,打印机断电重启后又不认 ZPL 指令了。
原因:退出设置界面时选了“否”或者直接断电,配置没写入非易失存储。
解决:每次改完命令语言,退出时确认选“是”保存,然后正常重启一次打印机,再测试。如果还是丢,检查打印机固件版本,老固件可能有保存 bug,需要升级。
5.5 发送频率过高导致标签丢失
现象:连续打码时,中间偶尔少一张标签,PLC 侧 DONE 正常触发但打印机没出纸。
原因:ZPL 指令发得太快,打印机缓冲来不及处理,或者 TCP 缓冲区堆积导致部分数据被覆盖。
解决:在 DONE 之后加延时,用 TON 定时器延时 300ms 再允许下一次发送。如果节拍实在紧,可以把多张标签的 ZPL 指令拼成一个包发,打印机解析完一个 ^XZ 再解析下一个,但这样中间不能有丢包。
6. 进阶技巧:用 STL 指针直接改字符串里的编码段
前面用 SCL 的 FIND/DELETE/INSERT 做替换,逻辑清晰但执行效率一般,尤其是模板多、编码长的时候。如果产线节拍紧,可以用 STL 的指针直接定位到字符串里的数据段,原地改写,省去删除和插入的开销。
思路是:ZPL 模板里数据字段的位置是固定的,比如^FD后面跟 9 个字符,那这 9 个字符在字符串里的偏移量就是固定的。用 STL 的+AR1或+AR2把地址指针移到那个位置,然后逐个字节写入新编码。下面是一个示例片段:
// 假设发送缓冲在 DB100,字符串从 DB100.DBB0 开始 // 数据字段在字符串内的偏移量为 20(需根据实际模板计算) L P#DBX 0.0 // 加载DB100的起始地址 +AR1 P#20.0 // 指针移到偏移20 L "CodeDB".CodeByte1 // 加载编码第1字节 T B [AR1,P#0.0] // 写入 L "CodeDB".CodeByte2 T B [AR1,P#1.0] // ... 依次写入后续字节这段代码的前提是:模板里数据字段的偏移量已经算好,且编码位数固定。如果编码位数可变,指针偏移量也要动态计算,复杂度会上升。我一般会在模板设计阶段就把数据字段放在固定偏移,比如字符串的第 20 字节开始,这样程序里直接写死偏移量,改编码时只改数据源,不动指针。
验证方法:先用电脑的调试助手连打印机,手动发一段带实际编码的 ZPL 指令,确认能打出正确标签。然后把同样的指令码填进模板 DB,用 PLC 发一次,对比打印结果。如果电脑能打、PLC 不能打,重点查 DB 块的字符串长度和发送缓冲的 DATA 引脚指向是否正确。如果两边都打不出来,回打印机 Web 页确认端口和指令语言。
从那以后我每次做这种 TCP 打印项目,都会先在电脑上用调试助手把 ZPL 指令跑通,再动博图。这个习惯帮我省了至少三次在 PLC 侧瞎调的时间。希望帮到你。
本文还有配套的精品资源,点击获取