产线要做批次追溯,第一步都是把扫码枪接进上位机。接法就三种:键盘楔(模拟键盘输入)、串口(RS232)、网口(TCP)。选型不复杂:单工位、就扫个码不做逻辑,键盘模式最快上线;多工位、要和工位数据绑定、要防重码漏码,老老实实走串口或 TCP。扫码本身一天就能调通,难的是后面那件事——怎么把码和这个工位的加工数据绑在一起,出了问题能正查反查。这篇从接线讲到落库。

三种接法:先想清楚要不要"程序拿到码"

接法 A · 最省事 键盘楔(USB 模拟键盘)

扫码枪当键盘用,码值直接"打"进当前焦点的文本框,末尾自带回车。零代码,但程序无法区分"扫码"和"手工敲键盘",焦点一跑偏码就丢了。

零开发无法校验焦点依赖
接法 B · 最常用 串口 RS232

扫码枪切串口模式,上位机开 SerialPort 监听,按结束符拼帧。码值独立通道进来,可以做格式校验、防重、绑定逻辑,是定制上位机的默认选择。

独立通道可校验线缆≤15m
接法 C · 最远 网口 TCP

固定式工业读码器常用,扫码器做 TCP 客户端主动把码推给上位机监听端口,布线距离不受限,适合读码器装在线体上、工控机在柜子里的场景。

距离不限固定读码器要管连接

▲ 判断标准其实就一条:码进来之后要不要走程序逻辑。要校验、要绑定、要防重,就必须 B 或 C;只是把码填进一个输入框,A 最省事。

串口模式两个必配项:结束符和帧间隔

串口扫码枪的数据是一串字节流过来的,程序怎么知道一条码扫完了?靠两个约定:

配置项推荐值说明
结束符CR+LF(\r\n)扫码枪设置里打开"添加回车换行后缀",程序按行读取,一条码一行,边界清晰
波特率9600 / 115200枪与程序必须一致;改波特率后记得重新上电
帧间隔超时50~100 msReadTimeout 兜底:万一结束符配置丢了,靠"静默 100ms 视为一帧结束"收尾
编码ASCII条码内容都是 ASCII;遇到中文标签码再考虑 UTF-8

这里有个新手常踩的坑:用 ReadExisting 一把抓再自己切串。串口数据是分段到达的,一条码可能分两三次 DataReceived 事件才收齐,直接抓就会拿到半条码。稳妥做法是逐字节/逐段累积进缓冲区,见到 \r\n 才取出一整条。C# 骨架:

private readonly StringBuilder _buf = new StringBuilder();
private DateTime _lastCode = DateTime.MinValue;

private void OnDataReceived(object s, SerialDataReceivedEventArgs e)
{
    string chunk = _port.ReadExisting();
    lock (_buf) _buf.Append(chunk);

    string all; lock (_buf) all = _buf.ToString();
    int idx;
    while ((idx = all.IndexOf("\r\n")) >= 0)
    {
        string code = all.Substring(0, idx).Trim();
        all = all.Substring(idx + 2);
        if (code.Length > 0) HandleCode(code);   // 一条完整码
    }
    lock (_buf) { _buf.Clear(); _buf.Append(all); }
}

private void HandleCode(string code)
{
    // ① 防抖:同码 2 秒内重复到达视为连扫抖动,丢弃
    if (code == _lastText && (DateTime.Now - _lastCode).TotalSeconds < 2) return;
    // ② 格式校验:长度、前缀、字符集,不合格直接红字提示重扫
    if (!CodeRule.IsValid(code)) { RaiseBad(code); return; }
    _lastText = code; _lastCode = DateTime.Now;
    _queue.Enqueue(code);   // 丢给业务线程做绑定,串口线程不做重活
}
键盘模式想"伪校验"也有个土办法:监听 KeyPress 的输入速度——扫码枪几十个字符在 50ms 内打完,人手敲不可能这么快。按"字符间隔小于 20ms 判定为扫码"可以粗略区分。能用,但只适合过渡,正式项目还是建议换串口。

码不是目的:扫码要和工位数据绑在一起

扫码枪调通只是开始。追溯的本质是回答两个问题:这个产品用了什么料、经过了什么过程(正查);这批料出了问题,流到了哪些产品里(反查)。所以每条扫码记录落库时,必须同时绑上当时的上下文:

① 扫码码值+时间串口/TCP 收到完整码,格式校验通过
② 绑定上下文工位+设备+批次当前工单号、工位编号、操作员、设备参数快照
③ 校验放行防错判断物料与工单BOM是否匹配、是否重复上线、是否跳工序
④ 落库追溯记录一物一码写 trace 表,同时给 PLC 放行信号
⑤ 查询正查/反查按产品码查全过程,按物料批号查流向

落库结构不复杂,核心就是一张主表 trace_record,记每一次扫码绑定:

字段类型说明
idbigint主键
product_codevarchar(64)产品码(一物一码),建索引
material_batchvarchar(64)扫到的物料/零件批号码,反查的关键字段,建索引
station_id / op_novarchar / int工位与工序号
work_ordervarchar(32)工单号
operatorvarchar(32)操作员账号
process_datajson/varchar该工位关键参数快照(扭矩、温度、测试值)
result / scan_timetinyint / datetime合格与否 + 扫码时刻

▲ 反查就是一条 SQL:SELECT product_code FROM trace_record WHERE material_batch = '批次号',物料批号索引必须建,否则产线追溯时全表扫描能急死人。

现场最容易翻车的三件事

重码。操作员对着同一个件连扫两下,或者返修件二次上线,系统里出现两条记录。处理原则:同一工位同一产品码只允许一条"合格"记录,重复扫码要么拒绝并提示"已上线",要么走显式的返修流程覆盖,绝不能静默追加。

漏码。产品流到下一工位,才发现上一工位没扫码。所以第③步的"校验放行"很重要:下一工位扫码时检查上一工序记录是否存在,缺了就拦截报"跳工序"。宁可停线一分钟,不要事后补录一堆假数据。

码制混乱。今天客户用 Code128,明天换 QR,后天来一批 DataMatrix。扫码枪要在设置里把需要的码制全打开,同时上位机的格式校验规则按"前缀+长度"做白名单,陌生格式的码直接拒收并报警——收进来一个解析不了的码,比不收更麻烦。

一个容易被忽略的点:扫码枪的"蜂鸣反馈"要和系统结果联动。扫码枪自带的蜂鸣只能说明"码读出来了",不能说明"系统接受了"。我们通常让上位机校验通过后再给枪一个信号(串口枪可配触发线,或用画面大字+声音反馈),操作员听到两声才是真通过。不然现场永远在问"我扫了怎么没反应"。

收尾:上线前的自检清单

  • 结束符配置与程序解析方式一致(都按 \r\n),断帧超时兜底已配;
  • 同一码 2 秒内重复扫,系统只认一次;
  • 扫错料(与工单 BOM 不符)时系统拦截并红字提示,不放行;
  • 跳工序能被下一工位拦截;
  • 拿一个真实批号做反查,10 秒内能列出全部流向产品;
  • 扫码记录与工位参数快照在同一事务里落库,不会出现"有码无参数"。

扫码接入这件事,硬件层面半天搞定,真正的工程量在"绑定与防错"上。如果你的追溯系统现在只是把码存了个流水,建议先补一个功能:输入任意物料批号,列出它流向了哪些产品——做不出来的话,追溯其实还没开始。