简介:面向初次接触 TSC 标签打印机二次开发者的入门级资料包,聚焦 Windows 平台下调用厂商动态库完成标签打印与二维码打印这一常见需求,解决新手在 dll、lib 与头文件配置上反复摸索、函数声明缺失的问题。包内共 8 个文件,涵盖 2 个 lib 静态库、2 个 h 头文件、2 个 dll 动态库,另有 1 个驱动安装程序与 1 份 TSPL 中文文档,分别对应 32 位与 64 位两套调用环境,压缩包整体约 18.89MB。文件已按平台分目录整理,头文件中的接口声明完整,无需自行手写函数原型,复制即可接入工程;配合中文指令手册可查阅 TSPL 指令含义,驱动安装程序则便于本地联调测试。已有 507 人学习下载,适合需要在 C++、C# 等项目中快速打通打印链路的初中级开发者参考使用。
1. TSC 打印机开发包到底装了什么:从一张扫不出的 40×30mm 标签说起
标签打印这件事,从外面看只是把字打到纸上,真正接手后才会发现是一堆数值在互相打架。业务系统把订单数据推到工位,一台 TSC 打印机通上电,纸走了一半就停住,或者二维码印出来要反复扫几次才有反应——多数情况下不是硬件坏了,而是 TSPL 指令里的尺寸、DPI、纠错等级没有对齐。这个压缩包把 TSC 打印机开发过程中需要反复查阅的内容集中在一起:指令手册、驱动、动态库、示例代码和调试工具都在里面,做标签打印、二维码打印时不必再各处去找。
它适合正在做产线打标、仓储面单、资产标签的开发者,也适合第一次接需求、还不清楚 TSPL 长什么样的人。后面按实际落地顺序来走:先打通链路,再拼版,再处理二维码,最后讲集成和翻车点。
2. 打通链路:USB、串口、网口三种连法的参数与最小验证
拿到压缩包后先别急着看 SDK 示例,第一件事是让机器打出一张能看的纸。链路不通,后面所有关于坐标、字体、纠错等级的讨论都没有意义。这一章按“看机器 → 选连法 → 发最小指令”三步走,每一步都给出可复现的操作。
2.1 先看自检页:机型、DPI、固件版本一次读全
TSC 打印机的自检页是排障时第一手资料。常见做法是断电状态下按住走纸键不放,再上电,等指示灯按固定节奏闪几次后松手,机器会自动走纸并打出一张自检页。这张纸上通常包含型号、固件版本、分辨率(203dpi 或 300dpi)、内存容量、已安装的字体和当前通信参数。把这几项抄下来贴在你的开发笔记里,后面每一次“打出来不对”都要回来对照。
这一步最容易被跳过,也最容易出问题。203dpi 和 300dpi 的机器同一份坐标打出来的位置差 1.5 倍,如果你在实验室用 203 的机器调好模板,到了现场换成 300 的机器,所有元素会挤在左上角。分辨率不是可以忽略的参数,它是整张标签的坐标系基准。
压缩包里的指令手册一般会区分 TSPL 和 TSPL-EZ 两套指令集,不同机型支持的指令范围不一样。老一些的机型可能不支持某些图形或条码指令,手册里会标注适用机型;如果翻到的指令在自检页对应机型上没有写,就不要勉强尝试,直接用等价指令替换。判断依据以自检页和手册为准,不要凭记忆。
2.2 USB、串口、网口:参数怎么填,失败先看哪
三种连接方式在实际项目里的分工大致是这样的:USB 适合单机工位和桌面式打样;串口适合老产线和长距离(配合转换器);网口适合多工位共享和需要固定部署的场景。选型上没有优劣,只有现场条件。
USB 连法在 Windows 下最省事。装完驱动后会生成一个打印队列,用 RAW 方式往队列里写字节流就行,不需要走图形驱动的渲染。要注意队列名,带空格和中文的队列名在代码里要原样传入。如果现场是 Linux 工控机,走 USB 端点直接写入需要额外权限配置,产线上我更倾向用网口或者转成串口,少一层驱动依赖。
串口的参数是固定的几项:波特率(常见 9600 / 19200 / 38400 / 115200,必须和机器设置一致)、数据位 8、停止位 1、无校验、无流控。串口最常见的翻车是波特率不匹配,表现为打印出乱码或者直接不响应。排查方法是先用串口工具手工发一条最简单的指令,确认有反应再回到代码。
网口的默认端口是 9100,走原始数据流。部署时把打印机 IP 设成固定地址,不要放在 DHCP 池里——产线重启一次路由器,打印机换了个 IP,第二天早班全线打不出来,这种事故我见过不止一次。先验证网络可达,再验证端口,最后才发数据。
# 1. 确认网络可达(把地址换成你机器上自检页打出来的 IP) ping -c 3 192.168.1.50 # 2. 确认 9100 端口在监听 nc -vz 192.168.1.50 9100 # 3. 发一段最小 TSPL 指令,打一张 40×30mm 的测试标签 printf 'SIZE 40 mm,30 mm\r\nGAP 2 mm,0\r\nDIRECTION 1\r\nCLS\r\nTEXT 20,20,"3",0,1,1,"LINK OK"\r\nPRINT 1,1\r\n' | nc 192.168.1.50 9100这段脚本的关键点在第 3 步:每条指令后面必须跟\r\n,不能只发\n。TSPL 是行式指令集,部分固件对行结束符很敏感,只给\n会出现指令被截断、后半段被当成内容打印出来的情况。SIZE和GAP的单位写成mm是允许的,但TEXT后面的坐标20,20是点(dot)不是毫米,这个区别在第 3 章会重点讲。PRINT 1,1的两个参数分别是份数和套数,先用 1,1 验证。
如果nc发出去有反应但纸是空的,先检查是不是走纸方向反了,再看DIRECTION设置(0 和 1 是 180 度翻转)。如果完全没反应,回到第 2 步确认端口;端口通但数据被吞,多半是打印机处于错误状态(缺纸、开盖、碳带用尽),面板上会有指示。
2.3 用 Python 把这段指令发出去:网口与 Windows 队列两版
命令行验证通过之后,把它翻译成代码。网口版用 socket,Windows 队列版用win32print的 RAW 写入,两段代码结构几乎一样,都是“拼字节流 → 打开通道 → 写 → 关”。
import socket def send_tspl_tcp(ip: str, port: int, payload: str, timeout: float = 5.0) -> None: """通过网口 9100 发送 TSPL 指令流""" # 统一转成 CRLF,避免不同平台换行符差异 data = payload.replace("\r\n", "\n").replace("\n", "\r\n").encode("utf-8") with socket.create_connection((ip, port), timeout=timeout) as sock: sock.sendall(data) # 给打印机留出解析和走纸的时间,立即 close 会导致尾部数据丢失 sock.settimeout(timeout) try: sock.recv(1024) # 部分固件会回一行状态,不强制要求 except socket.timeout: pass LABEL = """ SIZE 40 mm,30 mm GAP 2 mm,0 DIRECTION 1 CLS TEXT 20,20,"3",0,1,1,"LINK OK" PRINT 1,1 """ send_tspl_tcp("192.168.1.50", 9100, LABEL)import win32print def send_tspl_windows(printer_name: str, payload: str) -> None: """通过 Windows 打印队列以 RAW 方式发送,绕过驱动渲染""" data = payload.replace("\r\n", "\n").replace("\n", "\r\n").encode("utf-8") handle = win32print.OpenPrinter(printer_name) try: # 第二个参数是 job 名称,第三个参数必须是 RAW job_id = win32print.StartDocPrinter(handle, 1, ("tspl-label", None, "RAW")) win32print.StartPagePrinter(handle) win32print.WritePrinter(handle, data) win32print.EndPagePrinter(handle) win32print.EndDocPrinter(handle) finally: win32print.ClosePrinter(handle)网口版里有两个细节值得说。一是sendall之后不要立刻关闭连接,用recv阻塞一小会儿或者time.sleep(0.2),否则打印机可能只收到前半段;二是统一换行符,Windows 上拼出来的字符串默认是\r\n,Linux 上是\n,如果不做归一化,同一份模板在两边表现不一致,排查时会多花很多时间。
队列版的关键是RAW这个数据类型。走 RAW 意味着字节流原样送到打印机,驱动不做任何渲染和缩放。这一点很重要:如果你的模板坐标按 203dpi 算好,结果驱动按 A4 页面给它缩放了一遍,打出来的东西就全乱了。RAW 方式下打印机的SIZE指令说了算。StartDocPrinter的第二个参数 1 表示一个文档一页,标签场景固定用 1。
3. 指令拼版:TEXT、BARCODE、QRCODE 在一张标签上的落点计算
链路通了之后,真正花时间的是排版。TSPL 的排版逻辑和前端 CSS 完全是两套思路:没有流式布局,没有自动换行,所有元素按绝对坐标往画布上放,放歪了就是歪了。这一章把坐标、字体、条码和二维码四件事拆开讲,最后给一份能直接抄的完整模板。
3.1 坐标系与 DPI:40mm 到底等于多少点
TSPL 里有两套单位混着用,这是新手最容易栽的地方。SIZE、GAP、BLINE这类描述纸张的指令可以带mm或inch单位,而TEXT、BARCODE、QRCODE后面的 x、y、高度、宽度全部是点(dot),不能带单位。你写TEXT 20mm,20mm,...会直接报错或者被解析成别的东西。
点与毫米的换算取决于机器分辨率:
| 分辨率 | 每毫米点数 | 40mm 宽对应点数 | 30mm 高对应点数 |
|---|---|---|---|
| 203 dpi | 8.00 | 320 | 240 |
| 300 dpi | 11.81 | 472 | 354 |
| 600 dpi | 23.62 | 945 | 709 |
所以一张 40×30mm 的标签,在 203dpi 机器上可用画布是 320×240 点,在 300dpi 上是 472×354 点。同一个元素想在两种机器上都距左边缘 10mm,203dpi 下写 x=80,300dpi 下写 x=118。我一般会在代码里写一个mm2dot(mm, dpi)的函数,模板里全部用毫米描述,发送前统一换算,这样换机型时只改一个dpi变量。
DIRECTION和REFERENCE也会影响原点。DIRECTION 0和1是出纸方向相差 180 度,REFERENCE x,y可以把原点整体平移,用于补偿机械误差。这两个参数建议在模板头部固定好,不要在业务代码里动态改。
3.2 TEXT 和 BARCODE:字体号、倍率与可读字符
TEXT的完整格式是TEXT x,y,"font",rotation,x-multiplier,y-multiplier,"content"。字体号(font)在不同机型上映射不同,内建的英数字体通常是"1"到"5"这几个,中文字体则是包里附带的点阵字库文件名,常见以TST开头,具体可用哪些以压缩包里的字体说明和自检页打印出来的清单为准。rotation取 0 / 90 / 180 / 270,x-multiplier和y-multiplier是横纵向放大倍数,取 1 到 10 的整数。注意放大是整数倍的点阵拉伸,不是矢量缩放,放大 3 倍的字边缘会有明显锯齿,这是点阵打印的物理特性。
BARCODE的格式是BARCODE x,y,"code type",height,human-readable,rotation,narrow,wide,"content"。height是条码高度(点),human-readable取 0 或 1 决定下方是否打印可读字符,narrow是窄条宽度(1 到 10 点),wide是宽窄比。做 CODE128 时narrow建议不小于 2,203dpi 下 1 点的窄条只有 0.125mm,有些扫描枪在磨损或反光条件下读不出来。EAN13 这类定长码对内容位数有硬性要求,少一位直接不打,业务侧要在生成前做校验。
条码内容里如果有特殊字符,比如空格、星号、逗号,要用引号包住并且注意转义。CODE128 支持全 ASCII,是仓储面单里最稳妥的选择;CODE39 兼容性好但密度低,长内容会超出标签宽度。
3.3 QRCODE:五个参数决定扫得出来还是扫不出来
二维码打印是这个包里被问得最多的部分。QRCODE指令的格式是QRCODE x,y,ecc-level,cell-width,mode,rotation,"content",五个参数每一个都会影响最终能不能扫。
| 参数 | 取值 | 影响 |
|---|---|---|
| x, y | 点坐标 | 二维码左上角位置,需预留足够空间否则会被裁切 |
| ecc-level | L / M / Q / H | 纠错能力,H 最强但同等内容下模块更多、尺寸更大 |
| cell-width | 1 到 10 | 单个模块的边长(点),直接决定物理尺寸和扫描成功率 |
| mode | A / M | A 为自动选版本,M 为手动指定 |
| rotation | 0 / 90 / 180 / 270 | 旋转角度 |
cell-width是核心。203dpi 下cell-width=4意味着每个模块 0.5mm,一个 25×25 模块的二维码约占 12.5mm 见方,这是产线标签比较稳妥的配置;cell-width=2时模块只有 0.25mm,理论上能扫,但碳带浓度稍低、纸面稍反光就废了。我在现场见过为了把二维码塞进 8mm 宽度而把 cell-width 调到 1 的方案,最后是靠换更大标签解决的——这种取舍要在设计阶段就和业务方谈,不要等到打样。
ecc-level的选择有个反直觉的点:不是越高越好。H 级纠错能扛住 30% 的面积污损,但同样内容下模块数量增加,物理尺寸变大或者单模块变小。标签内容不长、贴标环境干净的话,M 级足够;如果标签要贴在有油污或者容易磨损的工件上,再上 Q 或 H。内容长度也会推动版本升级,一段长 URL 用 H 级可能直接超出标签宽度,这时要么缩短内容,要么降纠错等级。
mode用 A 让打印机自己选版本最省心,只有在需要固定版本号做兼容时才用 M。rotation在窄标签上很有用,横向放不下就转 90 度竖着放。
3.4 一张完整的 40×30mm 标签:从模板到函数
把上面的东西拼起来。下面这张标签包含品名、批次号、CODE128 条码和一个二维码,尺寸 40×30mm,按 203dpi 计算。
SIZE 40 mm,30 mm GAP 2 mm,0 DIRECTION 1 REFERENCE 0,0 SPEED 4 DENSITY 8 CLS TEXT 16,12,"3",0,1,1,"PART-A1024" TEXT 16,44,"TST24.BF2",0,1,1,"批次:B20240611" BARCODE 16,80,"128",60,1,0,2,4,"B20240611A1024" QRCODE 200,80,M,4,A,0,"https://example.local/p/A1024?b=B20240611" TEXT 16,190,"2",0,1,1,"2024-06-11 09:30" PRINT 1,1逐行说。SIZE和GAP描述物理纸张,GAP 2 mm,0表示标签间隙 2mm、偏移 0;如果是黑标纸要换成BLINE,连续纸用BOTH或者不写。DIRECTION 1固定出纸方向。REFERENCE 0,0是原点补偿,机械有偏差时在这里调。SPEED 4和DENSITY 8是打印速度和浓度,速度越低、浓度越高,二维码和细条码越清晰,但产线节拍会变慢,这两个值要在打样阶段调好写进模板。CLS清空图像缓冲区,不写会把上一次的内容叠上来——这是很常见的“影子重影”来源。
TEXT那两行的坐标单位是点:16,12是左上角起点,"3"是内建字体号,0是不旋转,1,1是横纵各放大 1 倍,即原始大小。中文那行用了点阵中文字体,字号由字体文件本身的点阵高度决定,倍率调大只是拉伸。
BARCODE那行里"128"是码制,60是条码高度(点),1表示打印可读字符,0不旋转,2是窄条宽度,4是宽窄比。宽窄比 4 在 CODE128 下是合法配置,实际用 2 或 3 更多,这里保持和窄条宽度匹配即可。
QRCODE那行:x=200、y=80 定位,M纠错,4模块宽度,A自动版本,0不旋转。内容里的 URL 带查询参数,长度适中,自动版本一般落在 4 到 6 之间,40mm 宽度放得下。
把这段模板参数化,做成一个函数:
def build_label(part_no: str, batch: str, ts: str, dpi: int = 203) -> str: mm = lambda v: int(round(v * dpi / 25.4)) lines = [ "SIZE 40 mm,30 mm", "GAP 2 mm,0", "DIRECTION 1", "REFERENCE 0,0", "SPEED 4", "DENSITY 8", "CLS", f'TEXT {mm(2)},{mm(1.5)},"3",0,1,1,"{part_no}"', f'TEXT {mm(2)},{mm(5.5)},"TST24.BF2",0,1,1,"批次:{batch}"', f'BARCODE {mm(2)},{mm(10)},"128",60,1,0,2,4,"{batch}{part_no}"', f'QRCODE {mm(25)},{mm(10)},M,4,A,0,"https://example.local/p/{part_no}?b={batch}"', f'TEXT {mm(2)},{mm(23.5)},"2",0,1,1,"{ts}"', "PRINT 1,1", ] return "\r\n".join(lines) + "\r\n"mm2dot用v * dpi / 25.4换算,round取整避免累积误差。所有坐标改成毫米后,换 300dpi 机器只需要把dpi传 300,模板本身不动。这一步看起来只是省事,实际价值在于把“分辨率”这个变量从散落各处的魔法数字收敛到一个参数上,后面排查偏移问题时能排除掉一大类原因。
4. 接进业务系统:批量队列、状态回读与重打幂等
单张标签打对之后,剩下的问题是量和稳定性。产线一天几千张,业务系统一次推一批过来,中间断一次就可能导致整批重打或者漏打。这一章讲三件事:指令流怎么拼、发出去之后能拿到什么反馈、失败了怎么重打而不重复。
4.1 指令流的拼装顺序与发送节奏
TSPL 的执行模型是“先建缓冲区,再一次性打印”。一份完整的作业应该是:纸张参数 → 方向与原点 → 打印参数 →CLS→ 所有内容元素 →PRINT。顺序乱了会出问题,比如CLS写在内容后面会把内容清掉,PRINT写在中间会导致前面渲一半就出纸。
批量打印不要“每张标签建一次连接”。网口场景下,每次 TCP 连接都有握手开销,几百张标签就是几百次连接,打印机那边的连接数管理不一定扛得住。正确做法是把多张标签拼成一个连续的指令流,一次发出去:
def build_batch(jobs: list[dict]) -> str: """把多个标签拼成一个连续指令流,一次发送减少连接开销""" chunks = [] for job in jobs: chunks.append(build_label(job["part_no"], job["batch"], job["ts"])) return "".join(chunks)要注意的是,一个指令流里每个PRINT后面都跟着一次走纸,打印机会按顺序一张张出。如果批次特别大(比如超过 500 张),建议分成每 50 到 100 张一批发送,中间留 200ms 间隔。原因是打印机的接收缓冲区有限,一次性灌太多,超出部分会被静默丢弃,表现出来就是“打了前 300 张,后面没了”,而且不报错。这个缓冲区大小不同机型不一样,压缩包里的手册一般会写,没有写就按保守值分批发。
4.2 状态回读:能拿到什么,拿不到什么
这是整个链路里最容易产生误解的部分。走网口 9100 原始数据流,发出去之后打印机通常不回任何东西,你只知道“TCP 写成功了”,不知道“纸打出来了”。走 Windows 队列,可以通过EnumJobs或GetPrinter查到作业状态(打印中、已完成、错误),但队列状态的更新有延迟,而且打印机侧的缺纸、开盖不一定能及时反映到队列里。
import win32print import time def wait_job_done(printer_name: str, job_id: int, timeout: float = 30.0) -> str: """轮询 Windows 打印队列,直到作业离开队列或超时""" handle = win32print.OpenPrinter(printer_name) deadline = time.time() + timeout try: while time.time() < deadline: jobs = win32print.EnumJobs(handle, 0, -1, 1) if not any(j["JobId"] == job_id for j in jobs): return "done_or_removed" time.sleep(0.5) return "timeout" finally: win32print.ClosePrinter(handle)这段代码能告诉你作业是否已经离开队列,但离开队列不等于纸打出来了——它也可能是被取消或者报错后清掉的。更可靠的反馈来自厂商 SDK 提供的状态接口,压缩包里的 SDK 文档一般会列出该机型支持的状态查询指令和返回格式,不同固件返回的字段顺序和含义有差异,以文档和实测为准,不要照搬网上的片段。
如果现场必须做到“打没打出来可确认”,务实的方案是在打印机上加装出纸检测,或者在业务侧引入人工确认节点。纯软件层面能做到的是“发出去”和“队列没报错”,做不到百分之百的物理确认,这一点在方案评审时就要说清楚。
4.3 重打与幂等:业务侧必须有后悔药
打印是不可逆动作,重打会产生重复标签。产线上重复标签的后果比漏打还麻烦——同一批次出现两张同号标签,追溯链就断了。所以重打逻辑必须放在业务侧,用状态位控制,而不是靠人去点按钮。
我一般会给打印任务建一张表,字段包括任务号、批次、内容摘要、状态(待打 / 已发 / 已确认 / 作废)、重打次数、操作人。状态流转只允许单向:待打 → 已发 → 已确认,重打时生成新任务号并关联原任务,原任务标作废。这样即使打印机中途卡纸,操作员补打的是新任务,审计链完整。
-- 只允许推进状态,不允许回退,重打走新记录 UPDATE print_job SET status = 'SENT', sent_at = NOW() WHERE job_id = :job_id AND status = 'PENDING'; -- 重打:复制原任务内容,生成新任务号,原任务置为作废 INSERT INTO print_job (job_id, batch_no, payload, status, retry_of) SELECT :new_job_id, batch_no, payload, 'PENDING', job_id FROM print_job WHERE job_id = :old_job_id AND status <> 'VOID';WHERE status = 'PENDING'这个条件保证了并发情况下不会重复发送同一个任务,影响行数为 0 就说明已经被别人领走了。这种乐观锁的写法比在应用层加锁简单,也不依赖数据库特性。重打记录用retry_of指回原任务,月底对账时能查出哪些批次补打过、补了几次。
5. 踩坑排查:五类现场翻车记录的现象、成因与处置
下面这五条都是实际遇到过、并且复现过的。写出来不是为了吓人,是为了让你在遇到时能少走弯路。
5.1 第一张整体偏移,后面几张正常
现象:开机后打第一张,内容整体下移 2 到 3 毫米,第二张开始恢复正常位置。
原因:打印机断电后纸张没有被定位到间隙传感器位置,第一张走纸时多走了定位距离。另外GAP的标定值和实际标签间隙不一致也会放大这个偏差。
解决:上电后先发一次FEED指令走两张纸做定位,再发正式内容;同时用卡尺量实际间隙,把GAP设准。如果偏移量稳定在固定值,用REFERENCE做原点补偿,不要靠改内容的 y 坐标硬凑,后者会在换纸卷后重新出问题。
5.2 二维码有的能扫有的扫不出
现象:同一批标签,用手机扫十张,能扫出六七张,剩下的要试好几次。
原因:cell-width偏小加上浓度或速度不匹配。模块太小的时候,碳带转移不均匀会让边缘糊在一起,扫描器解不出来。内容过长导致自动选到高版本、模块数变多、单模块更小,也是同一类问题。
解决:先把cell-width从 2 或 3 提到 4 到 5,再看效果;把SPEED降到 3 到 4,DENSITY调到 8 到 10 之间试;内容能缩短就缩短,URL 里的参数能砍则砍。这三步按顺序试,一次改一个变量,否则不知道是哪一步起的作用。
5.3 中文变成问号或者方块
现象:英文和数字正常,中文位置打印出来是问号、方块或者空白。
原因:字体没指定对,或者代码页不匹配。TSPL 默认按单字节处理,中文必须显式指定支持中文的点阵字体,并且内容编码要和打印机侧的代码页一致。
解决:确认包里的中文字库文件已经随指令下发或者已安装到机器上,TEXT里的字体名写全(包括扩展名部分),在指令流开头加CODEPAGE UTF-8(如果固件支持),并且发送前把字符串统一编码成 UTF-8 字节。三步里任何一步缺失都可能出乱码,建议先用一个固定的中文串做单变量测试。
5.4 批量打印后半段丢单
现象:一次推 500 张,前 300 张正常出纸,后面没动静,打印机也不报错。
原因:单次发送的数据量超过打印机接收缓冲区,超出部分被静默丢弃。网口原始数据流没有流控机制,发多快都照单全收,但打印机处理不过来。
解决:分批发送,每批 50 到 100 张,批间留 200ms 以上间隔;或者每批发完后等一个短超时的recv再发下一批。更稳妥的做法是业务侧把批次拆小,按队列逐批消费,这样即使中途断了也能从断点续打。
5.5 换到 300dpi 机器后内容挤在左上角
现象:模板在 203dpi 机器上排版正常,换到 300dpi 机器后所有元素集中在左上角,右下大片空白。
原因:坐标是按点写的,300dpi 下同样的点数对应的物理尺寸只有原来的三分之二左右,整个版面按比例缩小了。
解决:把所有坐标统一改成毫米描述,发送前按当前机器的 dpi 换算成点。这个改动要一次性做掉,不要试图在旧模板上乘系数打补丁,否则后面每加一个元素都要记得乘,迟早漏掉一个。
6. 验收方法:把标签质量压到一页纸上的对比卡
模板调通不等于能上产线。我在现场吃过一次亏:实验室里扫得飞快,到了车间灯光下一半扫不出来,原因是二维码模块太小加上纸面反光。从那以后,我每次上线前都会打一张对比卡,把关键变量排在一起,一眼能看出哪组配置最稳。
具体做法是固定同一份内容,只变两个变量:cell-width取 3、4、5、6 四档,SPEED取 3 和 5 两档,排成 4×2 的矩阵打在一张 A4 大小的连续纸上。每格下面用TEXT标上参数,方便对照。打出来之后做三件事:在正常室内光下扫、在强光斜射下扫、用手指蹭两下再扫。三关都过的配置才写进模板。
| 验收项 | 判定标准 | 不过怎么办 |
|---|---|---|
| 二维码识别 | 正常光、斜射光各扫 10 次,10 次全过 | 提高 cell-width 或降速 |
| 条码识别 | 扫描枪 10 次全过,可读字符清晰 | 加大 narrow 宽度 |
| 字符完整性 | 中文无乱码、无截断 | 检查字体与代码页 |
| 位置精度 | 连续 20 张偏移不超过 0.5mm | 校准 GAP、加 REFERENCE |
| 切刀/剥离 | 切口不压内容、不粘标 | 调 SIZE 高度留 1mm 余量 |
配套的一个小技巧是给每台机器做一份配置档案,把 dpi、SPEED、DENSITY、GAP标定值、REFERENCE补偿值、二维码参数记在一个 JSON 里,随模板一起版本管理。换机器时先查档案,没有就现场跑一遍对比卡补上。这套东西听起来笨,但比事后追查“为什么这台机器打出来和那台不一样”省太多时间。
再补一个验证细节:不要用手机自带相机扫完看到链接就完事,很多相机的识别能力远强于产线手持扫描枪。验收时用实际要用的那把枪,或者至少用同等级的工业扫描器。这个差异在二维码模块偏小时尤其明显,相机能读、枪读不出,是现场最常见的扯皮来源。
从那以后我每次上产线前的第一件事,就是把对比卡打出来贴在机器旁边,参数不对就当场改,绝不留到量产。希望帮到你。
本文还有配套的精品资源,点击获取