← 博客
技术2026-09-1449 次阅读

MES 对接 Zebra 打印机实战:ZPL 标签打印踩坑记录

# MES# Zebra# 标签打印# ZPL# C## 制造业IT

背景:MES 出货环节的打印难题

我们厂区的出货标签打印机全是 Zebra 系列。最初 MES 对接打印走的是厂商商业中间件,标签模板锁死,改一个条码规则要等厂商排期两周。后来我直接研究了 ZPL(Zebra Programming Language),发现标签打印本质上就是往打印机 9100 端口发一段文本指令——很多"高深"的对接方案,其实一层窗户纸。

这篇文章记录我们用 .NET 直连 Zebra 打印机替代商业中间件的全过程,重点讲中文、二维码和耗材尺寸这几个必踩的坑。

解决思路:绕过驱动,直发 ZPL

Zebra 网络打印机监听 TCP 9100 端口,发过去的字节流会被当作打印指令直接执行。这意味着我们不需要安装驱动、不需要打印服务、更不需要中间件——MES 后端拿到标签数据,拼一段 ZPL,直接 Socket 发过去即可。

  • 优点:零驱动部署、响应快(毫秒级)、模板完全代码化可版本管理;
  • 缺点:ZPL 语法有学习成本,坐标定位全靠 ^FO x,y 手算,改版式要重新调坐标。

实现步骤:从拼接 ZPL 到发送

一张典型的出货标签包含品名、条码和二维码,ZPL 大致长这样:

^XA
^PW609
^LL406
^FO30,30^A0N,36,36^FDHard Disk Drive 2.5"SATA^FS
^FO30,90^BY2,3,120^BCN,120,Y,N,N^FD123456789012^FS
^FO440,90^BQN,2,6^FDLA,SN:A1B2C3D4E5^FS
^XZ

关键指令:^PW 定标签宽度(点数)、^LL 定高度、^A0N 设字号、^BCN 画 Code128、^BQN 画二维码、每段内容以 ^FS 结尾、^XA...^XZ 包裹整张标签。C# 侧发送只需要十几行:

using var client = new TcpClient(printerIp, 9100);
var data = Encoding.UTF8.GetBytes(zplCommand);
await client.GetStream().WriteAsync(data);
await client.GetStream().FlushAsync();

上线前先别急着连产线:把 ZPL 存成 .zpl 文本文件,拖进浏览器访问 labelary.com/viewer.html 在线预览渲染效果,坐标调好再真机验证,能省一半调试时间。

踩坑记录:三个血泪坑

  • 坑一:中文全是乱码或空白。直接发 UTF-8 中文,打印机按默认字符集解码,出来一堆问号。解法是在 ZPL 开头加 ^CI28 声明 UTF-8 编码,同时确认打印机固件里有对应中文字体(Swiss 721 不含中文,需机器内置 GB 字体或下载字体文件到打印机)。我们第一批标签就是在这里翻车的。
  • 坑二:二维码扫不出来。^BQN 的放大倍数给小了,打印出来二维码点阵太密,扫码枪距离稍远就识别失败。经验值:二维码模块尺寸至少 4~6 倍放大,且 ^FD 内容前要带模式前缀(如 LA,),漏了前缀整段数据都打不出来。
  • 坑三:标签走位越打越偏。换了不同供应商的标签纸后没有重新校准,打印内容逐张上移。Zebra 打印机要执行一次介质校准(长按走纸键或发 ~JC 指令),让它重新识别纸与纸间隙。这个坑排查了一下午,最后发现和程序毫无关系——教训是先查硬件再看代码。

总结

直发 ZPL 方案上线后,出货打印链路去掉了商业中间件,模板改动从"等厂商两周"变成"改代码十分钟"。给同行三条建议:

  • 对接打印机前先用 Labelary 在线预览调版式,不要拿真纸试错;
  • 中文问题优先查 ^CI28 和打印机字体,这是 90% 乱码的根源;
  • 把 ZPL 模板做成参数化代码(品名、条码、批次作为占位符),入库到 Git,变更可追溯——标签版式本质上是质量文件,出了客诉要能还原当天打了什么。

评论 (0)