简介:Sicar-Training-show-V16程序面向工业自动化工程师、西门子PLC编程学习者及产线调试人员,围绕Sicar标准程序框架提供一套可参考的培训示例工程,用于理解标准程序的分层结构、设备组态、报警与画面资源组织方式,适合具备一定TIA Portal与Profinet基础的中级读者对照学习。压缩包共106个文件,约38.19MB,包含ap14项目归档及xml、ini等配置与描述文件,bmp、png、ico等设备图标和界面素材,以及cfs、dat、idx等运行与索引数据,另有xsl、hsf、plf等辅助文件,基本覆盖标准程序从项目工程到可视化资源的常见组成。该资源已有654人学习下载,可作为Sicar标准程序入门与框架梳理的参考样本。读者可从中了解培训示例工程的目录组织、设备图片与GSDML描述文件的配套关系,以及标准程序在项目归档中的资源分布,便于后续按模块查阅、对照自身项目进行结构分析和二次整理。
1. 把 V16 当骨架看:Sicar 标准程序培训演示包先解决哪三个落地问题
第一次拿到 Sicar 标准程序培训演示包 V16,我没有急着打开画面,而是先看它把设备控制拆成了什么形状。很多同行找 sicar标准程序,表面是找一份能演示的工程,实际要的是三件事:设备层和工艺层怎么解耦、报警和配方怎么不写成一锅粥、换一个工位时哪些接口能原样复用。这套 V16 培训演示程序的价值不在“能跑”,而在它把标准程序的骨架摆出来了:统一的单元接口、配方参数校验位置、报警与诊断的落点。适合正在从单机程序往标准模板迁移的工程师,也适合刚接手一套历史工程、想把黑匣子拆开看的人。它不承诺直接上产线,但能当对照表用。
2. 先看骨架:V16 标准程序的四层划分与统一接口
2.1 设备层、单元层、工艺层、管理层怎么切
我一般先把工程里的程序块按调用关系摊开,不看画面,只看谁调用谁。标准程序最容易翻车的地方,是把设备动作、工艺判断和报警文本全塞进一个功能块里,前期跑得挺顺,后期加一个工位就要复制三遍。V16 培训演示程序的结构更适合按四层去读:设备层只处理 IO 映射、驱动状态和硬件诊断;单元层处理工步、互锁和单步/自动切换;工艺层处理配方、参数窗口和节拍;管理层处理报警归档、权限和追溯。这样切的好处是,设备层换模块时不用动工艺判断,工艺层调参数时不用碰 IO 地址。
读工程时我会先画一张调用关系草表,不追求好看,只标三件事:每个功能块的输入来自哪里、输出被谁消费、异常码在哪个层被翻译成文本。常见误用是把配方计算写在设备层,结果换一台设备就要改一遍配方逻辑;另一种是把报警复位放在 HMI 脚本里,PLC 侧没有首出记录,出了问题只能靠猜。V16 的演示程序把复位和首出放在单元层,HMI 只下发命令,这个边界值得抄。设备层不写工艺条件,单元层不直接写 IO 地址,工艺层不直接驱动输出,管理层不参与实时互锁,这四条守住,后面加功能才不容易乱。
我还会看程序块的命名和分组。标准程序不是名字越整齐越好,而是从名字能看出层级和职责,比如设备层块带Drv或Io,单元层块带Unit,工艺层块带Rcp或Par,管理层块带Alm或Trace。如果打开工程发现所有块都叫FB1、FC2,那这套演示程序只能当参考,不能直接当模板。V16 的培训演示包在这一点上比较克制,至少能让人顺着块名找到调用入口。读的时候不要一上来改代码,先把调用链和接口表抄下来,后面调试会省很多后悔药。
2.2 统一接口表:把“能跑”变成“可复用”
标准程序能不能复用,关键不在代码写得多巧,而在接口是不是闭合。我习惯给每个单元功能块定一张最小接口表:输入侧有使能、复位、模式、启动、参数结构;输出侧有就绪、忙、完成、错误码、诊断文本。输入只读,输出只写,内部步序号不暴露给调用方。这样 HMI 只认命令和状态,工艺层只认参数结构,设备层只认 IO 和驱动状态,谁也别越界。V16 的演示程序里,单元块基本按这个思路留了口子,读的时候可以拿这张表去对照,缺哪一项就记下来。
接口表不是越全越好。我见过一种写法,把一个单元的所有中间变量都做成输入输出,结果调用方要填二十多个引脚,换一个工位就漏填。更稳的做法是只暴露调用方真正需要改的东西:模式、启动、复位、配方号、少量工艺参数;诊断信息用错误码加文本输出,不把内部步序号抛出去。这样调用方不需要知道内部怎么走步,内部改步序也不会影响上层。常见做法是给每个单元块配一个参数结构体,结构体里只放工艺层关心的字段,设备层字段留在设备块内部。这样接口表能稳住,复用才有基础。
下面这段 ST 代码是我在读这类标准程序时常用的最小接口骨架,不是 V16 的原样代码,但结构能对上。它把输入输出和内部步序分开,调用方只看Ready、Busy、Done、ErrCode和Diag。参数结构体ST_UnitPar只放工艺层需要调的字段,设备层地址不在这里出现。
FUNCTION_BLOCK FB_UnitBase VAR_INPUT Enable : BOOL; // 单元使能,FALSE 时输出回安全位 Reset : BOOL; // 故障复位,上升沿有效 Mode : INT; // 0=手动 1=单步 2=自动 Start : BOOL; // 启动命令,单步模式下走一个工步 Par : ST_UnitPar; // 工艺参数,不含 IO 地址 END_VAR VAR_OUTPUT Ready : BOOL; // 无故障且使能到位 Busy : BOOL; // 工步执行中 Done : BOOL; // 当前周期完成 ErrCode: WORD; // 错误码,0 表示无错误 Diag : STRING[80]; // 诊断文本,只给 HMI 看 END_VAR VAR step : INT := 0; // 内部步序,不暴露给调用方 tStep : TON; // 步超时定时器 END_VAR这段代码的逻辑说明不复杂:Enable为假时,块内部应该把输出和步序拉回安全状态,而不是继续走步;Reset只在上升沿清错误码和首出,不能把正在执行的工步直接清掉;Mode决定Start的语义,手动模式只允许点动,单步模式走一个工步,自动模式才连续执行;Par从工艺层下发,单元层只做范围检查和互锁,不在这里改配方来源。ErrCode用WORD是为了留出设备层、单元层、工艺层的分段,比如16#1000段给 IO,16#2000段给互锁,16#3000段给配方。Diag只做显示,不参与逻辑判断,避免有人拿文本比较当条件。
参数说明要落到调用方怎么用:调用方在每个周期调用一次块,先给Enable和Mode,再给Start一个上升沿;Reset用按钮上升沿,不要用常闭点;Par在配方切换时整体赋值,不要逐字段散写。如果ErrCode非零,先看Diag定位层,再去对应层查首出。这个骨架不追求功能完整,但能把“能跑”变成“可复用”的起点。
2.3 用一段 ST 代码验证接口是否闭合
读完接口表,我会做一次接口闭合检查:每个输出有没有被消费,每个输入有没有被赋值,错误码有没有被翻译,复位有没有清首出。这个检查不需要仿真器,静态看调用关系就能发现一半问题。V16 培训演示程序里有些块是演示用的,输出可能只接到画面,不接后续逻辑,读的时候要区分“演示接线”和“标准接口”。如果是准备拿来改自己工程,演示接线不能直接当正式接线用。
下面这段检查代码不是运行逻辑,而是我常用来验证接口字段有没有漏的静态清单式写法。它把单元块的输出逐个映射到监控结构,编译期能发现字段名对不上,运行期能看出哪个输出一直没动。
// 接口闭合检查:每个输出都要有消费点 gMon.Unit01.Ready := fbUnit01.Ready; gMon.Unit01.Busy := fbUnit01.Busy; gMon.Unit01.Done := fbUnit01.Done; gMon.Unit01.ErrCode := fbUnit01.ErrCode; gMon.Unit01.Diag := fbUnit01.Diag; // 错误码分段翻译,不要在 HMI 里写一长串 IF CASE fbUnit01.ErrCode OF 0: gMon.Unit01.ErrText := 'OK'; 16#1001: gMon.Unit01.ErrText := 'IO 映射不一致'; 16#2001: gMon.Unit01.ErrText := '互锁条件未满足'; 16#3001: gMon.Unit01.ErrText := '配方超窗口'; ELSE gMon.Unit01.ErrText := '未定义错误'; END_CASE;逻辑说明:前半段把单元块输出抄到监控结构,不是为了多写几行,而是让编译器和后续逻辑都盯着这些点;如果某个输出没人消费,监控结构里就会空着,读工程时一眼能看出来。后半段用CASE把错误码翻译成文本,HMI 只显示ErrText,不参与判断。参数说明:gMon是监控结构,按单元编号分组;错误码分段要和接口表一致,16#1000段留给设备层,16#2000段留给单元互锁,16#3000段留给工艺参数。这样排查时先看错误码段,再看具体码,不用在几百行文本里翻。
接口闭合检查还有一个动作:把每个输入列出来,看有没有默认值。Enable默认 FALSE,Reset默认 FALSE,Mode默认手动,Start默认 FALSE,Par用配方默认值初始化。没有默认值的输入在首次扫描时可能是随机态,标准程序最怕这个。V16 的演示程序在初始化块里做了默认赋值,读的时候可以对照自己的工程,看看有没有漏掉的保持型变量。这一步做完,再去碰硬件组态,心里才有底。
3. 把程序跑起来:从工程恢复到首轮空载调试的检查顺序
3.1 工程导入与硬件组态核对
工程恢复不是点一下打开就完事。我一般先备份原始包,再确认工程软件版本和演示程序要求的版本是否对得上,库文件有没有缺失,硬件组态里的模块顺序和实际设备是否一致。V16 培训演示程序是演示工程,硬件组态可能是虚拟配置,直接下载到实机会报错,所以第一步不是下载,而是把组态改成自己的设备配置。常见做法是新建一个副本工程,保留原始包不动,在副本里改组态、改 IO 映射、改单元数量。这样后面翻车了还能回到原始包对照。
硬件组态核对我按一张表走,表里只列会直接影响首轮调试的项。模块顺序错了,IO 地址会整体偏移;分布式从站看门狗时间太短,上电会掉站;模拟量模块的量程卡和程序里的缩放系数不匹配,HMI 数值会跳;急停链路如果没有在程序里做首出,复位后可能直接重启输出。下面这张表是我读这类标准程序时常用的核对项,不是 V16 的官方清单,但能覆盖大部分首轮问题。
| 检查项 | 看什么 | 失败表现 |
|---|---|---|
| 工程软件版本 | 打开时是否提示库缺失或块升级 | 编译报错、块被替换 |
| 模块顺序 | 槽位和实际设备是否一致 | IO 地址整体偏移 |
| 分布式从站 | 看门狗时间、站点数量 | 上电掉站、诊断闪断 |
| 模拟量量程 | 量程卡、缩放上下限 | HMI 数值跳变或超量程 |
| 急停链路 | 急停输入是否进首出 | 复位后输出直接吸合 |
| 输出禁止 | 首轮调试是否有输出禁止位 | 空载测试变成带载动作 |
核对完组态,再编译一次。编译不要只看“0 错误”,还要看警告。标准程序里常见的警告是变量未使用、类型隐式转换、块接口变更。未使用变量可能是演示接线没接完,隐式转换可能是INT和REAL混用,块接口变更可能是库版本不对。这些警告在首轮调试时不一定报错,但会在某个配方切换或模拟量缩放时冒出来。我一般把警告也当问题记,能清就清,清不了就写明原因。
3.2 符号映射与地址漂移检查
符号映射是标准程序从演示走向复用的关键一步。演示工程里常用绝对地址,因为看着直观;正式工程里更稳的是符号寻址加结构体映射,把 IO 地址收口到一个映射块里,其他块只认符号。这样换模块时只改映射块,不用全工程搜地址。V16 的演示程序里能看到这种收口思路,但演示工程为了短,可能只映射了一部分。读的时候要检查:每个设备块的输入输出是不是都从映射结构取,有没有人绕过映射直接写%I0.0这种绝对地址。
地址漂移的典型现象是,改了组态之后某个传感器信号跑到另一个工位,程序不报错,动作却错位。原因通常是绝对地址散落在多个块里,改组态时只改了一处。解决方法是把 IO 映射做成一个独立功能块,上电时检查映射地址和期望地址是否一致,不一致就置错误码,不进入自动。下面这段 ST 代码是我常用的映射检查骨架,参数说明放在代码后面。
FUNCTION_BLOCK FB_IoMapCheck VAR_INPUT Enable : BOOL; // 使能检查,首轮调试时常开 END_VAR VAR_OUTPUT MapOk : BOOL; // 映射一致为 TRUE FirstErr : WORD; // 第一个不一致的序号,0 表示无错误 END_VAR VAR i : INT; END_VAR MapOk := FALSE; FirstErr := 0; IF NOT Enable THEN RETURN; END_IF; FOR i := 1 TO 32 DO // gIoMap 是映射表,PlcAddr 是实际地址,ExpectedAddr 是期望地址 IF gIoMap[i].PlcAddr <> gIoMap[i].ExpectedAddr THEN FirstErr := INT_TO_WORD(16#1000 + i); RETURN; END_IF; END_FOR; MapOk := TRUE;逻辑说明:上电初始化时调用一次,Enable常开,循环检查映射表里的实际地址和期望地址;发现第一个不一致就记录序号并返回,不继续检查,避免错误码被覆盖。MapOk为假时,单元层不应该进入自动模式,HMI 显示FirstErr对应的映射点。参数说明:gIoMap是全局映射结构,PlcAddr在组态变更后更新,ExpectedAddr是程序侧期望值;16#1000是错误码段,加序号后能直接定位到第几个映射点。这个检查不能替代硬件诊断,但能挡住大部分地址漂移。
符号映射还要注意数据类型。模拟量输入常见是INT,程序里做缩放时先转REAL再乘系数,不要直接INT * REAL后截断。HMI 上显示小数点错位,很多时候不是画面问题,是缩放系数和量程卡不匹配。映射块里把原始值、缩放值、量程上下限都留出来,调试时能一眼看出是原始值不对还是缩放不对。V16 演示程序里如果有模拟量演示,可以顺着这条链对一遍。
3.3 首轮空载测试的四个闸门
首轮空载测试不是“按一下启动看动不动”,而是按闸门走。我一般设四个闸门:输出禁止、急停链路、强制表清零、单步走步。输出禁止是第一步,把所有执行输出锁在安全位,只让程序跑逻辑和报警;急停链路是第二步,按急停看程序是否记录首出、复位后是否要求重新启动;强制表清零是第三步,仿真时留下的强制值不清,实机会出现“程序里没写但输出动了”的鬼故事;单步走步是第四步,手动模式点动每个输出,单步模式走每个工步,自动模式最后再开。
输出禁止的做法不是拔保险,而是在程序里加一个调试禁止位,所有单元块的输出先经过禁止位再落到映射。这样空载测试时逻辑照跑,输出不动,能看清步序和报警。急停链路要检查首出:急停按下时,哪个单元先报错,错误码是不是急停段,复位后Ready是不是要等启动命令才恢复。强制表清零要在下载后、上电前做,仿真器里的强制值有时不会跟着工程走,实机下载后第一件事就是清强制、清保持型变量。
单步走步时我会盯三个东西:步序是否按预期递增,超时定时器是否在每一步重新计时,错误码是否在步序回安全位后才清除。V16 演示程序的单元块如果带step和tStep,可以顺着看每一步的进入条件和退出条件。常见翻车是步超时定时器没有在步切换时复位,导致第二步刚进来就报超时;另一种是错误复位把步序清到 0 但输出没回安全位,下一步直接带着旧输出启动。空载测试就是把这些问题在带载前逼出来。
提示:首轮空载测试前,把原始工程再备份一份,下载后先清强制表和保持型变量,再按输出禁止、急停、单步、自动的顺序走。
4. 参数怎么设:配方、报警限值与节拍参数的落点
4.1 配方参数的三层校验
配方参数不是填进去就完事。我一般分三层校验:第一层量程,第二层互锁,第三层工艺窗口。量程校验是最基础的,温度设定不能超过设备允许范围,压力设定不能为负,时间设定不能是 0;互锁校验看参数之间是否打架,比如阀门模式是手动关闭时压力设定还给非零值,或者加热和冷却同时使能;工艺窗口校验看这批产品允不允许这个组合,比如保温时间低于下限、升温速率超过材料允许值。三层校验放在工艺层,不放在 HMI 脚本里,HMI 只负责提示,不负责放行。
V16 培训演示程序里如果有配方演示,可以看它把校验放在哪个块。常见误用是只在 HMI 输入框做上下限,PLC 侧不校验,结果配方从外部导入或从旧工程迁移时绕过画面,非法值直接进逻辑。更稳的做法是 PLC 侧有一个FB_RecipeCheck,任何来源的配方切换都走这个块,校验不通过就拒绝装载并给出错误码。下面这段 ST 代码是三层校验的最小写法,参数说明在后面。
FUNCTION FB_RecipeCheck : BOOL VAR_INPUT Recipe : ST_Recipe; // 待校验配方 END_VAR VAR ok : BOOL := TRUE; END_VAR // 第一层:量程校验 IF Recipe.TempSet < 20.0 OR Recipe.TempSet > 180.0 THEN ok := FALSE; END_IF; IF Recipe.HoldTime < 5 OR Recipe.HoldTime > 120 THEN ok := FALSE; END_IF; // 第二层:互锁校验 IF Recipe.PressureSet > 0.0 AND Recipe.ValveMode = 0 THEN ok := FALSE; END_IF; IF Recipe.HeatEnable AND Recipe.CoolEnable THEN ok := FALSE; END_IF; // 第三层:工艺窗口校验 IF Recipe.TempSet > 120.0 AND Recipe.HoldTime < 10 THEN ok := FALSE; END_IF; FB_RecipeCheck := ok;逻辑说明:三层校验按顺序执行,任何一层不通过都返回 FALSE,调用方不装载配方,保持旧配方或回默认配方。量程校验用常量边界,互锁校验看字段组合,工艺窗口校验看跨字段关系。参数说明:TempSet是温度设定,HoldTime是保温时间,PressureSet是压力设定,ValveMode是阀门模式,HeatEnable和CoolEnable是加热冷却使能。边界值不要散写在多个块里,最好放一个参数常量表,改工艺窗口时只改一处。校验失败时给出具体错误码,不要只给一个“配方无效”,否则现场只能猜是哪一层没过。
配方切换还要注意保持型变量。新配方装载后,旧配方的中间计算结果如果没复位,会出现“配方号变了但动作还是旧参数”的残留。我一般在新配方装载后强制走一次单元复位,把中间变量、积分项、超时定时器清掉,再允许启动。这个动作在演示程序里可能被简化了,读的时候要留意。校验通过不等于切换完成,切换完成要等单元块回到Ready且ErrCode为 0。
4.2 报警限值:HH/H/L/LL 之外还要加什么
报警限值最容易写成四个数:HH、H、L、LL。实际现场只写四个数不够,还要加延时、回差和首出。延时是防止数值在限值附近抖动导致报警反复触发;回差是报警恢复后要回到更安全的区间才允许复位;首出是多个报警同时出现时记录谁先来。V16 演示程序里的报警块如果只有比较器,没有延时和回差,读的时候可以把它当简化版,自己工程里要补上。常见翻车是报警复位后马上再次触发,现场以为是复位按钮坏了,其实是数值还在限值内,复位条件没消失。
我一般把报警参数做成一张表,每个报警点有四个限值、一个延时、一个回差、一个屏蔽位。延时用TON,不要用循环计数,循环计数会随扫描周期变化;回差用恢复阈值,比如高报警在 80 触发,恢复到 75 才允许复位;屏蔽位只屏蔽显示和归档,不屏蔽联锁,联锁该动还要动。首出用报警字的第一位置位,复位时只清已恢复的报警,未恢复的保持。下面这张表是参数落点,不是 V16 的原始参数表,但结构可以照着建。
| 参数 | 含义 | 常见取值方式 |
|---|---|---|
| HH/H/L/LL | 报警限值 | 按工艺窗口和传感器量程取 |
| Delay | 触发延时 | 3 到 10 个扫描周期,按信号噪声调 |
| Deadband | 恢复回差 | 量程的 1% 到 3% |
| FirstOut | 首出字 | 每个报警点占一位 |
| Mask | 屏蔽位 | 只屏蔽显示归档,不屏蔽联锁 |
报警文本不要写太长,HMI 上显示不下,现场也不看。我一般用“单元 + 参数 + 方向 + 限值”的短文本,比如“单元01 温度 HH”,详细原因放诊断码。报警归档要带时间戳和首出,复位后还能查。V16 演示程序里如果有报警演示,可以看它有没有把报警和错误码分开:报警是工艺越限,错误码是逻辑故障,两者不要混在一个字里,否则排查时分不清是工艺问题还是程序问题。
4.3 节拍参数别拿扫描周期硬凑
节拍参数和扫描周期是两件事。扫描周期是 PLC 跑一圈的时间,节拍是工艺动作之间的时间间隔。常见误用是用循环计数当定时,比如“循环 100 次算 1 秒”,换了 PLC 或加了程序块,扫描周期变了,节拍就漂了。标准程序里应该用定时器或时间戳,节拍参数以毫秒为单位下发,单元层用TON或R_TRIG加时间差实现。V16 演示程序如果为了短用了循环计数,读的时候要标出来,自己工程里换掉。
节拍参数还要和超时参数分开。节拍是正常动作间隔,超时是动作没完成的容忍时间。比如一个气缸动作节拍 500ms,超时设 2s,不能把超时也设 500ms,否则正常波动就报错。我一般给每个工步配一个节拍参数和一个超时参数,节拍参数放工艺层,超时参数放单元层,调试时先放宽超时,等节拍稳定再收紧。下面这段 ST 代码是节拍定时器的常见写法,参数说明在后面。
// 节拍定时:用 TON 而不是循环计数 tStep(IN := (step > 0) AND (step <> lastStep), PT := gUnitPar.StepTime[step]); IF tStep.Q THEN // 节拍到,允许进入下一步 StepDone := TRUE; END_IF; // 步切换时复位定时器 IF step <> lastStep THEN lastStep := step; StepDone := FALSE; END_IF;逻辑说明:tStep在当前步有效且步号变化时开始计时,计时到StepTime[step]后置StepDone;步号变化时清完成位,让下一步重新计时。参数说明:StepTime是工艺层下发的节拍数组,按步号索引;step是内部步序;lastStep用来检测步切换。这里没有用循环计数,所以扫描周期变化时,只要定时器分辨率够,节拍不会明显漂。节拍数组的默认值要在初始化块里给,不能留 0,否则第一步就立即完成。
节拍参数调的时候先看空载,再看带载。空载时动作快,节拍可以短;带载后机械惯性、气压建立时间都会拉长,节拍要放宽。不要为了追产能把节拍压到设备极限,超时和报警会教做人。V16 演示程序里的节拍参数如果只是演示值,不要直接抄到产线,按自己设备的动作时间重新测。测的时候用趋势图看输入输出时间差,比拍脑袋靠谱。
5. 避坑与排查:这套标准程序最容易翻车的五个位置
5.1 下载后首扫描就报错
现象:工程编译通过,下载后 PLC 一上电就报错,单元块ErrCode非零,复位也清不掉。原因通常不是程序逻辑,而是初始化顺序。标准程序里很多块依赖全局结构体和映射表,如果初始化块在单元块之后执行,首扫描时全局结构还是默认值,映射检查、配方校验、报警限值都会报错。另一种原因是保持型变量从旧工程带过来,新工程的默认值没覆盖,首扫描读到旧值。
解决:先看初始化块在任务里的执行顺序,确保全局结构、映射表、默认配方在单元块之前初始化。保持型变量在下载时选择复位,或者在上电初始化里显式赋默认值。映射检查块首扫描可以延时一个周期再使能,等硬件组态稳定。复位清不掉时看错误码段,16#1000段查映射,16#2000段查互锁,16#3000段查配方,不要一上来改逻辑。V16 演示程序如果带初始化块,可以对照它的执行顺序。
5.2 HMI 数值跳变或小数点错位
现象:HMI 上温度、压力数值乱跳,或者小数点错一位,PLC 内部趋势看是正常值。原因多半是数据类型和缩放系数不匹配。模拟量输入是INT,程序里做INT_TO_REAL后乘系数,如果系数写错一位,HMI 就错位;如果 HMI 侧又做了一次缩放,等于缩放两遍。另一种原因是 HMI 读写的是绝对地址,程序里改用了符号映射,地址漂移后画面读到别的变量。
解决:先看映射块里的原始值和缩放值,确认量程上下限和模块量程卡一致;再看 HMI 变量连接的是符号还是绝对地址,标准程序里统一用符号;最后看 HMI 侧有没有二次缩放,有就删掉。数值跳变还要看滤波,模拟量输入加一阶滤波或移动平均,滤波时间不要大于工艺响应时间。V16 演示程序里的画面如果只是演示,变量连接可能不完整,读的时候以 PLC 侧映射为准。
5.3 配方切换后旧值残留
现象:配方号已经切到新配方,HMI 显示新参数,但设备动作还是旧参数,或者第一步用新值、第二步又回旧值。原因是保持型中间变量没复位,配方装载只写了参数结构,没清单元块内部的积分项、步序、超时定时器和上次配方缓存。标准程序里如果配方切换和单元复位是两条路径,很容易只走了一条。
解决:配方切换做成一个完整事务:校验新配方、装载参数结构、复位单元块、等Ready、再允许启动。单元复位要清内部步序和保持型变量,不要只清错误码。下面这段 ST 代码是常见写法的对比,错误写法只写新值,正确写法先装载再复位。
// 错误写法:只写新配方,不清内部状态 IF RecipeChange THEN gRcp := NewRecipe; END_IF; // 正确写法:装载后强制走一次单元复位 IF RecipeChange AND FB_RecipeCheck(NewRecipe) THEN gRcp := NewRecipe; gUnit.Par := gRcp.Par; gUnit.Reset := TRUE; gUnit.Reset := FALSE; END_IF;逻辑说明:先校验再装载,装载后给Reset一个上升沿,让单元块把步序和保持型变量清回初始态;Reset只给一个周期,不能常开,否则单元块一直复位无法启动。参数说明:NewRecipe是待切换配方,gRcp是当前配方缓存,gUnit.Par是单元块参数输入。切换完成后要等gUnit.Ready为真再给启动命令,不要在同一周期给启动。
5.4 报警复位后马上再次触发
现象:按复位按钮,报警消失,松手又报,反复几次后现场不敢复位。原因是复位条件没消失,数值还在限值内,或者报警块没有回差,复位后立刻重新比较触发。另一种原因是复位只清了显示位,没清首出和锁存,下一次扫描又根据旧首出置位。
解决:复位逻辑加“恢复条件确认”,只有数值回到回差区间内才允许复位;报警块加触发延时和恢复延时,不要用瞬时比较;复位时清显示位、首出位和锁存位,但保留未恢复报警。联锁报警不要用复位按钮反复清,先处理工艺条件。V16 演示程序里的报警块如果简化了回差,自己工程里补上。
5.5 仿真正常、实机动作错位
现象:仿真器里步序、报警、配方都正常,下载到实机后某个气缸或电机动作错位,程序不报错。原因通常是 IO 映射和实机不一致,或者仿真时留下的强制表没清。标准程序里如果演示接线只接了一部分输出,实机下载后未接的输出可能保持上次状态;另一种原因是输出禁止位在仿真时被强制为 TRUE,实机没清,程序逻辑跑了但输出没动。
解决:下载后先清强制表和保持型变量,再核对 IO 映射,逐个点动输出。仿真和实机的差异列一张表:哪些输入是强制模拟的,哪些输出没接,哪些从站仿真时不存在。首轮实机调试一定从输出禁止开始,确认逻辑跑通再放开输出。V16 培训演示程序的输出如果只是演示,实机接线要按自己设备重做映射,不要直接套演示地址。
6. 进阶验证:用回放与注入把标准程序压到边界
标准程序跑通之后,我会做一轮回放和注入,把参数压到边界,看报警、配方校验和单元复位是不是真的按接口表工作。回放不是拿真实产线数据直接灌,而是先用脚本造测试序列,覆盖最小值、最大值、非法值和跳变值,再通过仿真器或离线回放工具按时间戳注入。常见做法是用 Python 生成 CSV,字段包括用例号、变量名、注入值、期望结果和备注,回放时逐行读,记录实际错误码。
import csv # 边界用例:每个参数取低于下限、下限、上限、高于上限 cases = [ ("TempSet", 20.0, 180.0, 0.5), ("HoldTime", 5, 120, 1), ("PressureSet", 0.0, 0.8, 0.01), ] with open("boundary_cases.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["case_id", "variable", "value", "expected_ok", "note"]) cid = 0 for name, low, high, step in cases: for value in (low - step, low, high, high + step): cid += 1 writer.writerow([cid, name, value, low <= value <= high, "range"])这段脚本只做一件事:按参数量程生成四类边界值,expected_ok记录期望校验结果。low - step和high + step是越界值,low和high是边界值。回放时把value注入配方结构,调用FB_RecipeCheck,对比实际返回和expected_ok。参数说明:step不要取太小,否则浮点误差会让边界值看起来越界;整数参数步长取 1,浮点参数按工程量取。回放记录要带时间戳和用例号,失败时能直接定位到哪一行。
边界矩阵还要覆盖组合条件,不只单参数。比如温度上限加保温时间下限、压力非零加阀门手动关闭、加热和冷却同时使能。这些组合在单参数回放里看不出来,要单独造用例。验收口径我一般定三条:非法值必须拒绝装载且错误码可定位;边界值必须按工艺窗口放行或拒绝,不能一会儿行一会儿不行;回放后单元块必须能回到Ready,不能停在半复位状态。
血泪经验是,标准程序最容易在“看起来没问题”的地方翻车:单参数校验都过,组合条件漏了;仿真回放都过,实机强制表没清;配方切换都过,保持型积分项没复位。从那以后我每次拿到一套标准程序,都先跑接口闭合检查和边界回放,再碰工艺逻辑,不急着改画面。希望帮到你。
本文还有配套的精品资源,点击获取