
电梯控制是PLC应用里最经典的“多条件状态机”场景但真正能把逻辑写得干净、调试起来不头大的方案并不多。最近用博途V15TIA Portal V15配合S7-1500系列PLC用SCL语言完整做了一台六层单电梯的控制程序从电梯呼梯登记、方向调度、平层停车到开关门联锁和检修模式全部写成结构化程序。这篇内容不整虚的直接讲清楚我怎么做、为什么这么做、踩过哪些坑给正在学SCL或者准备做电梯项目的朋友一个能直接参考的底稿。先说结论用SCL写电梯不是为了炫技而是因为电梯这种“大量布尔条件 优先级判断 状态记忆”的控制逻辑用梯形图写会散成一片SCL能用数组、循环、结构化条件把这些拧成一股绳。六层单梯虽然不算复杂但麻雀虽小五脏俱全该有的逻辑一个不少做完这一套再上手多梯联动或者更高层数只是量的扩展思路完全能复用。1. 总体设计思路先把电梯拆成几个“独立子系统”1.1 六层单梯的控制需求拆解拿到“六层单梯”这个需求别急着写代码。先坐下来把电梯当成一台状态机来分析我习惯把它拆成五个子系统轿厢内呼登记每层一个按钮按下后登记目标楼层到达后自动消号。楼层外呼登记每层上下行按钮顶层只有下行底层只有上行登记后等待电梯响应响应后消号。运行方向决策根据当前楼层、当前运行方向、还有哪些呼梯信号决定继续走、停车还是换向。平层与开关门控制电梯到站后判断是否平层给出开门命令同时处理开门延时、光幕/安全触板中断、关门联锁。安全保护逻辑门锁回路、超速、限位、检修急停任何一个不满足都要禁止运行。这五块逻辑在程序里不能混成一团否则后期查问题会非常痛苦。我的做法是在博途里用一个FB主函数块内部再划分多个子程序段每段只负责一个子系统段和段之间通过接口变量通信。这样做的好处是将来如果要改成双梯或者加群控每个子系统可以单独拎出来改不影响其他部分。1.2 为什么这次选择SCL而不是梯形图很多老工程师习惯用梯形图这完全能理解毕竟电气图纸出身的人看梯形图就像看电路图。但电梯逻辑有个特点方向决策和呼梯分配本质上是“查找集合中满足条件的元素”这类查询用梯形图写很别扭要么做一堆中间继电器要么用一堆M区地址来回倒腾程序量上去之后可读性直线下降。SCL的优势在三个方面第一数组和循环直接可用。比如六层内呼可以用一个ARRAY[1..6] OF BOOL表示登记就是把对应下标置TRUE消号就是置FALSE查询某层是否有呼梯信号就是遍历数组。梯形图里要实现同样功能你得为每层建一个独立的变量和一批触点程序条数差出一个量级。第二条件分支清晰。方向决策用IF...ELSIF...写出来层次一目了然改逻辑的时候改一行就行。梯形图的复杂分支会画成蜘蛛网改一处经常牵一发动全身。第三SCL可读性强注释能写得更细。我可以在每个段里面用中文注释写上“这一段负责什么、为什么这么判断”半年后回来看自己代码还能看懂同事接手也不会骂人。当然SCL也有短板比如不适合做位运算密集型的底层控制但在电梯这个应用场景里它的优点完全碾压缺点。1.3 调度算法选型不要一上来就搞“智能算法”网上有不少电梯算法的资料什么最短路径优先、动态规划调度的都有。但我必须说一句大实话六层单梯根本用不着那些。单梯调度最优方案就是方向优先法也叫顺向响应法。方向优先的核心规则只有三条如果电梯当前向上运行只响应当前层以上、且方向为向上的呼梯信号以及所有内呼目标层。如果向上方向已经无呼梯可响应则判断是否存在反方向呼梯信号有的话换向。换向后同样只响应新方向同向的呼梯以此类推。这个算法的好处是不会出现电梯反复上下抖动的“振荡”现象逻辑实现简单乘客等待时间在单梯场景下已经非常接近最优。硬要上复杂算法反而会引入状态判断的边界条件增加调试成本。我在这个项目里就采用方向优先把方向判断写成一个独立的、可复用的SCL函数后面升级多梯的时候每台电梯自己跑方向优先上层的群控调度再去做分配层次不混乱。2. 博途V15项目搭建与硬件组态地基打牢后面才不返工2.1 CPU选型考虑博途V15支持S7-1200和S7-1500两个系列的PLC1500系列里有CPU 1511、1513、1515等多个等级。六层单梯的点数需求大概在40到60个数字量左右CPU 1511-1 PN的处理能力完全足够。但如果你打算后期在PLC里做较复杂的数据记录或者要跑Web服务器做远程监控建议直接上CPU 1515程序存储量和处理速度都有富余。我用的是CPU 1511-1 PN具体订货号不写了大家按自己手里硬件来。选型时唯一要注意的是S7-1500有标准型和技术型两种电梯属于运动控制相关应用但单梯调速一般由变频器完成不需要PLC直接做轴定位所以标准型就够了不必花冤枉钱上技术型。2.2 数字量输入输出地址规划I/O分配是整个项目最容易忽略但最影响后期效率的环节。我坚持的原则是地址的编号规律必须和楼层、方向建立明确映射方便程序里写循环和数组处理。建议这样分配以我实际用的地址为例信号说明地址范围备注轿厢内呼按钮I0.0 - I0.5对应1-6层按下为1一层外呼上行I1.0底层只有上行二至五层外呼上行I1.1 - I1.4每层一个上行按钮二至五层外呼下行I1.5 - I2.0每层一个下行按钮六层外呼下行I2.1顶层只有下行一层平层感应开关I3.0各层平层磁开关/光电开关二层平层感应开关I3.1三层平层感应开关I3.2四层平层感应开关I3.3五层平层感应开关I3.4六层平层感应开关I3.5门锁回路反馈I4.0所有层门轿门串联信号门区感应I4.1开门区内有效检修开关I4.2检修时为1上行接触器反馈I4.3下行接触器反馈I4.4变频器运行反馈I4.5变频器故障I4.6输出上行接触器Q0.0输出下行接触器Q0.1输出变频器运行使能Q0.2输出开门继电器Q0.3输出关门继电器Q0.4输出变频器多段速1Q0.5低速输出变频器多段速2Q0.6高速输出电铃/到站钟Q0.7看到没我把楼层相关的输入信号都按低位到高位连续排列这样在SCL里可以直接用FOR循环去遍历楼层信号不用为每一层单独写几条程序。这个细节如果你接手别人的项目看到地址乱排的处理起来有多痛苦你就能体会了。2.3 创建UDT和FB函数块在博途V15里建项目后我习惯先建一个UDT用户自定义类型来存放每个楼层的“呼叫状态”这样做比单独建6个布尔变量干净得多。UDT我就命名为UDT_CallStatus包含几个成员CarCallUp轿厢内呼置位信号CarCallDown轿厢内呼复位信号其实用不到内呼不分方向HallCallUp外呼上行呼叫HallCallDown外呼下行呼叫FloorReached本层是否平层到位然后在变量表里建一个数组变量Call[1..6]类型为UDT_CallStatus这样我只需要操作Call[2].HallCallUp就能访问二层的上行外呼代码可读性非常高。再建一个FB函数块我命名为FB_ElevatorSCL写的所有控制逻辑都在这个块里。FB的好处是每次调用都有自己的背景数据块DB如果你以后要实例化两台电梯只要给FB创建两个不同的DB实例就行不用复制粘贴整套程序。这一点使用结构化编程时必须养成习惯。3. 核心数据区设计把状态变量先安排妥3.1 状态标志体系用什么变量记录电梯“现在在想什么”这部分特别重要。电梯程序写不好多半不是逻辑不懂而是状态变量混乱导致的。我建了一套“四类状态标志”的分层体系大家可以参考运行状态类RunMode、CurrentFloor、TargetFloor、CurrentDirection、RunSpeedStage呼叫记录类上面提到的Call[1..6]数组门控制类DoorOpenCmd、DoorCloseCmd、DoorOpenTimer、DoorForceCloseFlag保护类FaultStop、DoorLockOK、EmergencyStop、MaintenanceMode其中RunMode我定义为整型0表示停止、1表示运行、2表示检修、3表示故障。CurrentDirection也定义为整型-1下行、0停止、1上行。用整型而不是直接用两个布尔量来表示方向是因为SCL里做方向判断时可以直接比较大小写起来简洁得多。这里要特别提醒状态变量的初始值必须提前规划。比如CurrentFloor上电时如果不复位程序不知道电梯在几楼就必须强制要求电梯先低速找平层找到一个平层信号后把CurrentFloor设置为对应楼层。我在程序里专门写了一个“初始定位段”上电后如果CurrentFloor等于0就自动进入低速寻址模式直到某个平层开关有信号才更新楼层值并退出。3.2 内呼信号的登记与消号内呼逻辑很简单但很容易写错的地方是“消号时机”。我的做法是当电梯到达某一层且该层有内呼时如果电梯已经完成平层停车就先消号再开门。SCL代码大概是这样// 内呼登记 IF I0.0 THEN Call[1].CarCall : TRUE; END_IF; IF I0.1 THEN Call[2].CarCall : TRUE; END_IF; // ... 依此类推 // 内呼消号 IF CurrentFloor 1 AND CarCall_Active THEN Call[1].CarCall : FALSE; END_IF;这段逻辑里我用了CarCall_Active这个中间变量它的含义是“本层内呼有效且电梯已经平层”避免电梯还没完全停稳就把呼号消掉导致乘客订单丢失。有些初学者直接把消号写在平层信号之后结果电梯在减速过程中路过平层开关时就把呼号消掉了这是一种非常隐蔽的错误。3.3 外呼信号的方向标记一个容易忽略的坑外呼信号不像内呼只有一层一个它带方向属性。六层建筑的外呼有“上行”、“下行”两种方向首层只有上行顶层只有下行。所以我的UDT_CallStatus里有HallCallUp和HallCallDown两个独立变量。外呼登记后不要急着置方向标志。电梯换向与否取决于“当前方向下还有没有同向呼梯”。“外呼信号只是乘客的这个方向的请求不代表电梯必须立即运行这个方向”这句心得我在带徒弟时反复强调。举个例子电梯在一层此时三层有人按了下行外呼同时二层有人按了上行外呼。电梯启动向上走到二层停下接上行乘客继续上行到三层。到三层后电梯当前上行方向已经无呼梯可响应再判断“下行方向是否有呼梯”——发现有于是换向下行开门让三层的下行乘客进入电梯再带着乘客下行。这是一个完整的方向优先调度循环。4. 核心SCL程序实现从方向判断到平层停车的完整逻辑4.1 方向判断整个电梯最容易出Bug的地方方向判断的逻辑我写成独立程序段放在FB内部靠前的位置因为后面所有运行段都要引用方向结果。// 上行方向需要响应的条件 #UpNeed : FALSE; FOR #i : #CurrentFloor 1 TO 6 BY 1 DO IF #Call[#i].CarCall OR #Call[#i].HallCallUp THEN #UpNeed : TRUE; END_IF; END_FOR; // 如果当前电梯停止且目前没有运行方向则根据呼叫决定方向 IF #CurrentDirection 0 THEN IF #UpNeed THEN #CurrentDirection : 1; ELSIF #DownNeed THEN // 下行条件类似从当前层的下方找 #CurrentDirection : -1; ELSE #CurrentDirection : 0; END_IF; END_IF;这段代码里我用了FOR循环和数组配合用一行循环代替了梯形图里六层全部触点的串联并联。这就是SCL的优势所在。写的时候注意循环边界上行查找要从CurrentFloor1开始不能包含当前层因为当前层应该已经处理过平层逻辑。4.2 运行段变速与平层检测的配合电梯运行不像电机启保停那么简单它要经历加速、匀速、减速、平层四个阶段。我程序里的运行段核心思路是启动时输出高速运行信号多段速2同时计时器开始计时。当检测到目标楼层的前一个楼层感应开关时切换为低速运行信号多段速1。当检测到目标楼层的平层开关时立即切断运行接触器和变频器使能然后给出制动信号本项目用变频器内置直流制动PLC只给停车命令。代码大概长这样// 高速运行段 IF #RunMode 1 AND #CurrentDirection 0 THEN #Q_HighSpeed : TRUE; #Q_ContactUp : (#CurrentDirection 1); #Q_ContactDown : (#CurrentDirection -1); #Q_InvEnable : TRUE; END_IF; // 减速判断如果目标楼层在第N层路过第N-1层感应开关时降速 IF #CurrentDirection 1 AND #TargetFloor #N THEN IF #FloorSensor[#N-1] THEN #Q_HighSpeed : FALSE; #Q_LowSpeed : TRUE; END_IF; END_IF; // 平层停车 IF #FloorSensor[#TargetFloor] AND #LowSpeedRunning THEN #Q_ContactUp : FALSE; #Q_ContactDown : FALSE; #Q_InvEnable : FALSE; #RunMode : 0; // 进入停止状态 #DoorOpenCmd : TRUE; // 触发开门 #CurrentFloor : #TargetFloor; END_IF;这个版本的逻辑是个简化示例实际项目里还要加入“运行超时保护”“目标楼层丢失保护”。比如电梯运行了20秒还没检测到目标楼层可以判定为故障立即停车并报警。这种保护逻辑我下面专门讲。4.3 开关门逻辑安全永远是第一优先级开关门是电梯最容易出安全事故的地方这里必须强调几个硬性安全原则开门继电器输出前一定要确认电梯处于停止状态RunMode 0。关门继电器输出前一定要确认门锁回路反馈有效DoorLockOK TRUE而且开门延时已到。门区感应DoorZone在轿厢不在门区时不允许开门。无论任何情况只要检测到光幕/安全触板信号开门命令保持关门命令强制断开。开门逻辑我用了TON定时器做开门保持时间。SCL里调用定时器不像梯形图那么直观但掌握了方法其实更灵活TON_DoorOpenTimer( IN : #DoorOpenCmd, PT : T#20S, Q #DoorOpenTimerOut, ET #DoorOpenElapsed );这个定时器的含义是开门命令有效后开始计时20秒后定时器输出导通。在自动模式下我判断DoorOpenTimerOut再执行关门动作就实现了“开门后保持20秒再自动关门”。如果中间有人挡光幕需要把定时器复位重开或者把定时器的IN条件改为“开门命令且无光幕遮挡且门区正常”这样更保险。4.4 保护逻辑宁可错停不可错行电梯程序里保护逻辑是超高优先级的我把它放在所有逻辑段之前用IF FaultStop THEN ... RETURN的技巧直接旁路掉运行逻辑。SCL里在FB内可以用RETURN提前返回这是梯形图做不到的。我的保护段大概检查这些条件门锁回路断开时立即断开上下行接触器和变频器使能。变频器故障信号为1时禁止任何运行命令。上下行接触器反馈同时有信号时这在实际中意味着接触器粘连或短路必须判定严重故障。运行超时保护启动后超过设定时间仍无平层信号立即停梯报警。检修模式下自动逻辑完全旁路只能通过手动按钮控制点动运行且点动运行不与任何呼梯逻辑关联。// 核心保护段放置在最前 IF #EmergencyStop OR #DoorLockOK FALSE THEN #Q_ContactUp : FALSE; #Q_ContactDown : FALSE; #Q_InvEnable : FALSE; #Q_HighSpeed : FALSE; #Q_LowSpeed : FALSE; #RunMode : 3; // 故障状态 RETURN; END_IF; IF #MaintenanceMode THEN // 检修逻辑点动控制不走自动流程 #RunMode : 2; END_IF;这里要特别说下门锁回路。电梯的门锁回路是串联所有层门和轿门的一组信号任何一层门没关好门锁回路都不通。运行中如果门锁回路突然断开要立即停车而且不能直接恢复自动运行必须等人为确认故障后才能复位。我程序中专门用了一个FaultLatch锁存变量就是为了做到“故障保持”禁止自动复位。4.5 到站钟与楼层显示到站钟和楼层显示属于外围功能逻辑不复杂但做好能提升使用体验。楼层显示我用一个整型变量DisplayFloor传给HMI的IO域显示。到站钟我做了个脉冲信号平层停车时输出一个0.5秒的脉冲电铃。// 到站钟脉冲 #ArrivalPulse : FALSE; IF #PreviousRunMode 0 AND #RunMode 0 THEN #ArrivalPulse : TRUE; #ArrivalTimer(IN : TRUE, PT : T#500MS); END_IF; IF #ArrivalTimer.Q THEN #ArrivalPulse : FALSE; END_IF; #Q_Bell : #ArrivalPulse;5. 调试过程实录博途V15里怎么高效排查电梯程序5.1 用好PLCSIM做纯软件仿真我这个项目在实际硬件通电之前先在博途V15的PLCSIM里做了完整的软件仿真。PLCSIM可以模拟数字量输入的变化我把程序下载到虚拟PLC后用PLCSIM的变量表模拟按钮按下观察程序的响应。有一个很实用的技巧把FB里的关键状态变量CurrentFloor、CurrentDirection、RunMode、DoorOpenCmd全部添加到“监视表格”里仿真过程中实时观察这几个值的变化逻辑对不对一眼就能看出来。特别是方向判断那段我是用表格强制修改Call数组里的呼梯信号一步步验证“上行响应”“下行响应”“换向”“反向响应”四种情况是否和预期一致。还有一个好用的工具是博途里的“Trace”功能也就是轨迹记录。它能把变量值随时间的变化画成曲线非常适合分析电梯加减速切换时机。我在调整关门延时和开门保持时间时就用Trace同时监测了门命令、门锁反馈和时间曲线效果非常直观。可惜Trace在有些精简版软件里不能用如果打不开就退回到监视表格手动记录状态变化也能凑合。5.2 硬件调试的坑变频器参数和PLC程序的配合到了现场通电调试最大的坑往往不在PLC程序而在变频器和PLC的配合上。变频器接收PLC的多段速信号需要把频率给定方式设为“多段速端子给定”并且把对应端子功能设为多段速1、多段速2。如果端子参数没设对就会出现PLC输出信号了电机却不转或者转速不对第一反应以为是PLC程序写错了查半天才发现是变频器参数问题。我用的是普通三相异步电机加变频器方案速度分两档低速约15Hz用于找平层和检修点动高速约50Hz用于正常运行。PLC给出的高速/低速信号直接在变频器的多段速端子上选频率不需要走通讯配置简单可靠。另一个必须注意的问题是上下行接触器的电气互锁。PLC程序里我虽然保证了不会同时输出上行和下行但为了防止接触器触点粘连等情况造成机械短路我在外部接线里还必须加硬互锁触点——上行接触器的常闭触点串联在下行接触器的线圈回路里反之亦然。这一点我写进程序注释里目的是提醒看这篇文章的人程序互锁不能替代硬件互锁电梯这种高危设备必须双层保护。5.3 HMI联调虚拟HMI和实际触摸屏的差异如果项目配了HMI建议用博途里集成的SIMATIC WinCC做画面。我做了主监控画面和检修画面两个页面主画面显示当前楼层、方向箭头、内外呼按钮和开关门状态检修画面单独显示每个输入信号的状态方便现场诊断。这里分享一个小经验HMI上的楼层按钮最好用“置位按钮”或“瞬时按钮”尽量不要用“切换按钮”。因为呼梯按钮按下后应该保持“已被登记”的状态但如果HMI上的按钮被设成自锁型乘客按第二下反而会取消呼梯不符合电梯使用习惯。正确的做法是HMI按钮触发PLC里的置位指令PLC在消号时再复位HMI按钮本身用瞬时模式显示状态绑定到PLC的呼叫记录变量上。联调中最常见的问题是通讯组态不对导致PLC和HMI连不上。S7-1500和精智面板之间用的PN/IE通讯在组态时必须确保PLC和HMI在同一个子网里IP地址在相同网段且HMI的“连接”配置里选择了正确的PLC。这些如果以前没做过第一次联调容易卡壳照着博途的网络组态向导一步步来就能绕开。6. 常见问题与排查技巧这些坑我都替你踩过了6.1 电梯到了目标层附近却不减速不停车这是最常见的Bug排查思路按优先级来先看减速信号也就是#FloorSensor[#N-1]有没有被触发。很多时候是平层感应开关的安装位置偏了尤其感应开关在井道里磁铁安装距离太近或太远都可能导致感应不到。再看目标楼层变量确认TargetFloor是不是正确被赋值。我遇到过内呼信号到站前被意外消号的情况检查后发现是CurrentFloor更新得太早电梯还没停稳就被当成“已经到站”把目标层覆盖了自然就不会停车。最后看平层信号是不是抖动。如果平层开关用的是干簧管或光电传感器可能会在减速振动时产生瞬间脉冲导致程序误判平层。对策是在SCL里加一个去抖计时器平层信号要保持20ms以上才认为是有效平层。6.2 电梯方向信号反复切换出现“抖方向”方向判断段如果写得不好会有一种典型故障电梯在上行过程中因为反复查看是否有下行呼梯导致方向标志位在上行和下行之间来回跳变接触器咯咯响。解决办法就是坚持“运行中方向不改变”的原则。在SCL里只有当CurrentDirection 0停止状态时才允许重新判断方向一旦运行开始方向只能在停车并完成开关门周期后才能改变。代码里用一个DirectionLock变量运行启动时置TRUE停车后清FALSE方向判断段只在DirectionLock FALSE时才执行。这招基本能根治抖方向。6.3 检修模式下的安全逻辑检修模式也叫慢车模式在很多项目中是容易被忽略的点但它恰恰是维保人员生命安全的关键。我的做法是检修信号接入PLC后自动模式下的所有呼梯响应全部失效——不是简单不执行而是要把Call数组全部清零。检修时只能通过轿顶检修盒的上下按钮点动运行且运行速度必须限制在低速15Hz以下。检修时门锁回路依然有效门没关好点动也不能运行。在SCL里实现“自动逻辑失效”最简单的方式在方向判断段和运行段的外面套一个IF #MaintenanceMode FALSE THEN ...IF #MaintenanceMode FALSE THEN // 正常自动运行的呼梯响应和方向判断 ELSE // 检修点动逻辑 #Q_InvEnable : #ManualUp OR #ManualDown; #Q_ContactUp : #ManualUp; #Q_ContactDown : #ManualDown; // 检修时禁止高速 #Q_HighSpeed : FALSE; #Q_LowSpeed : TRUE; END_IF;要注意检修和正常运行不能同时生效最好在外部硬件上直接把检修开关串联在自动运行回路里保证检修时自动回路物理断开这才是双重保护的做法。6.4 博途V15使用中的一些软件层面的坑软件本身也有一些需要适应的地方。比如SCL编辑器对中文注释的支持有时会出现显示异常我的习惯是变量名用英文或拼音注释用中文这样即使编辑器字体有问题程序逻辑也不受影响。另外一个坑是SCL的FOR循环里不能直接修改数组的元素数量数组大小是编译期决定的。要把楼层数改成可配置的话只能先定义足够的数组空间然后用一个MAX_FLOOR常量控制循环边界我习惯在FB顶部定义一个内部常量CONST MAX_FLOOR : 6; END_CONST以后要改成八层只需要把这个常量改成8循环边界自动扩展不需要动所有逻辑代码。7. 一点个人体会和后续扩展建议这个六层单梯的SCL项目做完之后我最大的体会是SCL的价值不在语言本身而在于它逼着你先把问题想清楚再用结构化的方式去表达。梯形图的思路往往是“这段电路能不能再加一个触点”SCL的思路则是“这个状态集合还缺什么条件、需要什么查找逻辑”。当程序规模上到一定程度后者的维护优势会越来越明显。如果你照着这篇文章从头搭过一遍接下来可以尝试三个方向继续扩展把方向优先算法封装成一个独立的函数FC输入当前层、方向、呼梯数组输出目标层和是否换向这样逻辑可以单测也方便移植。加上密码控制的直达层功能比如物业专用层只能通过轿厢内指定钥匙开关进入外呼按钮在这层失效这是高层项目常见的标配功能。如果有多台电梯做一个简单的群控层每台电梯都跑方向优先群控调度器只负责把外呼信号分配到最合适的一台梯上。这个方案比改单梯逻辑简单得多也更容易调试。最后再分享一个调试习惯电梯程序改完后先用PLCSIM把所有按钮信号按“底层到顶层再到底层”的顺序模拟跑一遍不要直接上电。把自动运行、检修、故障保护三条流程都验证过了再动硬件能省下大量现场返工时间。做电梯稳永远比快重要。