☰
工业互联网集成应用:PLC与RFID标识解析及平台接入实战
2026/11/4 16:38:54 网站建设 项目流程

简介:这份 PDF 样题面向备战工业互联网集成应用赛项的高职师生,也可供智能制造、工业互联网相关课程实训参考。内容围绕竞赛须知、职业素养与安全规范、竞赛任务及模块一设备安装调试展开,包含加盖拧盖与智能物流单元的工作流程、RFID 读写器安装接线、设备 IP 地址分配、PLC 与 RFID 通讯编程要求,以及截图提交和现场核验要点,便于读者理解赛题结构、梳理任务边界与评分关注点。资源包共 1 个 PDF 文件,约 360KB,轻量便携,适合打印或平板上查阅。已有 274 人学习,可作为赛前熟悉题型、教师命题转化和实训任务拆解的参考材料。

1. 从一份赛题样卷说起:它其实是份没写完的需求规格书

把“工业互联网集成应用”这几个字挂在嘴边的项目不少,但真正能拿出完整一条“制造 + 互联网”链路的样本不多,这份高职技能大赛样题算一个。多数人拿到 PDF 的第一反应是打印出来划重点、背流程、数分值,我第一遍也是这么干的,结果发现背下来的东西一到设备旁就散架——因为里面写的是任务,不是实现。

换个读法就不一样了:把它当成甲方丢过来的需求规格说明书。加盖拧盖单元要干什么、智能物流单元按什么规则分区、平台的三种状态怎么互相约束、哪些数据必须落到指定变量和指定 DB 地址,这些全是接口约束,只不过没配时序图,得自己补。适合两类人:手里有类似工作站但程序是半成品,想找一条能落地的通讯链路;或者没有硬件,想照着把 PLC 侧和平台侧的骨架搭出来跑通逻辑。

2. 系统全景拆解:两个单元、三层网络与一份 U 盘资料目录

这套工作站是典型的小型离散制造产线缩微版,从物料瓶投料到成品入仓全程自动,中间夹着标识解析和数据上云。拆之前先把“有哪些东西”列清楚,不然后面看任务书会觉得任务 1-1 到 2-3 是散的。

2.1 两个单元的职责边界与物理动作链

加盖拧盖单元负责“让瓶子变成合格品”。物料瓶由人放到输送带始端,输送到加盖机构下方,加盖定位机构先把瓶身固定死,加盖机构再动作:伸缩气缸推出、升降气缸下压,把盖子压到瓶口;完成后继续往拧盖机构送,拧盖定位机构重复一遍固定动作,拧盖电机带动夹爪旋转把盖拧紧。整个过程依赖六个位置信号——加盖前限、加盖后限、加盖上限、加盖下限、加盖定位后限、拧盖定位后限,少一个到位信号,动作链就卡死在那里不动。

智能物流单元负责“把合格品按规则放好”。分拣 A 位、B 位是两条短输送带对应的推料工位,搬运机构是伺服带动的三轴机构(左右、前后、上下都有原点与限位),负责把瓶子抓起来送进 3 号平面存储仓。容量上有硬约束:1 号存储区最多 4 个成品,2 号存储区最多 4 个成品,3 号存储区最多 6 个成品。这个容量表在写分拣逻辑时非常关键,很多人只盯着分配规则算序号,忘了区域满了要挡住,结果瓶子在输送带上撞成一排。

分配管理有单机和联机两套规则,这是容易看漏的地方。单机模式下,统计进入物流单元的累计瓶数 n,按 6 为周期循环:n 对 6 取模后落在 1、2 的进 3 号仓,落在 3、4 的进 2 号输送带,落在 5、0 的进 1 号输送带。也就是 1、2 号瓶进 3 号仓,3、4 号进 2 号区,5、6 号进 1 号区,7、8 号回到 3 号仓,9、10 号回到 2 号区,如此类推。联机模式则简化成:全部放 1 号区,1 号区满 4 个就提示人工取走。两套规则的存在意味着 PLC 里得有一个模式位来切分支,否则联机跑起来会一直往三个区乱丢。

投料前还有两条现场操作要求:物料瓶必须贴 RFID 标签,放置时别误碰输送带始端的传感器;启动智能物流单元之前,1、2、3 号存储区必须清空。这两条看着像废话,实际是最常见的翻车源——瓶子上没标签,RFID 读出来全是空,程序判 16#C8 失败一直重试;存储区没清空,累计计数从 4 开始算,第一批瓶子直接全进 2 号区。

2.2 U 盘“参考资料”的目录结构决定了你少走多少弯路

任务书里反复出现“见 U 盘中参考资料文件夹”,这句话不是免责声明,是索引。按任务 1-1 里给的路径写法,参考资料的组织方式大致是这样一套结构:

参考资料/ ├── 01_RFID读写器/ │ ├── 读写器说明书.pdf │ ├── 通讯协议与命令字.pdf │ └── 示例报文.txt ├── 02_智能阀岛与智能IO/ │ ├── GSD文件/ # 组态用的设备描述文件 │ └── IO模块接线与地址说明.pdf ├── 03_伺服驱动器/ │ └── 参数手册.pdf ├── 04_单元参考程序/ │ ├── 加盖拧盖单元_参考程序.ap** # 已含控制逻辑与平台对接 │ └── 智能物流单元_参考程序.ap** └── 05_模块二资料/ ├── 设备属性与点位表.xlsx └── 平台操作手册.pdf

这个结构的价值在于任务和资料是一一对应的:做 1-1 只翻 01 和 04,做 1-2 只翻 02 和 04,做 1-3 要 02、03、04 三份一起看,模块二只翻 05。四小时里最贵的成本是翻文件夹,先把这套结构在脑子里建起来,比多背两页协议有用。

提示:GSD 文件如果版本对不上,组态里设备会显示成灰色问号,网络参数一个都填不进去。动手前先确认 GSD 的版本号和实物模块外壳上的订货号一致。

2.3 三层网络拓扑与 IP 地址规划

整个系统的通讯是三层:现场设备层(PLC 与智能 IO、伺服、RFID 读写头)、单元互联层(两个单元 PLC 之间、PLC 与平台网关之间)、平台应用层(网关北向对接平台)。地址规划在任务书里给得很死,照着填就行,别自作主张改网段。

所属单元设备IP 地址备注
加盖拧盖PLC192.168.1.21主站,跑控制逻辑
加盖拧盖智能阀岛 / 智能 IO192.168.1.22设备名 pn-dev2
加盖拧盖RFID 读写头192.168.1.24端口 9000
智能物流PLC192.168.1.51主站
智能物流RFID 读写头192.168.1.54端口 9000
平台侧工业互联网平台192.168.1.100:30000Web 入口

两个单元各自一个网段前缀相同的子网,中间靠交换机串起来,再由其中一台 PLC 或独立网关往上走。RFID 读写头走的是以太网通讯而不是串口,端口 9000 是它对外暴露的固定服务端口,这一点很关键:调试阶段可以用电脑直连读写头,先确认 9000 端口能通,再去查 PLC 侧的收发程序,能把问题范围砍掉一半。常见做法是先 ping 通、再用 TCP 工具发一帧手工报文,能收到回包就说明读写头和标签都没问题,剩下的全是 PLC 里的程序问题。

平台的三种状态约束是跨单元的:停止状态下只能执行复位,复位状态下才能执行停止或启动,启动状态下平台只能下达一个生产订单,订单执行完必须重新启动才能接下一单。这个状态机不是 PLC 单方面实现的,PLC 和平台两边都得维护一份,任何一边跳步,平台会拒绝下发或者设备收到指令后不动作。

3. 标识解析链路:PLC 与 RFID 读写器的收发状态机怎么写

标识解析是这套系统里真正带“互联网”味道的一段:瓶子上的 RFID 标签是物理世界的身份,读写器把它变成字节流,PLC 把字节流塞进指定 DB,平台再把 DB 里的点位采上去。链条不长,但每一环都有硬性约定。

3.1 读写器接线与 9000 端口背后的通讯前提

接线按布局图和网络接线图走:读写头的电源、网口、以及和 PLC 之间的信号线(如果走硬线触发)都要接对。真正容易出问题的是网络这一层——读写头出厂默认 IP 未必是 192.168.1.24,得先用配置软件改成表里的地址,改完再确认端口 9000 处于监听状态。

调试顺序上,我一般按这个次序推进,每一步都能独立验证:

  1. 电脑改到同网段,ping 192.168.1.24 通,说明物理链路和 IP 配置没问题。
  2. 用 TCP 客户端连 192.168.1.24:9000,能建立连接,说明服务在跑。
  3. 手工发一帧读标签命令,收到首字节 16#C5 的回包,说明标签在读取范围内、协议对得上。
  4. 以上三步都过了,才动 PLC 程序;任何一步没过,先解决那一步。

第四步之前的所有动作都是纯网络调试,跟 PLC 程序无关。跳过前三步直接改程序,最后报错时你分不清是程序写错了还是读写头根本没响应,只能一遍遍瞎改。

3.2 发送与接收缓冲区:为什么是 72 个字节

任务书里给的两个变量定义很明确:"RFID 数据".发送和"RFID 数据".接收,类型都是Array[0..71] of Byte,接收区落在DB1.DBX0.0。72 个字节不是随便定的,它是这套读写器一帧报文的最大长度:命令头、站号、起始地址、长度、数据区、校验位全算进去,定长传输比变长好处理,收发两端不用协商长度,直接按 72 切。

// 全局数据块 DB1 中的定义(非优化访问,保证绝对地址可用) DATA_BLOCK "RFID 数据" { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 NON_RETAIN STRUCT "发送" : Array[0..71] of Byte; // 起始地址 DB1.DBX72.0 "接收" : Array[0..71] of Byte; // 任务书要求落在 DB1.DBX0.0 END_STRUCT; BEGIN END_DATA_BLOCK

这里有个顺序细节:任务书要求接收区在DB1.DBX0.0,那就得让“接收”结构体排在“发送”前面,否则偏移全错。启用“优化的块访问”后,绝对地址会失效,DB1.DBX0.0 这种写法编译直接报错,所以这个 DB 必须关掉优化访问。很多人是从新建 DB 开始做的,默认优化访问是开着的,编译报错后到处找原因,其实是块属性里一个勾。

定长还有个附带好处:接收区可以直接整块送进平台点位,不用做长度判断。平台侧按byte_array、长度 72 建一个点位,采上来就是一串十六进制,前几个字节就是命令字和状态码。

3.3 “RFID” 函数的六步状态机

任务书里给了一段流程描述,a 到 f 六个步骤,写得很“人话”,但翻译成 PLC 代码时需要落成状态机,不能写成六个串联的 IF。串联 IF 的问题是每个扫描周期都会从头执行一遍,发送和接收这种耗时的异步动作会被反复触发。

FUNCTION_BLOCK "FB_RFID_Read" VAR step : Int; // 0 空闲 1 组帧 2 发送 3 判发送 4 接收 5 判结果 6 收尾 retry : Int; // 重试计数,上限 3 次 sendBuf : Array[0..71] of Byte; // 与 "RFID 数据".发送 同构 recvBuf : Array[0..71] of Byte; // 与 "RFID 数据".接收 同构 END_VAR VAR_INPUT trigger : Bool; // M21.1 触发读取标签 reset : Bool; // 复位,回到 step 0 END_VAR VAR_OUTPUT done : Bool; // M20.5 读取标签成功 busy : Bool; error : Bool; END_VAR VAR_TEMP i : Int; END_VAR BEGIN // 复位优先,任何时刻拉高都回到空闲 IF reset THEN step := 0; retry := 0; busy := FALSE; error := FALSE; END_IF; // 上升沿进入:trigger 为真且当前空闲 IF trigger AND NOT busy AND NOT done THEN step := 1; retry := 0; busy := TRUE; done := FALSE; error := FALSE; END_IF; CASE step OF 0: ; // 空闲,什么都不做 1: // 组帧:命令字 + 站号 + 起始块 + 读取长度 sendBuf[0] := 16#01; // 读标签命令 sendBuf[1] := 16#00; // 读写头站号,按现场拨码修改 sendBuf[2] := 16#00; // 起始块地址高字节 sendBuf[3] := 16#00; // 起始块地址低字节 sendBuf[4] := 16#04; // 读取长度:4 字节 EPC sendBuf[5] := 16#00; FOR #i := 6 TO 71 DO sendBuf[#i] := 16#00; // 补零到定长 72 END_FOR; "RFID 数据".发送 := sendBuf; "标签读取延时" := FALSE; // M21.5 清延时标志 step := 2; 2: // 发送:置发送请求,等 sendDone 回来 #sendReq := TRUE; step := 3; 3: // 判发送结果 IF #sendDone THEN #sendReq := FALSE; step := 4; ELSIF #sendErr THEN #sendReq := FALSE; retry := retry + 1; IF retry > 3 THEN error := TRUE; busy := FALSE; step := 0; ELSE step := 2; // 回第 2 步重发 END_IF; END_IF; 4: // 接收:把 72 字节回包整块写入 "RFID 数据".接收 #recvReq := TRUE; IF #recvDone THEN "RFID 数据".接收 := recvBuf; #recvReq := FALSE; step := 5; ELSIF #recvTimeout THEN // 看门狗超时按失败处理 #recvReq := FALSE; retry := retry + 1; step := 2; END_IF; 5: // 判结果:16#C5 成功,16#C8 失败 IF "RFID 数据".接收[0] = 16#C5 THEN step := 6; ELSIF "RFID 数据".接收[0] = 16#C8 THEN retry := retry + 1; IF retry > 3 THEN error := TRUE; busy := FALSE; step := 0; ELSE step := 2; END_IF; END_IF; 6: // 收尾:置成功标志与延时标志,交出控制权 "读取标签成功" := TRUE; // M20.5 "标签读取延时" := TRUE; // M21.5 busy := FALSE; done := TRUE; step := 0; END_CASE; END_FUNCTION_BLOCK

逐块说清楚。step是整段逻辑的骨架,六个状态对应任务书 a 到 f,任何一次跳转都必须把step显式改掉,绝不靠自然顺序往下滑。retry是保命的,没有它,一个读不到的标签会让程序在 2→3→2 之间死循环,扫描周期被撑爆,其他动作全部停摆;到 3 次就认输、置error退出,让上游去决定是报警还是跳过这个瓶子。

sendBuf和recvBuf设计成块内静态变量而不是直接读写 DB,多了一层拷贝,但换来的是组帧过程不受外部干扰——如果一边组帧一边有别的逻辑改"RFID 数据".发送,发出去的报文就是半新半旧的。组帧完一次性赋值,语义干净。

第 4 步的recvTimeout是看门狗,读写头正常回包在几十毫秒内,超过 500 毫秒基本就是掉线或标签不在场,不能无限等。这个信号在块外用一个 TON 定时器做:#recvReq为真时启动,到时置位超时标志;#recvReq变假立刻复位定时器。

注意:任务书里给的是“函数”(FC),FC 没有静态变量,step和retry存不住。实际工程里我一般写成 FB 配一个背景 DB;如果非要用题目给的那个 FC,就把step、retry全部换成 M 区或 DB 里的静态位,别写在 TEMP 里——临时变量每个扫描周期都重新分配,状态机根本跑不起来。

3.4 16#C5 与 16#C8:判结果为什么要看首字节

读写器的回包是定长 72 字节,第一个字节是状态码,16#C5表示本次读写成功,16#C8表示失败。判结果只看"RFID 数据".接收[0],不看长度、不看校验,这是协议本身的设计——长度固定,校验位在读写器内部已经做过一遍。

这条规则有个副作用:如果程序没收到完整回包,接收[0]里留着的是上一帧的旧数据,很可能是16#C5,于是失败被误判成成功。这就是为什么第 4 步一定要有超时看门狗,并且接收必须整块覆盖——"RFID 数据".接收 := recvBuf这一句是整块赋值,不是逐字节写,只要recvDone为真,72 个字节一起换掉,不会出现半新半旧。

读写成功之后M20.5置位,这个位是跟主流程的握手信号。加盖拧盖单元的主流程在“取标签数据”节点上等这个位,等到了就去读 DB 里的 EPC,读完了把M20.5复位,然后走下一个动作。这中间如果M21.5(标签读取延时)没被正确复位,下一次触发会被误判成同一个标签的重复读取,所以流程里第 1 步专门把M21.5清零。

4. 数据采集与平台接入:从智能 IO 组态到数字化建模与告警规则

模块一的后两个任务和模块二,本质是同一件事的两端:设备侧把信号变成可寻址的地址,平台侧把地址变成带语义的点位。中间任何一段接不上,大屏上就是一片灰。

4.1 地址分配表怎么落成真实的 IO 映射

任务书里的地址表有个特别容易被忽略的细节:硬件接线和软件地址不是一一对应的。加盖拧盖单元的表里,硬件端子I0:0对应软件地址I2.0,I0:1对应I2.1,一路顺延到I1:1对应I3.1;输出侧Q0:0对应Q2.0,Q1:4对应Q4.4。

硬件接线软件地址功能描述
I0:0I2.0瓶盖料筒检测
I0:1I2.1加盖位检测
I0:2I2.2拧盖位检测
I0:3I2.3加盖前限
I0:5I2.5加盖上限
I1:0I3.0拧盖定位后限
Q0:0Q2.0输送带电机
Q1:0Q4.0加盖伸缩气缸

这个偏移不是笔误,是模块化 IO 的槽位预留:CPU 后面挂了通讯模块或占位模块,前面的字节被占掉,实际 IO 从 I2 开始。写程序时如果照着硬件端子号写I0.0,编译能过、下载能跑,但那个地址上没有任何物理信号,表现为“程序里所有到位检测永远是 0,设备一动不动的黑匣子状态”。我见过有人在这上面耗掉四十分钟,最后发现是地址差了两个字节。

正确做法是把这张表原样录进 PLC 的变量表,用符号名编程,程序里只出现"加盖位检测"这种名字,不出现绝对地址。这样即使后面地址再变,改一处变量表就行。智能物流单元的表同理,X100、Y100这种写法说明那个单元的 IO 是按另一套寻址方式编的,混合编程时两套地址不能互相套用。

4.2 组态、网络参数、IO 地址三段配置

智能阀岛/智能 IO 的接入分三段,顺序不能反:

第一段是组态。在编程软件里导入 GSD 文件,把设备拖到网络视图上,跟 PLC 连到同一根总线。这一步做完,设备会出现在硬件目录下,但还没有名字。

第二段是网络参数。给设备分配设备名pn-dev2和 IP 地址 192.168.1.22。设备名比 IP 更重要——PROFINET 靠设备名寻址,名字对不上,IP 填得再对也连不通。分配完名字后,设备上的指示灯通常会从闪烁变成常亮,这是最直观的成功信号。

第三段是 IO 地址。把模块的输入输出字节映射到 PLC 的地址区,也就是 4.1 那张表的来源。这一段做完,编好的程序里那些符号名才有实际落点。

// 用符号名访问,避免绝对地址偏移带来的误判 "输送带电机" := "启动" AND NOT "停止" AND NOT "急停"; "加盖伸缩气缸" := "加盖位检测" AND "加盖前限" AND "加盖上限"; // 拧盖动作:定位到位 + 上限到位才允许启动电机 IF "拧盖定位后限" AND "拧盖上限" THEN "拧盖电机" := TRUE; END_IF;

这段短逻辑比长代码更值得看:所有条件都用符号名表达,可读性直接决定四小时后你还改不改得动。"急停"放在输出条件里做串联,是最后一道硬保护,任何输出都得先过它。

智能物流单元那边还多一个伺服驱动器,接线按图 1-2 和图 1-4 走,参数配置的重点是原点回归方式和左右、前后、上下三组限位的逻辑电平,限位接反了会出现“一上电就往一个方向顶死”的经典场面。

4.3 平台侧:模型、设备、点位、北向的四级创建顺序

平台地址是 192.168.1.100:30000,登录信息在任务书里给出。模块二任务 2-1 列的六项提交内容,其实是四级对象的创建顺序:

先建网关模型和设备模型,把“加盖拧盖单元”和“智能物流单元”抽象成两类模型;再给模型做功能定义,也就是属性列表——瓶盖料筒检测、加盖位检测这些开关量,加上累计计数、订单数量这类数值量;然后基于模型创建设备实例,一个模型可以建多个设备;最后在网关里配 PLC 连接、子设备、点位和通讯参数,导出的点位表就是南北向打通的凭证。

网关导出的点位结构大致长这样,字段名各平台不同,但语义一致:

{ "gateway": "gw-press-01", "protocol": "S7", "plcIp": "192.168.1.21", "points": [ {"name": "rfid_recv", "addr": "DB1.DBX0.0", "type": "byte_array", "len": 72, "desc": "RFID 接收缓冲区"}, {"name": "cap_pos", "addr": "I2.1", "type": "bool", "desc": "加盖位检测"}, {"name": "conveyor", "addr": "Q2.0", "type": "bool", "desc": "输送带电机"} ] }

byte_array这种类型在多数平台上是支持的,但要注意字节序和长度,导出的长度如果写成默认 8,采上来的就是前 8 个字节,看不到完整 EPC。北向配置是平台对上层应用暴露的出口,配完之后设备监控页面才能拿到数据,这一步的顺序是“先南向通、再北向配”,反过来配完发现南向没通,大屏上全是空值,又得回头查。

4.4 三指令下发与 1 秒延时:生产排程的时序约束

任务 2-2 的订单是 5 瓶钙片、每瓶 2 粒,分三批做,第一批 60%,也就是 3 瓶。可视化页面上点预览、远程启动、绑定点位,这些都是操作层面的,真正容易翻车的是指令下发方式。

任务书里写得很明确:下发控制指令时一个动作要发 3 个指令,比如开机要设定“停机=0、复位=0、开机=1”,值为 1 的指令放在最后,三个指令之间需要延时 1 秒。这是一个典型的三段式状态复位——先把可能残留的状态位清零,再置位目标状态。少发一条,设备可能停在“既没停机也没开机”的中间态;顺序发反,先置开机再清停机,设备收到开机命令后立刻又被清掉,表现为按了没反应。

import time, requests BASE = "http://192.168.1.100:30000/api/v1" DEV = "press_unit_01" def post_cmd(stop: int, reset: int, start: int): """按 停机 -> 复位 -> 开机 的顺序下发,值为 1 的放最后""" payload = {"cmdList": [ {"attr": "stop", "value": stop}, {"attr": "reset", "value": reset}, {"attr": "start", "value": start}, ]} r = requests.post(f"{BASE}/device/{DEV}/command", json=payload, timeout=3) r.raise_for_status() return r.json() # 开机:先清停机位,间隔 1 秒,再清复位位,最后置开机 post_cmd(0, 0, 0); time.sleep(1) post_cmd(0, 0, 1)

这段脚本是课下自测用的,赛场上直接在平台可视化页面点也可以,但把请求写成脚本有个好处:能精确控制 1 秒间隔,也能批量重放,排查“点了没反应”时到底是平台没发出去还是设备没收到。timeout=3别省,平台在订单执行期间响应会变慢,不设超时脚本会一直挂着。

对应的状态机约束是:设备处于停止状态才能复位,处于复位状态才能启动或停止,启动状态只能接一个订单,做完必须重新启动才能接下一单。写脚本批量下发前先查一次当前状态,别默认它是复位态。

4.5 告警规则:40 度二级高温与 8 级停机告警

任务 2-3 要建两条规则。第一条是温度超过 40 度触发二级高温报警,这是标准的阈值规则,比较符用大于而不是大于等于,写错一个符号就会出现“刚好 40 度时报警”还是“41 度才报警”的差别,测试用例里得专门覆盖边界值。

第二条是加盖拧盖单元未完成订单且停止生产时,产生 8 级、类型为“其它”的告警。这条的难点在“未完成订单且停止生产”这个复合条件——它同时依赖订单进度和设备状态两个数据源,如果点位建模时没把“订单剩余数量”和“运行状态”定义成可比较的数值和枚举,规则里根本选不出来。所以在 4.3 那一步做模型功能定义时,就得提前想好后面要建什么规则,把字段留出来。

规则建完务必用一次真实停机去验证:下发一个订单,跑到一半手动停设备,看告警有没有在规定级别上冒出来。只在页面上看着规则是“已启用”不算数。

5. 避坑与排查:赛场上最容易翻车的五个点

下面五条都是能直接对号入座的,现象—原因—解决按顺序写,遇到时照单抓药就行。

5.1 接线与组态类

现象一:智能 IO 组态里设备显示为灰色问号,网络参数一栏全部不可编辑。

原因通常是 GSD 文件版本和实物模块的固件版本不匹配,或者导入的是另一型号的 GSD。解决方式是先看模块外壳上的订货号,回参考资料文件夹找订货号完全一致的那份 GSD 重新导入;找不到就换用通用 GSD,但要注意通用 GSD 下部分诊断功能会失效。导入后如果还是灰色,把设备从网络视图删掉重新拖一次,别在原地改。

现象二:设备名已分配,指示灯也常亮了,但 PLC 侧读不到任何 IO。

多半是 IO 地址段的映射没做,或者映射到了 PLC 已经被占用的地址区。这种情况编译能通过,下载也不报错,只是数据一直是 0。解决方式是打开设备视图核对输入输出起始地址,和 4.1 那张软件地址表逐个对一遍,特别注意那个 I2/Q2 的偏移。对完之后在线监控一下,用手挡一下传感器看 I2.1 有没有翻转,没有翻转就是地址还是错的。

5.2 程序与通讯类

现象三:RFID 程序一直停在发送/接收循环,扫描周期肉眼可见地变长,其他动作全部卡住。

原因是状态机缺重试上限或者缺接收超时,读写头没回包时程序在 2→3→2 之间无限打转。解决方式是补上retry计数器,到 3 次就置错误标志退出;同时在接收步骤挂一个 500 毫秒的 TON 看门狗,超时按失败走。补完之后还要检查是不是标签本身不在读取范围内——瓶子放偏了几厘米,读写头就是读不到,程序再健壮也没用。

现象四:读回来的标签数据是对的,但主流程拿不到,M20.5一直不置位。

原因通常是判结果的字节位置搞错了,或者接收区没落在DB1.DBX0.0。任务书要求接收区在这个绝对地址上,如果 DB 开着优化访问,地址对不上,程序里读的是另一块内存,首字节永远不是16#C5。解决方式是检查 DB 的块属性,把“优化的块访问”取消勾选,重新编译下载;再看一眼"RFID 数据".接收[0]在线值,手工触发一次读标签,看它是不是变成16#C5。

5.3 平台与提交类

现象五:可视化页面绑定完点位,预览时数据不刷新,但网关日志显示采集正常。

原因一般是北向配置没做或者做在了南向之前,平台应用层拿不到网关推送的数据;也可能是可视化页面绑的是模型属性,而设备实例上那个属性没被赋值。解决顺序是先确认网关南向点位在线值有变化,再确认北向出口已启用,最后回可视化页面重新绑定一次并保存。另外提交流程上有硬要求:所有截图要放进 U 盘指定文件夹,程序和答案存到“技能竞赛\竞赛编号”目录下,没存到指定位置的运行记录一律不给分——我见过功能全做完、分数丢在保存路径上的。

6. 二次开发:把样题改造成可自测的实训工程

这份样题最大的复用价值不在“照着做一遍”,而在它把一条完整链路拆成了可验证的六段。想拿它做二次开发,我建议按“抽骨架、换参数、加断言”三步走。

抽骨架:把第 3 章那个 RFID 状态机独立成一个 FB,输入只留trigger、reset,输出只留done、busy、error,内部所有"RFID 数据"的引用改成接口参数。这样它就不再绑死在这套设备上,任何走 TCP 定长报文的读写器都能套进去,只改组帧那一段的字节布局。分拣规则同理,把那个MOD 6的循环抽成一张映射表:

累计瓶数 n(n-1) mod 6目标区容量上限
1、20、13 号平面仓6
3、42、32 号输送带4
5、64、51 号输送带4

表驱动的好处是规则一变只改表,不改代码。比如把周期从 6 改成 8,或者把 1 号区容量从 4 改成 3,都只是数据层面的调整。

换参数:把所有 IP、端口、DB 号、设备名集中到一个配置 DB 或一份 JSON 里,程序里只引用符号。这一步做完,同一套程序可以同时适用于两个单元的 PLC,只是加载不同的配置。

加断言:这是最值得投入的一步。给状态机写几个可自动跑的测试场景——标签不在场、读写头掉线、回包首字节是16#C8、回包超时——每个场景都期望程序在规定时间内退到error而不是卡死。没有硬件也能测:用一个 Python 脚本起个 TCP 服务端模拟读写头,按不同分支返回不同报文,PLC 侧或者上位机侧跑状态机,看它是不是每次都按预期退出。这套脚本写一次,后面所有改造都能复用。

import socket # 模拟读写头:按请求次数切换返回分支,验证状态机的异常处理 MODES = [b"\xC5" + b"\x00" * 71, # 成功 b"\xC8" + b"\x00" * 71, # 失败 None] # None 表示不回包,触发超时 with socket.socket() as s: s.bind(("0.0.0.0", 9000)) s.listen(1) for mode in MODES: conn, _ = s.accept() conn.recv(72) # 收下 PLC 发来的 72 字节请求 if mode: conn.sendall(mode) conn.close()

这个模拟器的价值在于把“读写头”这个不可控因素从测试里摘出去,剩下的问题全在你自己的代码里。MODES列表顺序就是三条分支的执行顺序,跑完一轮看状态机的三个出口是不是都被覆盖到。

提示:模拟器绑的是 9000 端口,跑之前确认本机没有别的服务占着这个端口,否则bind直接抛异常。

从那以后我每次接手这类多单元联动的赛题或者实训台,都强制先走一遍“纯网络验证 → 单点 IO 验证 → 状态机空跑 → 联机”四步,宁可前面多花二十分钟,也不要在四小时的最后半小时里对着一堆不确定的中间态猜是哪一层出的问题。这套顺序不新鲜,但真能省下后悔药。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询