一台六层电梯,听起来不算复杂,但真正从零开始写PLC程序的时候,才能体会到什么叫“麻雀虽小,五脏俱全”。楼层呼叫的逻辑、平层停车的精度、开关门的时序、安全回路的冗余——每一个环节都直接关系到设备能不能稳定运行、乘客敢不敢坐。这篇文章记录了我用西门子S7-1200和博图V15.1开发单部六层电梯程序的完整过程,包括需求拆解、控制算法设计、代码实现和现场调试踩过的坑。
全文以实战为主,不会只讲空泛的理论,而是尽量把我当时的设计思路、程序结构、关键代码片段和调试细节都摊开来讲。无论是刚接触PLC的小白,还是准备做类似改造项目的工程师,都可以参考这套逻辑,结合自己的实际工况进行修改。
1. 需求拆解与IO点规划:动工之前先算清账
很多第一次做电梯项目的朋友容易上来就写程序,结果写到一半发现输入输出点不够用,或者某个信号不知道接到哪里,再回头改硬件布局,非常被动。我的习惯是先把需求彻底拆干净,算清楚IO点,再动博图。
1.1 六层电梯到底有多少个信号
单部六层电梯,先盘一下它有哪些功能需求:
- 轿厢内操作:每层一个内选按钮,共6个,带自复位和指示灯;
- 楼层外呼:每层有上/下呼叫按钮。一层只有上行,六层只有下行,中间层上下行都有,一共10个按钮,每个按钮也带指示灯;
- 楼层检测:每层一个平层感应开关(接近开关或永磁感应器),共6个;
- 轿厢位置显示:7段码或点阵显示,这里走IO输出,不算模拟量;
- 开关门控制:开门继电器、关门继电器、门锁反馈、光幕/安全触板信号;
- 安全类信号:急停、超载、上下极限限位、检修开关、变频器故障反馈;
- 速度控制:给变频器的启动、方向指令和速度给定信号。
统计下来,需要开关量输入大概在30点上下,开关量输出也在25点以上(含指示灯和显示),再加上模拟量速度给定1路。这个量级用S7-1200自带的集成IO往往不够,需要扩展模块。
1.2 硬件选型与地址分配
我这次用的是CPU 1214C DC/DC/DC,集成14DI/10DO,外扩一块SM 1223(16DI/16DO),再加上一块SM 1232模拟量输出模块(或者直接用S7-1200本体上的模拟量输出,1214C本体没有模拟量输出,所以必须扩展)。实际用下来,这样刚好把IO点全部覆盖住,还留了两个备用点。
分配地址的时候,一定要按功能分区,不能想到哪接到哪。我的划分规则是这样的:
| 功能区域 | 输入地址范围 | 输出地址范围 |
|---|---|---|
| 楼层平层与极限保护 | I0.0-I0.7 优先给平层感应器 | Q0.0-Q0.3 楼层显示低4位 |
| 轿厢内选与指示灯 | I1.0-I1.5 | Q1.0-Q1.5 |
| 外呼按钮与指示灯 | I2.0-I2.7(一组) | Q2.0-Q2.7 |
| 门系统与安全 | I3.0-I3.5 | Q3.0-Q3.5 |
| 变频器控制 | I4.0-I4.3 | Q4.0-Q4.3 |
具体的地址只要自己定一套规则并且写在变量表里注释清楚就行,但有个建议:平层感应器要优先占用连续地址,因为后面做楼层位置判断的时候,用字读取或者循环移位会非常方便。我一开始没注意这个,结果平层信号分散在I0.0、I0.4、I1.3这些乱七八糟的位置,写楼层比较逻辑的时候简直灾难,后来重新接线才理顺。
2. 方向判定与楼层停靠:电梯的大脑怎么设计
电梯程序里最容易写乱的就是方向判定。因为电梯不像普通设备那样只靠“启动/停止”就能工作,它需要自己在多个楼层呼叫请求中决定先去哪、途径哪些楼层不停地。
2.1 三种常见调度策略的取舍
我梳理过几种常见策略,给大家做个参考:
- 最远端呼叫优先:电梯响应离当前楼层最远的呼叫,跨楼层运行效率高,但顺路捎客的效果太差,高峰期体验不好;
- 先应答同方向呼叫,再反向响应:也就是“顺向截梯”。电梯上行时只响应上行方向的呼叫,下行时只响应下行方向的呼叫,直到当前方向的最远端无请求后才换向;
- 时间优先/楼层距离加权:这是群控才需要玩的东西,单梯没必要把算法搞那么复杂。
对于单部六层电梯,我最终选了第二种,顺向截梯。它是民用电梯最主流的逻辑,乘客体验好,代码实现也不复杂。逻辑上可以概括成两条规则:
- 电梯在某方向运行时,经过的楼层如果有该方向的呼叫,就停靠;
- 到达当前方向最远的呼叫楼层后,若还存在反方向呼叫,则换向继续服务。
2.2 用位逻辑实现呼叫登记与顺向截梯
在PLC里我专门用了一个DB块存所有呼叫信号,每个楼层每方向的呼叫用一个布尔变量保存,同时定义两个关键的字变量:
UpCallWord:位0~位5对应1~6层的上行呼叫;DownCallWord:位0~位5对应1~6层的下行呼叫。
为什么用字而不是用一堆Bool?因为我可以直接对字做循环右移/左移,非常轻松地判断“当前方向前方是否还有呼叫”。这比逐个比较Bool变量省太多事了。
上行方向的判断逻辑可以写成:
// 上行时,提取当前层以上所有上行呼叫 FOR i := currentFloor TO 6 DO IF upCall[i] THEN hasUpCallAhead := TRUE; END_IF; END_FOR;不过直接用FOR循环在OB1里扫会有点浪费时间,我实际用的是移位方式:把UpCallWord右移当前层位数,剩下的位里只要非零,就说明该方向前方有呼叫。程序更简洁,扫描周期也更短。
2.3 方向切换与最远端目标的计算
换向的判定条件是:当前方向的所有呼叫已经全部处理完,且另一个方向还有呼叫。具体到程序里,我需要实时维护两个变量:
UpCallsPending:上行方向尚未响应的呼叫总数;DownCallsPending:下行方向尚未响应的呼叫总数。
每次电梯平层开门、关门之后,就去刷新这两个计数。当电梯正在上行且UpCallsPending变成0,同时DownCallsPending大于0,就置位换向请求。在换向前要让电梯先停在某一个楼层完成一次完整的开关门,再进行方向切换。
这里有个容易踩坑的点:如果电梯上行过程中,有人在一楼按了上行呼叫,这时候UpCallsPending会立刻大于0,电梯可能会在下完客后直接往下跑响应这单呼叫——但正确的逻辑应该是电梯继续上行把当前方向所有楼层服务完,等再换向的时候去响应。
所以在换向判定时,我额外加了一个“同向服务未结束标志”,只有当前方向所有同向呼叫清零后,才允许把另一个方向的新呼叫计入换向判断。这个细节不处理好的话,电梯很容易在中途频繁变向,乘客会觉得电梯“疯了”。
3. 平层、开关门与速度曲线:从逻辑层落到执行层
方向算法只是大脑,真正让乘客有感知的是平层精度、开关门节奏和加减速的平滑度。这部分的调试花了我超过一半的时间。
3.1 平层信号怎么接才能停得准
六层电梯我用的方案是每层装一个独立的平层感应器,轿厢侧安装遮磁板。这种方式结构简单、改造成本低,很常见。但平层精度完全取决于感应器与遮磁板的相对位置调试。
安装要点:
- 遮磁板的长度要大于感应器感应面10毫米以上,确保停车过程中信号有足够的保持区间;
- 感应器输出要接成NPN常开,遮磁板进入感应区域时输出1;
- 调试时用变频器检修速度(低速)运行,反复调整遮磁板位置,以电梯停稳后轿厢地坎与层站地坎误差不超过5毫米为准。
如果现场要求更高精度,可以考虑旋转编码器加变频器闭环,但逻辑程序这块反而比感应器方案好写,因为不需要处理“信号保持区间”的问题。
我这次用的还是感应器方案,平层过程分成两段:
- 距离目标楼层还有一个平层感应器间隔时(通过当前楼层和目标楼层差判断),下发减速信号;
- 进入平层感应区域,连续检测到感应信号后,输出停车指令,同时变频器零速给定。
3.2 开门关门时序与防夹逻辑
开关门看起来简单,其实时序对乘客体验影响很大。我定的顺序是:
- 电梯平层停车且抱闸动作后,延迟300ms,确认无溜车,输出开门继电器;
- 开门到位信号返回后,保持开门状态;
- 开门保持时间根据是否有内呼或外呼动态调整:有呼叫时3秒,无呼叫时5秒;
- 开门时间到,且光幕、安全触板无遮挡,输出关门继电器;
- 门完全关好后,门锁信号闭合,电梯才能重新启动。
防夹逻辑必须独立于主流程,一旦光幕触发,立即给出“重新开门”命令,同时复位关门继电器。这里要加一个软件防抖:光幕信号持续时间超过100ms才认为是真遮挡,否则一些飞虫、灰尘干扰就会导致电梯反复开关门。
3.3 速度给定与换速点处理
速度给定我用的是模拟量输出,0~10V对应变频器的0~50Hz。但直接给阶跃给定会让人站着都晃一下,所以程序里做了斜坡给定。
斜坡的本质就是:每次扫描周期把实际给定值朝目标值递增或递减一步。步长要现场调,起步和到达前的步长要小一些,中间运行可以适当加大步长。
实际给定 := 实际给定 + 速度步长 * 方向;换速点的计算是关键。六层电梯楼层间距可能不一样,不能简单地按“距离目标楼层的楼层数”来换速。我是在每次运行前,根据当前楼层和目标楼层计算出减速距离,当实际运行距离接近减速距离时,把给定速度降到低速爬行值。
这个距离其实是估算的,因为我没有用编码器,采用的是“平层感应器计数+时间估算”的混合方式。更简单可靠的方案是直接让变频器自己处理S曲线加减速,PLC只给启停和方向信号,但前提是变频器的多段速或内部斜坡参数设置合理。
4. 安全回路设计:PLC可以出故障,人不能出事
电梯是载人设备,安全逻辑设计必须比普通设备严格一个量级。这也是我这次开发中强调最多、查资料最多的部分。
4.1 哪些保护必须做在硬件上,不能只靠程序
有个原则必须刻在脑子里:涉及人身安全的保护回路,必须独立于PLC硬件。PLC死机、程序跑飞、输出模块烧毁的时候,硬件安全回路必须能把电梯停下来。
我当时的硬件安全回路接法是:
- 急停按钮串联在安全继电器回路上;
- 上下极限限位开关串联在安全继电器回路上;
- 门锁信号直接串在运行接触器线圈回路上,门没关好,即使PLC输出启动信号,接触器也合不上;
- 超载信号通过独立继电器切断启动允许回路。
PLC程序里的安全逻辑,只是给控制系统层面再加一道软件保险,不能指望全靠它。这一点我在项目的技术方案评审时特别写过说明,现场电工师傅也都认可这个观点。
4.2 程序里的互锁与联锁逻辑
程序内我做了这么几个核心联锁:
- 方向互锁:上行接触器和下行接触器不能同时吸合。即便硬件回路已经做了机械互锁,程序里依然要双保险。输出的写法是:
IF upCommand AND NOT downCommand THEN QUp := TRUE; ELSE QUp := FALSE; END_IF; IF downCommand AND NOT upCommand THEN QDown := TRUE; ELSE QDown := FALSE; END_IF;- 开门禁止运行:只要门未关好或者门锁信号断开,运行方向输出必须清零;
- 检修模式优先:检修开关闭合时,自动运行逻辑全部旁路,只能点动检修速度运行;
- 终端限位联锁:上楼时如果上极限被触发,无论任何条件,立即切断上行输出;
- 超载联锁:超载信号有效时,电梯不响应任何运行指令,但保持开门,并给出门不关的提示。
4.3 检修模式与自动模式的切换
检修模式是维护电梯时的必要功能,极容易被忽略。我专门做了一个“运行模式”变量,0代表自动,1代表检修。
检修模式下:
- 内呼、外呼全部失效;
- 上下行用长动按钮点动控制,按住才动,松开即停;
- 速度强制为检修速度,不允许高速运行;
- 平层信号只做参考,不做精确停车判断;
- 开关门由维护人员手动控制。
在博图里我用的方式是:在主控制FC前面加一个模式选择分支,检修模式直接调用单独的FC_ServiceMode,自动模式才走正常流程。这样两个逻辑完全隔离,不怕误触发。
5. 博图V15.1项目结构与核心代码片段
前面讲了不少设计思路,这一节把博图项目的实际结构和关键代码贴出来,给准备上手的同行一个参考框架。
5.1 程序块划分与数据管理
我把程序拆成下面这些块:
| 程序块 | 用途 |
|---|---|
| OB1 | 主循环,按顺序调用各功能FC |
| FC_FloorDetect | 楼层位置检测与更新 |
| FC_CallRegister | 呼叫登记与指示灯刷新 |
| FC_Direction | 方向判定与目标楼层计算 |
| FC_SpeedCtrl | 速度给定与换速处理 |
| FC_DoorCtrl | 开关门时序控制 |
| FC_Safety | 安全联锁与故障停机 |
| FC_ServiceMode | 检修模式独立逻辑 |
| DB_Common | 电梯运行状态共享数据块 |
| DB_Calls | 呼叫登记数据块 |
这种按功能划分的方式,后期调试时找问题非常方便。比如现场反馈门关不上,直接监控FC_DoorCtrl里的变量就行,不用在一大坨程序里翻来翻去。
5.2 核心SCL代码:呼叫登记与方向判定
呼叫登记这段我用的是梯形图+SCL混编,梯形图处理按钮信号,SCL处理逻辑运算。下方是简化版SCL:
// 内呼登记 IF "1楼内呼按钮" THEN "DB_Calls".InnerCall[1] := TRUE; END_IF; // ... 此处省略2~6楼 // 外呼登记 IF "1楼上呼按钮" THEN "DB_Calls".UpCall[1] := TRUE; END_IF; // ... 此处省略其他楼层外呼 // 顺向截梯判定:电梯上行时,检查当前层以上是否有同向上呼或内呼 "临时字变量" := 0; FOR i := "当前楼层" TO 6 DO IF "DB_Calls".UpCall[i] OR "DB_Calls".InnerCall[i] THEN "临时字变量" := 1; END_IF; END_FOR; IF "临时字变量" = 1 THEN "保持上行方向" := TRUE; END_IF;这段逻辑在六层规模下性能完全够用。层数再多一点,比如十层以上,建议把FOR循环改成移位运算或者Table寻址,保证扫描周期稳定。
5.3 平层停车与开关门控制代码
平层停车判断这段我额外加了信号保持功能,防止感应器在临界位置时信号抖动导致重复判断。用延时接通定时器解决,延时时间设为50ms左右:
// 平层信号防抖 "平层防抖输出" := "平层感应器信号"; TON_Instance(IN := "平层感应器信号", PT := T#50MS); IF "平层防抖输出" AND "目标楼层" = "当前位置" THEN "平层到位" := TRUE; END_IF;开关门控制我采用的是状态机写法,四个状态:空闲、开门中、开门保持、关门中。状态之间的迁移条件前面已经讲过,这里提一句:状态机写法虽然代码长一点,但可读性和稳定性都远超用定时器堆出来的时序逻辑。
6. 模拟与现场调试记录:坑都在这一步暴露
程序写完只是第一步,调试才是最考验人的。我用博图的PLCSIM做了很多轮模拟验证,但真到了现场,还是被现实狠狠教育了几次。
6.1 PLCSIM仿真能帮你验证什么,不能验证什么
PLCSIM能帮你验证逻辑层面的东西,比如顺向截梯算法正不正确、换向条件合不合理、呼叫登记有没有遗漏,这些用仿真完全可以跑明白。方法是把输入变量虚拟成按钮,用“手动修改输入”功能模拟呼叫信号,看着监控表里的状态变化来判断逻辑是否正确。
但仿真验证不了下面这些现场问题:
- 平层感应器实际安装的物理偏移;
- 门锁信号接触不良带来的抖动干扰;
- 变频器运行时的电磁干扰对模拟量信号的影响;
- 机械惯性引起的溜车和过冲。
所以别以为仿真跑通了现场就能一次过,这两者之间有很长的距离。
6.2 现场调试遇到的三类疑难杂症
第一类是门锁信号抖动。电梯关门瞬间,门锁触点经常出现短暂通断,导致PLC误判门开门,运行指令被切断,电梯“一冲一顿”。我处理的办法是:读门锁信号时做了50ms的接通延时,只有门锁稳定闭合50ms以上才认为真正关门到位。
第二类是模拟量速度给定的干扰。刚开始用屏蔽电缆直接走线槽,变频器一启动,速度给定就跳动,电梯在低速爬行段一顿一顿的。后来把模拟量线单独走金属管,且在PLC输出端并联了一个1000pF的滤波电容,干扰才基本消除。这个问题在变频器功率较大时尤其明显,建议大家从一开始就重视弱电布线的屏蔽和分层。
第三类是平层停车冲过头。电梯从高速直接给停车信号,因为抱闸机构和负载惯性,每次停的位置忽高忽低,误差能到3厘米。后来我改成“先减速爬行,再停车”的两段式逻辑,并且延时200ms给抱闸信号,让电梯在零速状态稳定一下再抱闸,误差降到5毫米以内。
6.3 版本与固件兼容的注意点
博图V15.1可以连接S7-1200的绝大多数固件版本,但我遇到过一台CPU固件是V4.5的设备,在V15.1里下载程序时提示“设备不支持该功能”,后来是先把博图升级到V16或V17才解决的。
另外1200的PLC程序下载前一定要检查“设备组态”中的硬件型号和固件版本与实际设备一致,否则下载时会报“硬件配置不匹配”。具体操作是在博图左侧项目树里找到PLC,右键“属性”,查看固件版本,然后修改设备组态使其匹配。
关于版本问题,我的经验是:项目一开始就确认好现场设备的固件版本,并且用对应版本的博图建项目。如果像我们这次是给旧设备改造,更要提前确认,不然到现场才发现版本不对,整个进度都会受影响。
还有一个小细节:PLC的IP地址和电脑必须在同一个网段,下载时如果找不到设备,先ping一下PLC地址,不通的话检查网线和防火墙。这个坑很多人遇到过,其实基本不是PLC坏了,就是电脑防火墙拦截了博图的通信端口。
最后的个人体会
这套电梯程序改到今天,前后跑了三个多月,最深的感触是:电梯项目真正难的从来不是某个复杂的算法,而是把所有常规逻辑做得绝对可靠。一次呼叫漏登记、一次换向判断失误、一次门锁抖动没滤掉,看着都是小问题,但放到载人设备上就是安全隐患。
我自己的习惯是,每次现场处理完一类问题,就在程序注释里写清楚问题出现的前提和解决办法,方便下次直接查。程序不是一次写出来的,是靠一遍遍调试“磨”出来的。这也是我认为PLC项目最有价值的部分——你踩过的每一个坑,都是别人在文档里查不到的实战经验。希望这篇记录能帮到准备做电梯或类似定位控制项目的朋友,至少少走几步我们走过的弯路。