简介:面向自动化、西门子PLC及TIA Portal学习者,这份Sicar标准程序培训包以培训演示工程为主体,围绕标准程序的组织方式、设备组态与项目文件结构展开,适合需要理解Sicar工程范式、对照复现Demo或积累项目目录管理经验的初中级工程师。压缩包共106个文件,约38.19MB,主要由xml与ini配置文件、bmp/png设备图标、cfs/dat等工程数据以及ico、xsl等辅助资源构成,可覆盖组态素材、参数说明和工程文件等多类内容。目前已有654人学习,说明其在Sicar培训场景中具有一定参考价值。读者可从中获得较完整的培训演示工程样本,观察标准程序的模块划分与文件组织,结合设备图标和配置数据理解组态关系,为后续项目搭建、文件替换与问题排查提供可对照的素材与思路。
1. 从“换个人就改不动”说起:Sicar 标准程序 V16 到底给的是什么
接手一条车身车间的工位程序,最难受的不是不会写逻辑,而是每个人写的逻辑都不一样:气缸复位条件五花八门,机器人握手信号随手加一个,调机时全靠在梯形图里翻来翻去猜。Sicar 标准程序 V16 就是冲这事来的。它提供的是一副骨架:工位自动流程、设备标准块、报警诊断、HMI 交互都按一套固定规范铺好,具体动作还得你自己填。这套东西更适合已经在做产线集成、被“一人一套写法”折磨过的 PLC 工程师,或者刚进项目组、需要快速看懂别人程序的新手;想拿它当入门教程的人会失望,因为它默认你已经知道气缸怎么控制、机器人怎么握手。下面按我拆包的顺序讲:架构怎么分层、块怎么调、怎么在仿真里跑通、哪儿容易出问题、最后怎么改成自己的工位。
2. 架构与技术选型:这套程序“标准”在分层,不在功能
2.1 标准程序的核心诉求是“换人也能接着改”
普通工位程序的写法是“把这条线的动作写完就行”,标准程序的写法是“把动作拆成可复用的块,再规定谁能调谁”。Sicar 这套模板里,一个工位程序由四部分组成:设备标准块库(气缸、夹紧、输送、机器人握手、报警)、工位模板(自动步序、手动模式、维护模式)、全局数据区(按工位分块,接口用 UDT 定义)、诊断层(报警字打包 + HMI 面板)。真正落地的产线里,功能代码只占三成,剩下七成是接口约定和诊断。
这么设计的好处很直接:新工位上线,复制模板、改编号、挂设备实例,两天能出第一个可调试版本;坏处也明显,模板约束强,你想写点“灵活”的东西,往往要绕开规范,后面维护的人就会骂人。我一般建议团队先忍住,把标准块用满三个月再谈改造。
2.2 五层调用架构:一条线是怎么被拆开的
从顶层往下,调用链是固定的五层,每一层只认下一层的接口:
| 层级 | 典型块 | 职责 | 不允许做的事 |
|---|---|---|---|
| 线体层 | FB_LineCall | 汇总各区域状态、线体启停、上下游联锁 | 直接操作设备输出 |
| 区域层 | FB_ZoneCall | 区域互锁、区域内机器人通行权 | 写具体工位步序 |
| 工位层 | FB_Station_ST010 | 自动步序、模式切换、工位报警汇总 | 直接写电磁阀线圈 |
| 设备层 | FB_Cylinder / FB_RobotHandshake | 单个设备的动作、超时、故障判定 | 跨工位取信号 |
| 执行层 | 输出映射 FC | 把设备块输出送到物理地址 | 写任何逻辑判断 |
关键约束在最后一列。设备块只输出“我要伸出”这种意图,映射到物理地址由最底层的映射 FC 统一做,这样换 IO 模块、改地址,只动一个地方。跨工位取信号也是硬性禁止的,需要上游工位给信号,就走区域层的公共 DB,不然三个月后你根本查不出这个变量是谁写的。
2.3 技术栈与工程文件构成
这套模板跑在中型 PLC 上,编程平台是 V16 版本,语言混用:步序用顺序功能图或 SCL 的 CASE 状态机,设备块用 SCL,少量安全相关和现场调试用的逻辑保留梯形图。通信走工业以太网,机器人和 PLC 之间是硬线信号 + 网络心跳双保险。工程归档下来大致是这么几类东西:
| 内容 | 说明 | 上手注意 |
|---|---|---|
| 主工程归档包 | 含全部程序块、硬件组态、HMI 工程 | 归档包解出来才是可编辑工程,别直接改归档 |
| 标准块库 | 独立库文件,含版本号 | 库版本与平台版本是两条线,不能混着升 |
| HMI 面板工程 | 面板模板 + 变量连接 | 面板和 PLC 的 UDT 必须同版本 |
| 变量与监控表 | 按工位分组的监控表 | 调试时全靠它定位卡在哪一步 |
| 文档 | 块说明、编号规则、报警码表 | 报警码表不看,报警出来你只能猜 |
我一般先把库文件和主工程分开存放,库只在需要升级时动,主工程随便改。混在一起放的后果是,某天你想回退一个工位,发现库也被顺手改了,全线下不来台。
2.4 版本号 V16 的两条线:平台版本和库版本
V16 这个号容易让人误解,以为升到 V16 就什么都新。实际上有两套版本:编程平台的版本(决定你能打开什么工程、用哪些指令)和标准块库的版本(决定块接口长什么样)。平台升级相对安全,库升级是要命的事——库里的 FB 接口一改,所有调用它的工位实例都得重新编译,输入输出对不上就报错。
常见做法是维护一张兼容表:库版本、平台版本、HMI 面板版本三列,每上线一个新工位记一行。血泪经验是,别在生产线上直接升库,先在离线工程里全编译一遍,看有多少个实例报错,再决定是升级还是把新功能做成新块另起名字。
3. 核心模块拆解:气缸块、机器人握手、报警链怎么写
3.1 设备标准块 FB_Cylinder:五状态机加超时监控
气缸是所有工位里出现次数最多的设备,也是写乱最多的地方。标准块的思路是把一个气缸抽象成五步:空闲、伸出中、伸出到位、缩回中、故障。所有动作判定都靠反馈信号,不靠时间猜。下面这段是我按模板改出来的版本,逻辑和原版一致,注释按我的习惯补的:
FUNCTION_BLOCK "FB_Cylinder" VAR_INPUT xEnable : BOOL; // 工位自动步使能,掉步立即断输出 xCmdExt : BOOL; // 伸出命令,上升沿有效 xCmdRet : BOOL; // 缩回命令,上升沿有效 xFbExt : BOOL; // 伸出到位磁性开关(常开) xFbRet : BOOL; // 缩回到位磁性开关(常开) tTimeout : TIME := T#3S; // 单程超时,按缸径和行程给 xSim : BOOL; // 仿真标志:反馈跟随输出,不接实物 END_VAR VAR_OUTPUT xOutExt : BOOL; // 去阀伸出线圈 xOutRet : BOOL; // 去阀缩回线圈,单电控时恒为 FALSE xDone : BOOL; // 动作完成,只给一个扫描周期 xBusy : BOOL; xError : BOOL; iStep : INT; // 当前状态,HMI 直接显示这个数 iErrCode : INT; // 故障码,进报警字 END_VAR VAR tonMon : TON; rtExt : R_TRIG; rtRet : R_TRIG; END_VAR VAR_TEMP xFbExtEff : BOOL; xFbRetEff : BOOL; END_VAR BEGIN // 1) 仿真反馈:实物不在环时让反馈跟着上一步的输出走 xFbExtEff := xFbExt OR (xSim AND xOutExt); xFbRetEff := xFbRet OR (xSim AND xOutRet); // 2) 边沿与超时:只在“伸出中”“缩回中”两步计时 rtExt(CLK := xCmdExt); rtRet(CLK := xCmdRet); tonMon(IN := (iStep = 10) OR (iStep = 30), PT := tTimeout); xDone := FALSE; // 完成信号复位,保证是一个脉冲 CASE iStep OF 0: // 空闲:输出全断,等命令 xOutExt := FALSE; xOutRet := FALSE; xBusy := FALSE; xError := FALSE; iErrCode := 0; IF xEnable AND rtExt.Q THEN iStep := 10; ELSIF xEnable AND rtRet.Q THEN iStep := 30; END_IF; 10: // 伸出中:等伸出到位或超时 xOutExt := xEnable; xBusy := TRUE; IF xFbExtEff THEN iStep := 20; ELSIF tonMon.Q THEN iStep := 90; iErrCode := 16#0101; // 伸出超时 END_IF; 20: // 伸出到位:保持输出,反馈丢失立刻报故障 xOutExt := xEnable; xBusy := FALSE; IF NOT xFbExtEff THEN iStep := 90; iErrCode := 16#0102; // 保持中反馈丢失 ELSIF rtRet.Q THEN iStep := 30; END_IF; 30: // 缩回中 xOutRet := xEnable; xBusy := TRUE; IF xFbRetEff THEN iStep := 0; xDone := TRUE; ELSIF tonMon.Q THEN iStep := 90; iErrCode := 16#0103; // 缩回超时 END_IF; 90: // 故障:输出全断,等复位命令 xOutExt := FALSE; xOutRet := FALSE; xBusy := FALSE; xError := TRUE; IF NOT xEnable THEN // 工位复位时统一清故障 iStep := 0; END_IF; END_CASE; // 3) 双电控阀互锁,任何情况下不允许两个线圈同时得电 IF xOutExt AND xOutRet THEN xOutExt := FALSE; xOutRet := FALSE; iStep := 90; iErrCode := 16#0104; END_IF; END_FUNCTION_BLOCK参数里最需要琢磨的是tTimeout。给短了,气压稍低就报超时;给长了,真卡住时设备硬顶。我一般按“空载动作时间 × 2 + 0.5 秒”给,调试期在 HMI 上做成可改参数,稳定运行两周后再固化到程序里。
iStep这个输出别省。现场排查时,看一眼状态机停在哪一步,比在梯形图里逐行找条件快得多,尤其夜里调机,这个数字就是黑匣子。xSim也不是随便加的开关:仿真里反馈自短接能让你在不接实物的情况下跑完整个步序,但正因为如此,它也会把极性接反、常开常闭搞错这类问题全部掩盖,上机就现原形,这个坑后面单说。
xDone必须是单周期脉冲,否则下游拿到的是一个常真的信号,步序会一直往前跑。这一条是新写块最容易翻车的地方,忘记在扫描开头复位,序列就会失控。
3.2 机器人与 PLC 的六信号握手和区域互锁
机器人和 PLC 之间的信号,很多项目是“想到一个加一个”,最后变成二十几个信号,谁也说不清哪个是必须的。标准程序约束成六个:PLC 请求进入、机器人允许进入、机器人已进入、机器人作业完成、PLC 确认完成、外加一路心跳。写成状态机后,时序是确定的,谁先谁后不会乱。
FUNCTION_BLOCK "FB_RobotHandshake" VAR_INPUT xEnable : BOOL; // 工位自动 + 区域安全正常 xPlcRequest : BOOL; // PLC 请求机器人进入本工位区域 xRbtReady : BOOL; // 机器人侧“允许进入”应答 xRbtInZone : BOOL; // 机器人侧“已在本区域” xRbtDone : BOOL; // 机器人侧“作业完成” xRbtHeartbeat : BOOL; // 机器人侧 1Hz 方波 tHeartbeat : TIME := T#3S; END_VAR VAR_OUTPUT xAllowEnter : BOOL; // 允许进入,送机器人输入 xPlcAck : BOOL; // PLC 收到完成 xCommFault : BOOL; // 心跳丢失 iStep : INT; iErrCode : INT; END_VAR VAR tonHb : TON; rtDone : R_TRIG; END_VAR BEGIN // 心跳:3 秒内没有翻转就判通信故障,直接打断握手 tonHb(IN := NOT xRbtHeartbeat, PT := tHeartbeat); xCommFault := tonHb.Q; rtDone(CLK := xRbtDone); xPlcAck := FALSE; IF xCommFault THEN iStep := 90; iErrCode := 16#0201; END_IF; CASE iStep OF 0: // 等 PLC 请求 xAllowEnter := FALSE; IF xEnable AND xPlcRequest THEN iStep := 10; END_IF; 10: // 已允许,等机器人应答 xAllowEnter := TRUE; IF xRbtReady THEN iStep := 20; ELSIF NOT xEnable THEN iStep := 0; END_IF; 20: // 等机器人进入本区域 xAllowEnter := TRUE; IF xRbtInZone THEN iStep := 30; ELSIF NOT xEnable THEN iStep := 0; END_IF; 30: // 机器人作业中,PLC 侧输出全部封锁 xAllowEnter := TRUE; IF rtDone.Q THEN xPlcAck := TRUE; iStep := 40; ELSIF NOT xEnable THEN iStep := 0; END_IF; 40: // 机器人已退出,回到空闲 xAllowEnter := FALSE; IF NOT xRbtInZone THEN iStep := 0; END_IF; 90: // 通信故障,等人工复位 xAllowEnter := FALSE; IF NOT xEnable THEN iStep := 0; END_IF; END_CASE; END_FUNCTION_BLOCK时序上有两条不能省。一是第 30 步,机器人进入区域后 PLC 必须封锁本工位的动作输出,否则人和机器在同一空间里,靠“应该不会动”来保证安全迟早出事。二是心跳,很多老项目只有硬线信号,机器人程序挂了或者网络断了,PLC 那边看到的是“信号保持”,会一直等着,看上去没毛病实际已经死循环。加了心跳之后,3 秒不翻转就切故障态,所有人都知道出事了。
区域互锁在区域层做,逻辑简单但顺序不能反:
// 同一区域同时只允许一个进入请求,先到先得 "DB_Zone".xAllow_01 := "DB_Zone".xZoneFree AND "DB_Station_ST010".xRobotRequest AND NOT "DB_Station_ST020".xRobotRequest; "DB_Zone".xAllow_02 := "DB_Zone".xZoneFree AND "DB_Station_ST020".xRobotRequest AND NOT "DB_Station_ST010".xRobotRequest;这段代码看起来幼稚,但产线上的通行权问题就是这么解决的。要注意的是,xZoneFree必须由“区域内确实没有机器人和人”的条件构成,不能只看机器人自己的信号,安全门、光幕、急停这些都得并进来。谁先谁后的优先级,我一般把上游工位排前面,因为堵料比空等更麻烦。
3.3 报警与诊断:位号编码、报警字打包、HMI 映射
报警这一块写不好,现场就是灾难:报警号对不上,画面上一堆红字,操作工只能按“全部确认”。标准程序的做法是先把报警定义成结构体,再统一打包送 HMI。
TYPE "UDT_Alarm" STRUCT wAlarmNo : WORD; // 位号:工位号 + 设备号 + 故障码,如 16#0116 sText : STRING[60]; iClass : INT; // 0 提示 1 警告 2 故障 3 急停 xEdge : BOOL; // TRUE = 上升沿触发,FALSE = 电平 tDelay : TIME; // 防抖延时,避免传感器抖动刷屏 xActive : BOOL; xAck : BOOL; END_STRUCT; END_TYPE位号编码规则建议直接抄:高字节是工位号,低字节是设备号和故障码,比如16#0116表示 1 号工位、1 号设备的第 6 类故障(超时)。这样不用查表也能猜个大概,现场沟通成本低很多。
打包送 HMI 时用报警字,不用一条报警一个变量:
// 32 条报警压成 1 个双字,HMI 侧按位解析 "DB_Alarm".dwAlarmWord := 0; FOR #i := 1 TO 32 DO IF "DB_Alarm".astAlarm[#i].xActive THEN "DB_Alarm".dwAlarmWord := "DB_Alarm".dwAlarmWord OR SHL(DWORD#1, #i - 1); END_IF; END_FOR; // 首故障记录:只记第一个激活的,不被后续报警覆盖 IF "DB_Alarm".dwAlarmWord <> 0 AND "DB_Alarm".wFirstFault = 0 THEN FOR #i := 1 TO 32 DO IF "DB_Alarm".astAlarm[#i].xActive THEN "DB_Alarm".wFirstFault := "DB_Alarm".astAlarm[#i].wAlarmNo; EXIT; END_IF; END_FOR; END_IF;打包的理由是省变量数和扫描负载。HMI 上开 32 个连接变量和开 1 个字,刷新频率差得很多,工位一多画面就卡。首故障记录则是给维修的人留的后路:一条连锁反应报出十几个报警时,真正的原因只有一个,先看的应该是首故障。这个字段一定要在 HMI 上显眼位置放,不然没人知道它是干什么的。
4. 跑起来:从解归档到仿真跑通第一个循环
4.1 环境准备和打开工程的动作顺序
拿到归档包之后,别急着双击。我的顺序是:先确认编程平台版本与工程要求的版本一致,再确认标准块库已经安装到本地库路径,最后解归档。顺序反了会出现“工程能打开但块的接口是空的”这种玄学现象,找半天找不到原因。
具体清单如下:
| 步骤 | 动作 | 判断成功的标志 |
|---|---|---|
| 1 | 安装匹配版本的编程平台 | 能新建空工程并编译通过 |
| 2 | 安装标准块库 | 库管理里能看到库名和版本号 |
| 3 | 解归档到本地非中文路径 | 生成工程目录,不是压缩包 |
| 4 | 打开工程做全编译 | 无红色错误,警告可暂不管 |
| 5 | 检查硬件组态与实际是否一致 | IO 地址、站号、模块型号对得上 |
第 5 步最容易被跳过。别人给的模板往往带着自己那套硬件组态,直接下载到你的机架上会报错,或者更糟:地址对上了但模块型号不同,运行起来读写异常。改硬件组态之后一定要重新编译,让 IO 地址重新分配。
4.2 用仿真器跑通第一个循环
仿真这一步的价值不在于验证程序对不对,而在于验证步序会不会自己往下走。很多逻辑错误(漏复位、边沿用错、常开常闭反了)在仿真里单步跑一遍就能发现一半。
操作路径大致是:打开仿真器,把工程下载到仿真实例,切到在线,把xSim置 TRUE,然后在监控表里手动点亮xCycleStart,看自动步序的当前步号是否按 1、10、20、30 递增,而不是跳到某个奇怪的数。
// 仿真辅助:把工位的仿真标志统一拉到所有设备实例 FOR #i := 1 TO 8 DO "DB_Sim".axDeviceSim[#i] := "DB_HMI".xSimMode; END_FOR; // 步序当前步号输出给 HMI,仿真时盯着这个数看 "DB_HMI".iStationStep := "FB_Station_ST010_DB".iStep;第一段相当于一个总开关,把 HMI 上的仿真模式分发到每个设备实例,避免一个个去改。第二段把步号提到 HMI,仿真时你不用一直连着工程,看画面就知道停在哪。这两段都是调试期的临时逻辑,正式上线前要么删掉,要么用编译开关包起来,留着迟早出事。
仿真跑通的判断标准很明确:连续跑三个完整循环,步号顺序一致,没有卡顿,没有报警。达到这个状态再去接实物,效率差好几倍。
4.3 监控表怎么建,卡住时看哪几个变量
监控表建议按工位建,一个工位一张,列固定成四组:模式与使能、步序号、设备状态、报警字。别把所有变量塞一张表里,翻起来比翻程序还慢。
卡住时的排查顺序是固定的:先看模式对不对(是不是还在手动),再看步序号停在第几步,然后看这一步依赖的设备块iStep,最后看那个设备块缺的是命令还是反馈。绝大多数“程序不动了”都是这四层里的某一层条件没满足,逐层往下看,比在梯形图里瞎找快得多。
注意:监控表里改值是临时写,退出在线就没了;要固化参数就写到 DB 里,别指望监控表当参数面板用。
4.4 下载实机前的检查清单
从仿真切到实机,我一般走一遍固定检查:所有设备的仿真标志置 FALSE、安全程序单独编译并确认版本一致、输出映射 FC 里的地址逐条对过、急停回路实测有效、机器人握手的心跳信号确认在翻转。这几条里任何一条没过就不下载,尤其是心跳,仿真里靠强制位能过,实机上不翻转就直接判通信故障,第一次上机最常卡在这。
5. 避坑与排查:这四个坑最费时间
5.1 坑一:仿真里全绿,上机第一个循环就撞
现象很典型:仿真里连续跑十几个循环都顺,接上实物、按下启动,第一个动作就到位不停或者两个气缸同时出。原因八成是仿真标志把反馈自短接了,xSim一开,反馈跟着输出走,等于所有位置开关都是“永远正确”,极性接反、常开常闭搞混这类问题全被掩盖。
解决办法有两层。一是仿真阶段别全程开着xSim,至少要有一个循环把它关掉,用监控表手动强制反馈,感受一下信号真实翻转的时序。二是上机前做单点测试:每个气缸单独手动动作一次,确认伸出时xFbExt变 TRUE、xFbRet变 FALSE,反了就在硬件组态或接线里改,别在程序里取反糊过去。程序里取反是后悔药,三个月后没人记得。
5.2 坑二:自动循环偶发停在同一处,重启又好了
现象是跑了几个小时,偶尔停在某个步不再往下,复位重启后恢复正常,查不出规律。原因通常落在初始化上:上电首扫描的初始化块没执行、DB 里的中间变量保留着上一次的残值、或者某个故障位在故障消失后没有被清掉,导致使能条件一直不满足。
解决办法是把初始化做扎实:在启动组织块里把工位的步号、故障码、报警字全部写一遍初值,不要依赖 DB 的默认值;所有故障态都设一条“使能丢失即回空闲”的退出路径,别让状态机卡死在 90 步。另外,把停机瞬间的步号和报警首故障记到保持性 DB 里,下次开机第一件事就是看这两个值,比在现场守着等复现靠谱。
5.3 坑三:HMI 面板一串 ####,PLC 侧数据是好的
现象是 PLC 变量在线看数值正常,HMI 上全是 #### 或者 0。原因基本是两个:UDT 改过版本(加字段、改 STRING 长度)之后,HMI 侧变量没重新编译,偏移对不上;或者 HMI 连的是旧的面板模板,还指着老的 DB 地址。
解决办法是定规矩:UDT 只增不改,要改就新建一个类型;每次改完 PLC 接口,HMI 工程整体重新编译一遍再下载,别只下画面。这条规则听着麻烦,但比在画面上一格格数偏移量强太多。
5.4 坑四:改了一个设备块,别的工位跟着报警
现象是你只改了 ST010 用的那个块,结果 ST020、ST030 也开始出故障。原因是标准块被多个工位共用,接口里加了必填输入,其它实例编译时被补了默认值 FALSE,逻辑就跑偏了。
解决办法是改公共块之前先看调用点数量,工程里搜一遍块名,心里有数。新增输入一律给默认值,并且默认值要等于“保持原行为”(比如新增的xEnable默认 TRUE,不是 FALSE)。真要动接口语义,就复制一个新块另起名字,老工位继续用老块,等有机会再统一迁。混着改是线上事故的标准起点。
6. 二次开发:把标准工位改成你自己的那一台
改造的起点不是写代码,是选模板。挑一个和你目标工位最接近的现有工位,整段复制,然后按顺序做四件事:改工位号(块名、DB 名、报警位号全部跟着换,用全局替换,不要手动一个个改)、删掉不需要的设备实例、按新工位补设备、把自动步序重写一遍。
补设备的时候有个技巧:先在 UDT 里把设备接口定死,再去生成 FB 实例。顺序反了会反复改接口,每改一次所有调用点都要重编译。接口我一般这么定:
// 工位设备接口:一个工位最多挂 16 台标准设备 TYPE "UDT_StationDevice" STRUCT iType : INT; // 1 气缸 2 夹紧 3 输送 4 机器人 iDevNo : INT; // 设备号,进报警位号 xEnable : BOOL; xCmd : BOOL; xFb1 : BOOL; // 到位反馈 1 xFb2 : BOOL; // 到位反馈 2 tTimeout : TIME; iStep : INT; iErrCode : INT; END_STRUCT; END_TYPE验证方法也别省。改完之后先离线全编译,看错误数量;再进仿真,关掉xSim用强制位跑三个循环;最后上实机单点手动测试每个设备,再切自动跑空载一个循环。这三步里最容易被跳过的是“关仿真跑”,但恰恰是它能把反馈极性问题揪出来。
想把标准程序用出价值,关键动作是“先照抄,再改造,最后才谈优化”。我见过太多人上手就重构标准块,把状态机改成自己习惯的写法,结果半年后新人接手完全看不懂,维护成本翻倍。从那以后我每次改公共块之前,都强制走一遍“搜调用点、留默认值、记版本号”这三步,宁可多花十分钟,也不想半夜被叫起来查一个自己埋的雷。希望帮到你。
本文还有配套的精品资源,点击获取