博途V15下用SCL开发S7-1500六层电梯控制程序心得

📅 发布时间:2026/10/20 23:39:49
博途V15下用SCL开发S7-1500六层电梯控制程序心得
只是看到博途V15和1500系列这两个词很多同行第一反应就是梯形图不是挺好的吗为什么非要折腾SCL我一开始也是这么想的但真把一个单部六层电梯的控制逻辑用LAD画出来之后我果断把所有程序都推倒重写了。以前做这种项目我更习惯用梯形图毕竟现场维护的师傅们对LAD最熟。但这次面对六层集选电梯我发现LAD的触点网络越画越绕一个方向仲裁逻辑就能让屏幕滚好几页。后来整个程序换成在博途V15下使用S7-1500系列PLC的SCL语言进行开发反而清爽了很多。这篇就把我从选型、建模到写代码、调试整个过程的思路和踩过的坑都记录下来给想尝试用SCL做电梯控制或者类似多状态项目的朋友一个参考。1. 语言选型反思为什么六层电梯我改用了SCL1.1 传统LAD在电梯控制里的别扭之处不敢说LAD不好它在简单逻辑、继电器替代、电气维护场景下依然是最直观的表达方式。但电梯控制不一样它是一个典型的多条件 多状态 优先级仲裁的逻辑集合。举例来说电梯上行过程中某一层有人按了上行呼梯同时又有人在轿厢里按了更远楼层的目标按钮这时候到底怎么处理还有电梯刚启动、正在加速新的呼梯来了要不要立刻改变方向这些判断用LAD描述就是一大串触点的串并联看似每个网络都清楚放在一起就成了一团乱麻。我这次初步用LAD搭了方向仲裁逻辑光是上行是否有请求下行是否有请求两个判断就铺了二十多个网络。后面还有选层、开关门时序、检修、急停复位光看网络号就知道这套程序维护起来有多痛苦。项目是改造项目不是批量定型设备后续大概率还要改策略用LAD改一处牵全身实在不划算。1.2 SCL更像在描述规则而不是画线路SCL在博途V15里不是什么新鲜语言S7-1500系列对SCL的支持已经非常成熟编译、在线监控、交叉引用都没有明显短板。它的语法类似Pascal但写起来更像高级语言里的流程描述IF、CASE、FOR循环都是常规操作注释也写得很自然。我选择SCL的核心原因是电梯控制本质上是描述一组规则比如电梯上行时只响应上方楼层的呼梯、电梯下行时只响应下方楼层的呼梯、同向优先、就近响应。这些规则用SCL表达几乎就是自然语言的直译而用LAD表达那就变成了几十个网络的线路图。有一个观点我要先摆正SCL并不是比LAD更高级的语言两者在编译之后都会变成差不多的底层指令。它是一个表达能力的问题面对条件分支多、状态转换多的场景文本化语言的密度和可读性明显更好。反过来如果只是控制一个水泵启停我照样用LAD三分钟搞定。这次选SCL单纯是因为六层电梯的集选控制逻辑用SCL写更合适。2. 变量模型先行六层单梯控制清单与数据结构设计2.1 先把需求清单列清楚再谈写代码写PLC程序最忌讳一上来就拖功能块。我第一步是花了一整天把控制需求逐条写清楚六层单部电梯看着简单需求却非常琐碎6个楼层层站按钮数量不同1层只有上行呼梯6层只有下行呼梯2~5层上下呼梯都有。轿厢内有6个目标楼层按钮按下即登记目标。电梯运行方向分上行、下行、停止三种。每层有平层感应开关用于楼层判定和精确停车井道内有上/下终端限位。开门、关门由门机执行PLC只给开门/关门指令。门锁信号必须闭合电梯才允许走车。急停、安全钳、限速器等信号统一接入安全链任何一环断开立刻禁止运行。需求清单列完之后我发现这事情本质上就是两个模型一个是人怎么呼叫电梯的呼梯模型一个是电梯自己处于什么状态的运行模型。搞清楚这两个模型变量表也就出来了。2.2 用数组表达楼层召唤是第一步优化很多初学者的做法是给每一层定义独立BOOL变量比如CallUp_1、CallUp_2、CallUp_3……目标楼层再定义六个Target_1到Target_6。这样当然能跑但SCL里写起来非常痛苦每个楼层都要单独写一段IF判断从六层改成八层的时候所有逻辑都要跟着加一遍。我改用数组来统一表达目标楼层登记数组 Target[1..6]BOOL按下轿内按钮后置位对应下标的元素。上行呼梯数组 CallUp[1..5]BOOL只有1~5层有效第6层本来就没有上行按钮。下行呼梯数组 CallDown[2..6]BOOL只有2~6层有效第1层没有下行按钮。数组最大的好处是可以配合FOR循环统一扫描比如判断上楼方向是否还有请求一个循环就全部遍历完根本不用逐层写重复逻辑。博途V15的SCL编辑器对数组下标的处理也比较友好越界访问会进入诊断缓冲区。2.3 用UDT把电梯状态封装起来除了楼层召唤电梯自身的运行状态也需要统一描述。我建了一个UDT取名UDT_Elevator里面包含了CurrentFloor : INT当前所在楼层靠平层信号刷新CurrentDir : INT0停止、1上行、-1下行DoorState : INT0关门到位、1开门到位、2正在开门、3正在关门RunningState : INT0空闲、1上行运行、2下行运行、3开门等待、4关门等待、5检修慢车以及前面说的三组呼梯数组。这样整个程序只需要操作一个电梯状态结构体DB里的数据分区非常清晰。调试时打开数据块所有关键信息一眼扫完。S7-1500系列的存储空间足够大这点结构体占用的空间根本不算什么但换来的是极其清爽的程序结构。可能有人觉得UDT多余但考虑到以后可能扩展成双梯并联甚至群控UDT几乎是必选项每台电梯一个结构体实例逻辑代码烂一遍扩展时只需要新增DB实例上层调度再协调各台电梯即可。2.4 输入输出信号先做一层映射除了编程逻辑I/O映射也值得多说一句。S7-1500系列的数字量输入输出可以直接用I.0.0、Q0.0这类地址但SCL程序里最好先在开头把DI映射到中间变量再把中间变量传给功能块。比如平层信号分别接在I0.0到I0.5程序开头就可以写// 输入信号映射 #di_floorSignal[1] : I0.0; #di_floorSignal[2] : I0.1; // ... 以此类推这样做的目的是让逻辑代码和硬件接线解耦。以后如果改了接线端子位置只需要改映射段不需要翻遍整个逻辑程序去找到底哪个触点用的是I0.3。3. 集选控制的核心逻辑方向仲裁、楼层定位与开关门时序3.1 程序框架一个功能块管一台电梯我建了一个功能块FB_ELV_CTRL背景数据块是DB_ELV_CTRLOB1里每个扫描周期调用一次。程序内部大致分四段输入信号采集与刷新方向判定与目标选择运行控制输出门控制与状态刷新。顺序很重要方向判定必须放在运行控制输出之前并且在一个扫描周期内完成。如果同一个周期里方向已经变了但输出还是按旧方向给出的就会出现一个周期的不一致电梯运行中任何一次输出抖动都有可能造成不必要的停车。变频器拖动是本项目的常见配置所以运行输出主要是方向继电器和多段速给定SCL里只需要输出上行、下行、高速、低速这些BOOL量。加速和减速曲线交给变频器去处理PLC不参与闭环。3.2 方向仲裁同向优先就近响应方向仲裁是电梯逻辑里最核心的部分。我采用的策略是同向优先、就近响应这也是最常见的单梯集选策略如果当前方向是上行或者电梯处于停止状态但上一次执行的是上行那么优先扫描当前楼层以上的所有呼梯请求只要存在就维持上行如果上方没有请求再扫描下方是否有请求有则切换到下行上下都没有请求时电梯进入空闲停在当前楼层自动关门。要注意反向呼梯的处理电梯正在上行去5楼此时3楼有人按下行呼梯按照集选策略应该先记录呼梯等上行任务完成后再掉头下来响应而不是立即掉头。这个登记但不立即改变方向的动作在SCL里实现得非常自然。3.3 目标站怎么找先向上找找不到再向下目标站查找我写成了两个独立逻辑段一个负责上行选层一个负责下行选层。上行选层就是从当前楼层1开始向上遍历到6层遇到第一个登记的目标楼层就停下来作为目标层。这里我直接在FOR循环里找最大楼层目标然后停车时在遍历过程中同步清除对应呼梯。我给出一段选层示意代码注意SCL里FOR循环的范围下标是整数可以直接用常量// 上行目标查找与呼梯登记 #upFound : FALSE; FOR #i : #st.CurrentFloor 1 TO 6 DO IF #st.Target[#i] OR #st.CallUp[#i] OR #st.CallDown[#i] THEN #upFound : TRUE; #destFloor : #i; END_IF; END_FOR; // 如果没有上方请求检查下方 IF NOT #upFound THEN FOR #i : #st.CurrentFloor - 1 TO 1 BY -1 DO IF #st.Target[#i] OR #st.CallUp[#i] OR #st.CallDown[#i] THEN #downFound : TRUE; #destFloor : #i; END_IF; END_FOR; END_IF;这套代码在六层电梯里足够用没有用到复杂的最近距离算法因为楼层少逐层扫描的耗时完全可以忽略。但要注意FOR循环里用BY -1实现倒序递减这个语法在SCL里是合法的。3.4 到底怎么定位楼层平层开关加自学习楼层定位是电梯控制的另一个关键点。六层电梯通常每层装一个平层感应开关轿厢到站时平层信号到位。程序里我用这个信号判断当前楼层但这里有个小陷阱平层信号是一个持续量不是脉冲如果直接用它刷新当前楼层同一个信号在工作期间会反复刷新当前楼层导致后续逻辑误判。所以我用边沿检测处理平层信号博途V15里可以用R_TRIG功能块声明如下#trigFloor : R_TRIG; #trigFloor(CLK : #di_floorSignal[#idx]); IF #trigFloor.Q THEN #st.CurrentFloor : #idx; END_IF;如果项目用的是旋转编码器测楼层还要考虑打滑和脉冲漂移复杂度会明显提高。单部六层的常规配置还是以平层开关为主、编码器做校验更稳妥。3.5 开关门时序TON定时器在SCL里怎么用电梯到站以后的动作顺序是减速停车、平层确认、开门开门到位后开始延时延时结束自动关门。这套顺序我配合一个门状态字和多个TON定时器实现。博途V15的SCL里使用TON需要在FB的Static区先声明实例#doorTimer : TON;调用时的写法#doorTimer(IN : #openDoorCmd, PT : T#5S); IF #doorTimer.Q THEN #closeDoorCmd : TRUE; END_IF;这里有个细节开门指令不能一直为TRUE否则定时器的IN一直被保持Q虽然会一直为TRUE但后续关门逻辑永远不具备触发条件。我实际做的时候开门到位信号一到就把开门指令复位关门判定交给延时计时。关门过程中如果门光幕被遮挡SCL里一个IF嵌套就够IF #doorClosing AND #doorObstruction THEN #doorTimer(IN : FALSE); #openDoorCmd : TRUE; END_IF;防夹逻辑虽然简单但对现场体验影响非常大我后来调试时发现光靠定时器关门如果没有防夹电梯会被卡在某一层很久所以这行逻辑千万别省。4. 状态机和安全链急停、检修、乱层保护的SCL落地4.1 用状态机约束电梯的运行阶段电梯不是简单的启动/停止它有一个完整生命周期空闲、上行启动、运行、减速停车、平层、开门、关门、下行……这些阶段如果用一组BOOL变量表示容易出现两个状态同时为TRUE的尴尬所以我用了一个RunningState整数配合CASE语句做严格状态机。CASE语句的关键优势是每个扫描周期只进入一个分支状态天然互斥。我把状态定义成常量每个分支里只处理当前状态下的动作状态切换通过赋值发生不允许跨分支直接修改输出。调试的时候打开数据块看RunningState就知道电梯卡在哪个环节。如果发现卡在开门等待但门已经开了很久基本能确定是关门条件没有满足排查范围瞬间缩小。CASE分支里忘了写ELSE是SCL新手最容易犯的错。如果状态值意外超出枚举范围程序会走空分支所有输出保持旧值看起来像死机。我在代码开头加了兜底逻辑IF #st.RunningState 0 OR #st.RunningState 5 THEN #st.RunningState : 0; END_IF;这样即使出现异常赋值也会回到空闲状态。4.2 安全链宁可错杀不可放过安全逻辑我放在FB最前面独立于状态机之外。凡是安全链断开、门锁断开、急停按下、终端限位动作不管当前状态如何立刻把运行输出全部清零同时触发报警。SCL写这种逻辑比LAD可读性更好IF NOT #safetyChain OR NOT #doorLock OR #estop THEN #runEnable : FALSE; #alarmActive : TRUE; ELSIF #faultReset THEN #alarmActive : FALSE; END_IF;注意这里用的是ELSIF而不是ELSE IF因为SCL的ELSIF是单一表达式没有多层END_IF嵌套更清晰。安全链断开之后状态机要进入安全状态我把它设计成状态5急停保持只有故障复位并且安全链闭合才回到空闲状态。还有一个细节急停没有恢复时按压复位按钮不应该消报警更不应该让电梯重新走车。所以复位指令必须和安全链状态做与运算。4.3 乱层保护用校验逻辑挡住错层乱层是电梯最怕的故障之一。平层开关信号一旦抖动或丢失CurrentFloor就可能停在错误楼层然后整个选层逻辑全乱。我的做法是双重校验每个平层信号到位时先看当前楼层变化是否连续。比如上一周期记录在3层这一周期原则上只能在2、3、4层之间跳变如果突然跳到1层说明平层信号有问题。逻辑实现很简单#deltaFloor : ABS(#newFloor - #st.CurrentFloor); IF #deltaFloor 1 THEN #floorPlausibilityError : TRUE; // 进入故障状态禁止运行 END_IF;硬件上同理接近开关做高速计数校验平层开关做主判断。单部六层电梯虽然不到高速电梯的验收标准但基本的错层保护逻辑必须有。电梯是载人设备软件层面的保护能挡住90%的异常工况剩下的交给安全钳和限速器。4.4 检修模式慢车点动不是几行IF那么简单检修模式看起来就是几个IF分支检修开关按下之后自动运行逻辑被旁路改由点动按钮直接驱动接触器。但实际操作中有几个必须注意的坑检修时门锁信号可能不闭合所以检修动作不能走正常的安全链判断需要单独放行。点动按钮要保持按下才动、松手即停输出由按钮状态直接决定。慢车运行必须屏蔽超速、平层等自动条件但终端限位仍然保留。我单独建了一个检修状态在里面只判断点动上/下按钮和终端限位。相关分支不调用任何自动目标查询逻辑这样能保证检修状态下电梯不会自己思考往某层跑。检修模式的逻辑虽然简单但它和自动模式之间的切换处理一定要干净否则检修结束之后方向变量还残留着旧状态电梯可能自动冲层。5. 仿真与现场调试那些让我反复折腾的瞬间5.1 PLCSIM V15下的无实物跑逻辑博途V15自带的PLCSIM可以仿真1500系列CPU虽然不能真正带变频器和电机但跑程序逻辑完全没问题。我把整个程序下载到仿真PLC里又写了几个辅助测试用的变量强制表用来模拟按钮动作、平层信号变化。最适合仿真的是方向仲裁逻辑。我手动给不同楼层设置呼梯观察方向变量是否按预期切换。比如电梯停在3楼朝上运行去5楼此刻4楼按下行呼梯正常应该保持上行先停5楼再下来停4楼而不是立刻掉头去4楼。这类场景在仿真里验证起来非常快改代码成本极低比写完了去现场再改省太多时间。不过PLCSIM仿真也有盲区它仿真不了真实的传感器抖动和信号延迟。平层信号在现场可能因为安装位置偏差出现极短时间的来回抖动仿真环境里是干净的01变化所以现场调试依然要检查输入信号的实际波形和电气干扰。5.2 在线监控表与强制变量的使用习惯博途V15的监控表比老版本好用很多。我习惯建专门的电梯关键状态监控表把CurrentFloor、CurrentDir、RunningState、呼梯数组都放进去。运行的时候看着表基本能推断出程序状态。变量强制也是调试利器但强制之前必须先确认变量在程序中有没有被多处赋值。SCL比LAD更容易产生多地点赋值如果某个BOOL在多个位置被写强制它可能会被下一行逻辑覆盖导致我明明强制了还是没有反应的怪现象。我的程序里定了规矩一个输出BOOL只能有一个所有者其他位置只能读不能写。这虽然是编码习惯但直接决定了调试时能不能快速定位问题。5.3 三个典型的调试案例第一个案例是方向反复抖动。电梯由上行切换成下行的一瞬间因为下方楼层有呼梯上方楼层也存在一个已经被响应但尚未清除的目标导致方向在上行下行之间快速来回切换。解决办法是方向切换之后加一个锁定周期或者把目标楼层清除的时机放到平层确认之后。第二个案例是呼梯灯不灭。电梯停了目标楼层也开了门但HMI上的呼梯指示还亮着。查下来发现是清除呼梯信号的代码写在开门完成之后中途如果门没开到位本次清除不会执行。我改成到达平层信号一确认就清除对应呼梯问题消失。第三个案例是开门状态卡死。电梯停在1楼按理说应该自动开门但是DoorState一直停在正在开门。原因是开门指令被后面的逻辑条件瞬间复位上一行赋值TRUE下一行又来一个IF清零。类似这种问题用断点或分段监控可以很快定位。调试中有一个普遍经验PLC循环扫描是顺序执行的SCL里后写的赋值会覆盖前面写的相同变量。如果你发现逻辑应该生效但没有生效先查一下这个变量在后面的代码里是不是又被覆盖了。6. 收个尾SCL电梯编程的取舍心得这次六层单梯项目做下来我对用SCL写电梯控制有了更实际的感受。第一SCL不是万金油但对这种多状态、多条件、需要频繁改动的控制对象它的表达效率确实比LAD高很多。第二再好的语言也救不了混乱的变量建模顺序一定是先理需求、再建变量模型、写状态机最后才是写IF和CASE。第三电梯程序里安全逻辑永远要独立于运行逻辑之外不能把安全条件混进某个状态机的分支里否则一旦状态机异常安全保护也会被拖下水。如果再让我选一次我依旧会给这个项目配SCL但在程序结构上会更模块化方向决策、目标查找、门控制分别拆成独立小函数每个函数只做一件事调试时可以单独观察。以后如果要扩展双梯并联甚至群控也是一样的思路把单梯逻辑封装好上层再做调度协调SCL的文本化结构很适合写这种调度策略。最后分享一个小细节SCL程序一定要在函数头写清楚输入输出变量注释不要偷懒。博途V15支持在变量列表里直接写注释在线监控时鼠标悬停就能看到。这个东西不起眼但项目结束三个月后再打开程序你会感谢当初认真写注释的自己。