大概在半年前,我接到一条装配线的改造任务。现场情况是:产线上有80个托盘,每个托盘底部嵌着一张RFID标签,托盘经过不同工位时,PLC要实时读出托盘上挂的车型信息,自动切换拧紧扭矩和物料清单。主控用的是汇川AM401,触摸屏用的是汇川IT系列。最开始大家想走的是RFID读写器最常见的Modbus RTU串口方案,因为大部分读写器都支持,PLC这边也支持串口自由口通讯,感觉改起来会很快。可现场走了一圈,问题全暴露出来了。RS485线从第一个读头到PLC控制柜接近50米,加上中间分线,整个链路串了四五个读头,总长度超过120米。9600bps波特率勉强能通,但偶尔丢帧;把波特率拉到19200bps,通讯直接不稳定。更要命的是,装配线是边走边读,留给PLC读取标签的时间窗口只有大约300毫秒,Modbus RTU那种"查询-应答"一问一答的方式根本来不及。后来我把方案整个换成CK-LR08-E00工业级RFID读写器走以太网,用TCP/IP自由协议和汇川PLC直接通讯,问题一次性解决。这篇就把完整的选型思路、报文设计、PLC程序结构和现场调试过程讲透,给打算做RFID和PLC以太网自由协议通讯的人一个可以直接抄作业的实例。
1. 为什么是自由协议而不是Modbus TCP:一条装配线改造的通讯选型复盘
1.1 现场最初的方案评估
在做方案的时候,我把市面上的通讯方式都过了一遍。除了Modbus RTU串口,还有Modbus TCP、TCP/IP自由协议、IO触发这几种路线。加起来大概四个方案,我一一盘过,最后才定下来走自由协议。
先看Modbus RTU串口,这个方案最大的优势是便宜通用,几乎每个读写器都带RS485口,汇川PLC这边的配置也不算复杂。但它的短板太明显:速度被波特率卡死,距离被线缆质量卡死,抗干扰能力在电柜密集的场合又是个隐患。我们一条线上要挂四五个读头,全部走串口串联,任何一个节点出问题整条链路都会受影响,排查起来特别费劲。
再看Modbus TCP,通讯速度解决了,PLC也有现成的库可以用。但真正写程序的时候你会发现,Modbus TCP的数据是映射到一组保持寄存器里的,标签数据不定长、还是突发性的,PLC要做批量轮询、还要处理寄存器刷新时机,绕了一圈反而比自由协议更麻烦。而且像EPC这种12字节以上的原始数据,用Modbus寄存器表达特别别扭,先得把字节序倒腾一遍,触摸屏那边还得再倒腾一遍,中间的坑多得离谱。
IO触发方案最简单,只能告诉PLC"标签有还是没有",具体内容完全拿不到。对只做防错的工位可能够用,但对需要识别车型、切换工艺参数的产线来说完全不够。
最终选TCP/IP自由协议,核心就一句话:汇川AM401在Codesys平台下可以直接用Socket套接字收发任意字节,CK-LR08-E00也开放了TCP Server端口允许用户自定义报文,两边都有直接操作字节流的能力,那为什么还要套一层Modbus中转?直接在PLC里拼命令、发命令、收报文、解析EPC,所有逻辑都看得见摸得着,出问题也能快速抓包定位。
下表是我当时做的对比,供参考。
| 方案 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| Modbus RTU串口 | 成本低、读写器普遍支持 | 速度慢、距离受限、抗干扰一般 | 读头少、距离短、节奏慢的工位 |
| Modbus TCP | 标准协议、PLC库成熟 | 数据寄存器映射繁琐、不定长数据表达别扭 | 现场已有Modbus经验、上位机也要取数据的场景 |
| TCP/IP自由协议 | 报文可控、直接返回原始标签数据、灵活性最高 | 需要自己约定协议和CRC校验 | 标签数据需要快速进PLC、读写器开放自定义TCP口 |
| IO触发 | 最简单、成本最低 | 只能传达有/无信号,读不到标签内容 | 只做防错校验的简单工位 |
1.2 自由协议需要注意的"自由"边界
选自由协议不是说报文可以随便写。真正的难点在于,自由协议的一切约束都靠两端自己去约定,没人帮你兜底。协议定了之后,帧头要一致、长度字段的大小端要一致、CRC校验覆盖范围要一致、超时重发机制要一致,任何一处不一致,结果就是PLC收到一堆乱码或者干脆没反应。
我见过不少项目,一听到自由协议就觉得"自由"了,组帧随便写,长度字段想放哪个字节就放哪个字节,结果联调的时候两边一直在扯皮。我的习惯是,动PLC程序之前先把报文格式用一张表定死,截图发给读写器厂家确认一遍,再动手写代码。确认错了,最多浪费半天;不确认就写,后面可能白白搭上好几天。
1.3 网络拓扑和数据链路设计
整个系统是标准的工业以太网星型结构。CK-LR08-E00读写器接到现场工业交换机,汇川AM401 PLC接在交换机另一个口上,触摸屏也在同一个交换机。网段规划成:PLC是192.168.1.10,读写器是192.168.1.200,触摸屏是192.168.1.30,网关统一指向192.168.1.1。读写器配置为TCP Server,PLC作为TCP Client主动建立连接,这样PLC对连接的生命周期有完全的控制权,读写器断电再上电后,PLC可以自己判断重连时机。
数据链路分两层理解。物理层是"天线—读写器—网线—交换机—PLC网口",逻辑层则是一条"PLC发送读标签命令帧,读写器返回应答帧,PLC按协议解析出EPC和RSSI,标签数据写入变量供HMI显示和后续逻辑使用"的消息流。后面每一环怎么配、怎么写、怎么调,我一个一个拆开讲。
2. CK-LR08-E00读写器侧的准备:IP配置与报文格式约定
2.1 硬件接线与上电前的注意点
先说硬件。CK-LR08-E00是一台工业超高频RFID读写器,支持ISO18000-6C协议,工作频段覆盖920到925MHz这个国内常用频段,配一个SMA接口的外置天线,供电是DC24V,带一个RJ45百兆网口。我拿到的样机固件版本是V2.3,设备管理界面和指令集在不同批次上会有小幅差异,但大的配置点基本一致。
接线有几点必须注意。第一,天线馈线能短就短。SMA馈线超过3米后信号衰减非常明显,实测读取距离会缩短两成以上,我这边的馈线尽量控制在1米内。第二,天线正前方和侧面不要有连续金属平面,尤其是金属托盘循环线这种场景,天线与金属面之间至少要留出200mm以上,否则反射波叠加会出现"盲区",标签到了盲区就怎么都读不到。第三,读写器供电最好单独给一路DC24V开关电源,不要和变频器伺服共用电源。读写器瞬间发射射频时电流会有一个跳动,电源不干净很容易把干扰引到通讯电路上。第四,上电前先把天线接好再接电,SMA接口尽量不要空载,尤其大功率输出时空载容易损坏射频功放。
2.2 配置IP地址和工作模式
读写器默认IP一般和PLC不在同一个网段,第一次使用需要用随机附带的搜索工具按设备MAC地址或扫描网段把设备找出来,修改IP后重新分配固定地址。我这台默认是192.168.1.168,因为要和PLC的192.168.1.10通信,改成了192.168.1.200,子网掩码255.255.255.0,网关统一指向192.168.1.1。修改之后读写器会自动重启,重启完网段才生效。
接着设置工作模式。CK-LR08-E00内置了好几种工作模式,我选的是被动应答模式,也就是由PLC主动发命令,读写器收到命令后才执行并返回结果。另有一种主动上报模式,读写器一检测到天线场内有标签就自己往上发数据,好处是PLC不用轮询,坏处是数据到达时机不可控。装配线上一个工位可能同时进来好几个托盘,主动上报模式会出现连续好几帧报文一股脑砸过来,PLC处理起来要额外做队列和状态管理,程序复杂度会明显上升。为了保持逻辑可控,我选了被动应答。
通讯设置里,把通讯方式设成TCP Server,固定监听端口8600,允许的最大TCP连接数设为1。一读头对应一PLC,一个连接足够了。如果有多台PLC要同时取数据,读写器一般不支持多连接,得加串口服务器或者用上位机转发,那是另一种架构了。
2.3 报文格式约定:帧头、命令、长度、CRC和帧尾
自由协议的关键在于"先约定好,再写程序"。下面这套报文格式是我实际在用的,可以直接参考。
先看PLC发给读写器的命令帧,固定结构如下:
| 偏移 | 字段 | 宽度 | 说明 | 示例值 |
|---|---|---|---|---|
| 0 | 帧头 | 1字节 | 固定AA | AA |
| 1 | 帧头 | 1字节 | 固定55 | 55 |
| 2 | 命令码 | 1字节 | 01=读EPC,02=写EPC,03=读TID | 01 |
| 3 | 数据区长度高字节 | 1字节 | 大端,高字节在前 | 00 |
| 4 | 数据区长度低字节 | 1字节 | 大端 | 00 |
| 5 起 | 数据区 | n字节 | 命令参数 | 空 |
| 5+n | CRC高字节 | 1字节 | CRC16-Modbus,覆盖从偏移0开始到数据区结束的字节 | xx |
| 6+n | CRC低字节 | 1字节 | CRC结果高字节在前 | xx |
| 7+n | 帧尾 | 1字节 | 固定16 | 16 |
最常用的读EPC命令,没有数据区,边长8字节,十六进制长这样:
AA 55 01 00 00 xx xx 16其中xx xx是根据前面5个字节AA 55 01 00 00算出来的CRC16-Modbus校验值。
再看读写器返回给PLC的应答帧,结构基本一致,只是命令码变了。读EPC的应答命令码固定为0x81,数据区第一个字节是状态字,0x00表示成功,其他值是错误码,后面跟着12字节的EPC数据。因为多了12字节的EPC,数据区长度就是13字节,也就是0x000D。一个典型的读EPC应答帧长这样:
AA 55 81 00 0D 00 E2 80 11 60 12 34 56 78 9A BC DE F0 xx xx 16其中AA 55是帧头,81是应答命令码,00 0D表示数据区长度13字节,第一个00是状态字,从E2到F0这12个字节是标签EPC,xx xx是CRC,16是帧尾。
这里有一个最常见的坑:CRC16的覆盖范围到底从哪里到哪里。不同厂家的习惯不一样,有些厂家把帧头也纳入校验,有些厂家从命令码开始校验。我这台CK-LR08-E00的固件是按"从帧头AA开始,到数据区最后一个字节结束,不包括CRC本身和帧尾"来算的。这块如果不跟厂家确认清楚,后面CRC会一直对不上。
2.4 为什么我让PLC做Client,读写器做Server
很多人在做TCP自由协议时习惯把设备端设为Client,让PLC当Server等对方连过来。我在工业现场不这么干。让PLC主动做Client有两个直接好处。
第一,PLC可以在上电后自己判断什么时候建立连接。读写器上电到TCP Server起来一般需要一两秒,PLC如果一通电就去连,大概率连不上,需要重连逻辑。PLC做Client时,这个重连逻辑非常好写,主动权完全在自己手里。第二,当网络异常断开时,PLC能控制重连节奏,避免读写器断电期间PLC一直在发连接请求,把网络塞满。另外从排查角度讲,PLC发起连接后,读写器日志里会清楚记录"某个IP在某个时间发起了TCP连接",PC端抓包也能很清楚地看到连接三元组,问题定位快很多。
当然这个前提是读写器支持固定IP且能做TCP Server监听。CK-LR08-E00支持,所以成立。如果遇到只支持Client的设备,PLC就必须自己监听端口等连接进来,程序里还要处理多个连接抢占问题,复杂度会明显上一个台阶。
3. 汇川PLC侧的程序实现:Socket连接与收发状态机
3.1 在InoProShop里搭出Socket通信基础框架
汇川AM400/AM600系列用的编程软件是InoProShop,基于Codesys平台,底层用ST语言写逻辑。网络通信库在库管理器的"通信"分类下能找到,不同版本的库名字有差异,我这边库版本较新,里面带的是TCPSocket这类功能块。核心用到的功能块大致有四个:
- SocketConnect(或TcpConnect):作为TCP Client主动发起连接,输入服务器IP和端口,输出连接句柄和连接状态。
- SocketSend:把要发送的字节数组发送到指定连接句柄。
- SocketRecv:从指定连接句柄接收字节,存入接收缓冲区。
- SocketClose:关闭指定句柄。
用这些功能块有个非常重要的习惯:它们大多采用Execute边沿触发,不能把执行位一直置成TRUE,否则功能块会一直反复执行。我是用一个触发变量,每次需要建立连接或发命令时给Execute一个FALSE到TRUE的上升沿,等Done信号出现后再复位。这个习惯帮我省了大量调试时间。
3.2 主状态机:从连接到断线重连的全流程
自由协议没有标准协议那种自动管理连接的机制,我强烈建议把整个通信过程做成状态机,不要用"从上到下扫一遍"的线性PLC程序。我定义的状态如下:
S_INIT = 0; // 初始化,等待 S_CONNECT = 1; // 发起TCP连接 S_READY = 2; // 连接建立成功,空闲待命 S_SEND_CMD = 3; // 发送读标签命令 S_WAIT_RESP = 4; // 等待读写器应答 S_ERROR = 5; // 通信异常,准备重连程序主循环里按当前状态执行对应逻辑。上电后进入S_INIT,延时1秒让读写器完成TCP Server初始化,然后进入S_CONNECT,调用SocketConnect主动连接192.168.1.200:8600。连接成功后进入S_READY,此时如果托盘到位信号触发,就进入S_SEND_CMD,发送读EPC命令,发完立刻转到S_WAIT_RESP,并开启一个500ms超时定时器。若在超时时间内收到完整且CRC校验通过的应答帧,就解析数据、更新标签变量、回到S_READY;若超时没收齐,重发计数加1,回到S_SEND_CMD重新发命令;连续重发3次都失败,判定通信异常进入S_ERROR,主动关掉Socket,延时2秒后回到S_INIT准备重连。
这个状态机把正常读取、偶发超时重试、完全断线重连三条路径都覆盖了,是我在不同项目里反复调试后定型下来的结构。你复制过去改改IP和端口就能用,关键在于这套结构不会因为某次通信失败就把PLC程序卡死。
3.3 CRC16校验的ST实现
CRC16-Modbus是整个帧校验的核心。我常用的ST函数如下,注意最后做了字节交换,因为协议约定CRC高字节在前:
FUNCTION F_CRC16_MODBUS : WORD VAR_INPUT pData : POINTER TO BYTE; dwLen : DWORD; END_VAR VAR uiCRC : WORD; iByte : DWORD; iBit : INT; END_VAR uiCRC := 16#FFFF; FOR iByte := 0 TO dwLen - 1 DO uiCRC := uiCRC XOR WORD(pData[iByte]); FOR iBit := 0 TO 7 DO IF (uiCRC AND 16#0001) <> 0 THEN uiCRC := (uiCRC SHR 1) XOR 16#A001; ELSE uiCRC := uiCRC SHR 1; END_IF; END_FOR; END_FOR; F_CRC16_MODBUS := (uiCRC AND 16#00FF) SHL 8 OR uiCRC SHR 8;组帧时,把收发数组的首地址传给pData,长度按"从AA开始到数据区结束"计算。这里有个关键点:校验范围一定要和读写器固件文档核对清楚。我在不同项目里遇到过从命令码开始校验的、甚至有的从数据区开始校验的,五花八门。所以拿到读写器后的第一件事,就是拿官方示例报文逐字节验证CRC算法,对上了再写进PLC程序。省这一步,后面CRC出错时你会浪费两三天。
3.4 接收缓冲:TCP协议天然会带来的粘包和拆包
TCP是面向流的,底层不保证每次recv到的数据刚好等于发送方的一帧。读写器连续返回两帧应答时,可能一次性把两帧塞给PLC,这叫粘包;一帧应答也可能被拆成两三个小包分次到达,这叫拆包。如果PLC程序收到数据后直接按一帧解析,遇到粘包或拆包就全乱了。
我处理的标准做法是维护一个接收字节数组缓冲,把SocketRecv收到的字节不断追加进去,然后做"找帧头、读长度、收整帧、验CRC"的解析。流程分三步:
第一步,在缓冲里寻找连续的两个字节0xAA 0x55。如果没找到,把缓冲清理掉,等新数据。找到后,从帧头开始往下读偏移3和偏移4的两个字节,作为数据区长度n。
第二步,检查缓冲里从帧头开始是否已经有n+8个字节。这n+8是帧头2字节加命令码1字节加长度2字节加数据n字节加CRC2字节加帧尾1字节算出来的。如果不够,说明这一帧还没收完整,继续等下一轮recv。如果够了,把这n+8个字节整帧取出,做CRC校验。
第三步,CRC不对,就丢弃帧头第一个字节,从下一个字节重新找0xAA 0x55继续解析。CRC正确,就把整帧交给上层解析函数,提取状态字和EPC。
这样处理之后,无论TCP底层怎么粘怎么拆,PLC程序都能稳定取出一个完整且校验正确的报文帧。这套逻辑我在多个项目里复用过,是自由协议通讯里最值得认真写的一部分,比任何命令字和设备库都重要。
4. 联调实录:抓包、解析与HMI联动的完整流程
4.1 先用电脑模拟PLC,验证读写器报文是否符合预期
把PLC正式接进去之前,我都会先做一步"电脑假扮PLC"的联调。这一步非常关键,等于先把问题隔离在网络协议层,而不是让PLC程序问题和网络问题搅在一起。
在电脑上开一个网络调试助手,或者直接用Python写几行脚本,连到192.168.1.200:8600,发送读标签命令,看返回什么。最简单的一段测试脚本如下:
import socket def crc16(data): crc = 0xFFFF for b in data: crc ^= b for _ in range(8): if crc & 0x0001: crc = (crc >> 1) ^ 0xA001 else: crc >>= 1 return ((crc & 0xFF) << 8) | (crc >> 8) cmd = bytes([0xAA, 0x55, 0x01, 0x00, 0x00]) cmd += crc16(cmd).to_bytes(2, 'big') cmd += bytes([0x16]) s = socket.create_connection(("192.168.1.200", 8600), timeout=3) s.sendall(cmd) resp = s.recv(1024) print(resp.hex()) s.close()如果读写器天线前有标签,脚本会打印出一串十六进制,通常长这样:
aa5581000d00e2801160123456789abcdef0xxxx16把返回的报文和手册示例逐字节对一遍,确认帧头、长度、状态字、EPC位置都能对上。这一步做完,说明读写器工作正常,通讯协议也基本正确,再进入PLC联调就轻松了。
4.2 首次联调记录:三个真实遇到的小问题
第一次把PLC程序启起来,我实际碰到了三个问题,这里逐条记录,都是特别典型的小坑。
第一个问题是PLC连不上读写器。排查下来是IP写错了。读写器IP已经改成了192.168.1.200,但PLC程序连接目标地址我写成了192.168.1.2,少了一位0。改回来之后立刻能通。这种低级错误光靠眼睛检查很难发现,最好的办法就是抓包或者Ping一下,把地址确认清楚再往下走。
第二个问题是连接能建立,但读写器对命令没反应。抓包发现PLC确实把AA 55 01 00 00 xx xx 16发出去了,但读写器根本没回包。后来排查发现端口号不一致,读写器配置软件里监听端口设的是8600,PLC程序里连接端口写成了6080。这种"IP看着对但端口错"的问题在没有抓包习惯时特别容易卡壳,因为Ping是通的,你以为网络没问题,实际上TCP根本连错门了。
第三个问题是返回包CRC老是校验失败。同一个命令,电脑端测试正常,换到PLC程序里就CRC失败。对比两组报文,命令字节完全一样,问题出在接收解析:PLC程序在算CRC时把帧尾0x16也算了进去,而读写器的CRC是不包含帧尾的。把校验长度减掉一个字节,问题立刻消失。
这三个问题都不难,但每次联调几乎都会碰上一两个。所以我现在总结出一个固定习惯:先跑通电脑端,再接PLC;出问题先抓包,不要靠猜。
4.3 Wireshark抓包怎么看TCP报文里的RFID数据
调试以太网通讯时,Wireshark是必开工具。在PLC和交换机之间加一个镜像端口,或者在笔记本上连到同一台交换机做端口镜像,启动抓包后过滤tcp.port == 8600,就能看到PLC和读写器之间的全部TCP报文。
抓包重点看三层。第一层是TCP三次握手,SYN、SYN-ACK、ACK三个包正常出现,说明TCP连接建立没问题。第二层是应用层数据,在Wireshark中部窗口的Transmission Control Protocol里往下找TCP Payload,能直接看到AA 55开头的十六进制数据,这就对应了PLC发出的命令帧或读写器返回的应答帧。第三层是TCP序列号和重传情况,如果看到大量TCP Retransmission或Dup ACK,说明现场网络有丢包或交换机性能不足,这种情况下RFID数据再对也是白搭。
需要特别说明,Wireshark只反映网络层字节内容,它不会帮你做CRC校验。看到报文数据之后,还是要靠PLC程序按协议解析。不过Wireshark能快速帮我们判断问题属于"设备根本没发数据"还是"发了但PLC解析错了"这两类情况中的哪一种,这已经能省掉一半排查时间了。
4.4 HMI联动和最终读写成功率验证
标签数据进PLC后,我把它映射到一组全局变量,方便触摸屏读取:
szTagEPC : ARRAY[0..11] OF BYTE; // 12字节EPC,按十六进制显示 wRSSI : WORD; // 信号强度 bTagRead : BOOL; // 本次读标签是否成功 wReadCnt : DWORD; // 累计读取次数触摸屏上放一个"当前托盘EPC"显示框,一个"读取计数"显示框,一个"通讯状态"指示灯。操作工能直接看到当前托盘是什么车型,维护人员也能直观看到通讯是否正常。
最终验证我跑了三轮测试。第一轮,同一个标签静止放在读头天线下方,连续读100次,统计成功率。第二轮,把标签放在托盘上,让托盘以实际生产速度通过读头,看PLC能不能稳定读出EPC。第三轮,随机抽20个不同标签,每个读10次,确认不是个别标签好用、换个标签就抓瞎。实测下来,因为润滑脂、遮挡影响,第二轮会偶尔丢读,但通过状态机里的重发机制,加上工位两侧各装一个读头交叉覆盖,PLC最终读到的成功率能到99.8%以上,完全满足了装配线的防错需求。
5. 跑现场才遇到的坑:粘包、断线重连与标签读不到的排查
5.1 粘包问题:最典型的TCP自由协议翻车点
在实验室里跑单帧收发,一切正常,一到现场托盘连续过读头,PLC解析就开始乱了。这就是TCP粘包在作怪。读写器极短时间内连续读到多张标签,或者一张标签被连续触发两次,产生的两个应答帧很可能在同一批TCP报文里发出,PLC如果还是"收到一次数据就当一帧解析",就会把两帧混在一起,解析出乱七八糟的EPC。
我们的程序里做了接收缓冲和完整帧提取,粘包没有造成大问题。但我见过不少项目偷懒,直接拿"本次接收到的数据"当一帧解析,结果一到连续过料场景就翻车。TCP自由协议应用里,粘包拆包处理不是加分项,是必做项。这一条放到任何工业设备用TCP传输自定义协议都成立。
5.2 标签读取率下降:金属干涉和射频功率的取舍
现场还碰见一个"时好时坏"的问题:同一套设备在实验室测试完全正常,装到装配线工位后,标签偶尔能读出来,偶尔完全没反应。排查一圈,最后定位到天线安装位置和旁边的金属立柱。读头天线装在工位侧边,离一根金属立柱只有150mm,托盘经过时,天线发出的射频信号在金属面上反射形成驻波,场强出现不均匀的盲区,标签到了盲区里就完全读不到。
处理办法是把天线安装支架往外移,让天线边缘与最近金属面的距离拉开到300mm以上,同时调整天线角度,避免正对金属。此外还有一个容易被忽略的点:很多人以为读取距离不够就把功率调到最大,但在近距离金属环境下,功率过大反而会让多径反射互相抵消。正确做法是把功率从低往高逐级调,同时观察RSSI变化,找到一个现场最优值,而不是一味加大功率。
5.3 断线重连机制:PLC不能傻等
自由协议通信里,读写器随时可能因为断电、网线松动、交换机重启而掉线。如果PLC程序里只有一个"连接成功后一直发送接收"的流程,一旦掉线,Socket功能块会卡在那里等,程序永远等下去。所以断线重连不是可选项,是必须项。
我这边PLC的断线重连逻辑是:在S_WAIT_RESP状态启动一个500ms看门狗定时器,超时没收到完整应答,重发次数加1;连续重发3次仍失败,就认为TCP连接已经断开,主动调用SocketClose关闭句柄,清空接收缓冲,状态转到S_RECONNECT,延时2秒后重新执行SocketConnect。这样读写器恢复供电后,最多2到3秒PLC就能自动恢复连接,不需要人工重启,也不需要按复位按钮。这套机制运行半年里救了好几次现场,车间偶尔有电柜开关跳闸,恢复供电后系统自己把通讯拉起来了,操作工甚至都没注意到发生过断电。
5.4 数据"时好时坏"的排查顺序
最后把这种"时好时坏"问题的排查顺序总结一下。这个顺序是按实际经验排的,照着走能最快缩小范围。
第一步,先用电脑连读写器发命令,看电脑上读标签是不是完全正常。如果电脑上也是时好时坏,问题基本在射频侧,比如天线的位置、标签质量、现场干扰,这时候改PLC程序没有任何意义。
第二步,如果电脑上正常,PLC上不正常,开Wireshark抓包,看PLC发出命令后读写器到底有没有回包。有回包但解析失败,把回包字节贴到CRC计算器里验证,确认CRC算法和校验范围是否和读写器固件约定一致。
第三步,确认CRC没问题后,检查报文里的长度字段。长度是单字节还是双字节、高字节在前还是低字节在前,不同设备习惯不同,很多"能解析但永远错位"的问题就出在这个字段上。
第四步,检查接收缓冲的完整帧提取逻辑。连续运行时特别要留意是否出现粘包后把两帧混成一场的情况,这属于代码逻辑层面的问题,通过单步跟踪能查出来。
第五步,查现场干扰。把天线附近的大功率电缆、变频器出线、伺服电机动力线整理走线,必要时换屏蔽双绞线和SMA屏蔽馈线,并确认接地没有形成地环路。
按这个顺序排查,半小时内能定位九成以上的自由协议通信问题。整个过程中最忌讳的是问题一出现就先怀疑PLC程序,反复改代码却不抓包,最后发现是网线头松了或者IP网段不一致,白白浪费几个小时。
整套方案讲到这里基本完整了。这套"CK-LR08-E00读写器+汇川AM401+以太网TCP/IP自由协议"的组合在我手上已经稳定运行半年多,中间除了偶发断线重连和一次网线插头松动,几乎没出过问题。如果让我给一句总结性的建议,那就是:动手写PLC程序之前,先把报文格式和CRC校验在电脑端验证清楚,联调会顺利得多;通信程序里连接管理、超时重发、断线重连三件事一定要做成状态机,不要用一路到底的线性逻辑。希望这篇实例能帮你少踩几个坑。