PLC顺序控制实战:定时器与比较指令实现电机顺序启停
1. 项目缘起:一个经典但易错的工业控制场景
在工厂的自动化产线上,我们经常会遇到这样的需求:几台电动机需要按照特定的顺序启动,比如先启动主传动电机,再启动送料电机,最后启动冷却风机;而在停机时,又需要按照相反的顺序关闭,比如先停冷却风机,再停送料电机,最后停主传动电机。这个“顺序启动、逆序停止”的逻辑,听起来简单,但真要在PLC里把它做稳定、做可靠,里面有不少门道。
我最早接触这个需求是在一个物料输送系统的改造项目里。当时产线要求三台电机顺序启动,间隔5秒;逆序停止,间隔3秒。最初的方案是用多个延时继电器硬接线搭出来的,线路复杂不说,还经常因为继电器触点抖动导致顺序错乱,维护工每次排查都得对着图纸琢磨半天。后来改用PLC控制,逻辑清晰了,但第一次编程时我也踩了坑——只考虑了正常的启停按钮信号,没处理好急停和故障复位时的状态,结果在一次模拟测试中,急停后恢复,电机“哗”一下全同时启动了,差点造成机械干涉。
所以,今天我就结合自己多次实战和踩坑的经验,来详细拆解一下,如何用PLC里最基础的定时器指令和比较指令,稳健地实现多台电机的顺序启停控制。这个方案不依赖复杂的顺序功能图或高级指令,用最通用的梯形图就能实现,而且逻辑透明,易于调试和维护,非常适合中小型项目或者作为理解更复杂顺序控制的基础。
2. 核心控制逻辑与电气原理图设计
在动手写程序之前,我们必须先把控制逻辑和外围电路理清楚。程序是大脑,电路是手脚,手脚不灵光,大脑再聪明也白搭。
2.1 “顺序起动、逆序停止”的工艺要求详解
我们以一个经典的三台电机(M1, M2, M3)控制系统为例,把工艺要求具体化:
- 启动过程:按下启动按钮后,M1立即启动;延时T1秒后,M2自动启动;再延时T2秒后,M3自动启动。至此,所有电机启动完毕。
- 停止过程:按下停止按钮后,M3立即停止;延时T3秒后,M2自动停止;再延时T4秒后,M1自动停止。系统回到待机状态。
- 安全与故障处理:
- 任何时刻按下急停按钮,所有电机必须立即无条件停止。
- 系统运行中,若某台电机发生过载故障,该电机及其所有后续启动的电机应立即停止,而先于它启动的电机则应按逆序延时停止。例如,若M2故障,则M2和M3立刻停,M1则在延时T4后停止。这模拟了故障连锁和系统安全泄放的过程。
- 系统必须具备“启动中”和“停止中”的状态指示,方便操作人员监控。
2.2 主电路与控制电路设计要点
虽然重点是PLC程序,但硬件设计是根基。这里给出关键的设计注意事项:
主电路:每台电机依然采用经典的“断路器+接触器+热继电器”保护模式。接触器(KM1, KM2, KM3)的线圈由PLC的输出点驱动。热继电器(FR1, FR2, FR3)的常闭触点应接入PLC的输入点,作为故障信号,而不是仅串在接触器线圈回路中。这样做的好处是,PLC可以精确知道是哪一台电机故障,从而执行上述复杂的故障顺序停止逻辑。
控制电路:给PLC的输入信号至少应包括:
I0.0: 启动按钮(常开)I0.1: 停止按钮(常开)I0.2: 急停按钮(常闭,接入常闭点并使用正逻辑,或接入常开点但在程序里取反)I0.3,I0.4,I0.5: 电机M1, M2, M3的热继电器故障信号(常闭触点,故障时断开)I0.6: 系统复位按钮(用于故障复位)
PLC的输出点驱动:
Q0.0,Q0.1,Q0.2: 分别驱动接触器KM1, KM2, KM3的线圈。Q0.3,Q0.4: 可用来驱动“系统运行”和“系统停止中”指示灯。
注意:急停按钮必须采用硬件优先的原则。除了接入PLC输入点参与逻辑处理外,强烈建议将其常闭触点直接串联在PLC输出回路的总电源或所有接触器线圈的公共端上。这样即使PLC程序跑飞或通信故障,拍下急停也能物理切断输出,这是保障安全的最重要防线。
3. PLC程序架构与核心变量定义
接下来我们进入PLC编程环节。我会以西门子S7-1200/1500的梯形图(LAD)和SCL语言为例进行说明,其思想同样适用于三菱、欧姆龙等其他品牌的PLC。
3.1 变量表规划与数据类型选择
清晰的变量定义是程序可读性的关键。我们规划以下主要变量:
| 变量名 (符号) | 数据类型 | 地址 (示例) | 说明 |
|---|---|---|---|
StartPB | Bool | I0.0 | 启动按钮 |
StopPB | Bool | I0.1 | 停止按钮 |
E_Stop | Bool | I0.2 | 急停按钮 (常闭接入,True为正常) |
Fault_M1 | Bool | I0.3 | M1热继故障 |
Fault_M2 | Bool | I0.4 | M2热继故障 |
Fault_M3 | Bool | I0.5 | M3热继故障 |
ResetPB | Bool | I0.6 | 复位按钮 |
KM1,KM2,KM3 | Bool | Q0.0,Q0.1,Q0.2 | 电机控制输出 |
Sys_Running | Bool | M0.0 | 系统运行标志(内部) |
Sys_Stopping | Bool | M0.1 | 系统停止中标志(内部) |
T_Start_Cycle | Time | T#5s | 启动间隔时间,如5秒 |
T_Stop_Cycle | Time | T#3s | 停止间隔时间,如3秒 |
TON_StartTimer | Timer | DB1.TON_Start | 启动过程延时定时器 |
TON_StopTimer | Timer | T#3s | 停止过程延时定时器 |
Start_Time_Elapsed | Int | MW10 | 启动定时器当前值(毫秒) |
Stop_Time_Elapsed | Int | MW12 | 停止定时器当前值(毫秒) |
Motor_Step | Int | MW14 | 步骤标志:0=待机,1=M1运行,2=M2运行,3=M3运行 |
关键点:这里我引入了Motor_Step这个整型变量来标识系统当前所处的步骤。很多初学者喜欢用一堆辅助继电器(M点)来互锁,逻辑容易混乱。用一个步序号管理,逻辑会清晰很多。定时器我们选用TON(接通延时定时器),并计划通过比较指令来判断是否到达每一步的时间点。
3.2 主程序流程框架设计
整个程序可以围绕一个主状态机来构建,状态由Motor_Step变量控制:
- Step 0 (待机):等待启动命令。收到启动命令且无急停、无故障时,置
Sys_Running,Motor_Step置1,启动M1,同时启动TON_StartTimer。 - Step 1 (M1运行,等待启动M2):
TON_StartTimer计时。通过比较指令判断Start_Time_Elapsed >= T#5s。若成立,则Motor_Step置2,启动M2,重置并重启TON_StartTimer(为下一步计时)。 - Step 2 (M1&M2运行,等待启动M3):同上,判断
Start_Time_Elapsed >= T#5s,成立则Motor_Step置3,启动M3。此时所有电机已启动,Sys_Running保持,停止TON_StartTimer。 - Step 3 (全速运行):等待停止命令或故障信号。
- 停止或故障触发:一旦收到停止命令或某个故障信号,
Sys_Running复位,Sys_Stopping置位,Motor_Step根据当前值进入逆序停止流程。例如,若从Step 3触发停止,则先停M3,Motor_Step置为2,启动TON_StopTimer,依次类推。 - 急停处理:在任何步骤,急停信号直接清零所有输出和状态标志,跳回Step 0。
这个框架的核心在于,用同一个定时器配合重置,为顺序启动的每一步计时,而不是为每一步单独分配一个定时器。这样做节省了定时器资源,逻辑也更集中。
4. 梯形图程序逐行解析与关键指令应用
现在,我们把这个框架用梯形图实现。为了便于理解,我分网络进行说明。
4.1 网络1:系统启动与运行标志控制
StartPB E_Stop Fault_M1 Fault_M2 Fault_M3 Sys_Running --| |-----------| |---------|/|----------|/|---------|/|-------( )--- | | | | | StopPB | | | | --|/|-----------| |---------| |----------| |---------| |------- | Sys_Running | | | --| |-------------------------|------------|-----------|------- (S) ResetPB --| |-----------这个网络是程序的“总开关”。
- 启动条件:按下
StartPB,且急停正常(E_Stop常闭触点导通),且所有电机无故障(故障信号Fault_Mx为常闭触点,正常时导通)。 - 停止条件:按下
StopPB(常闭触点,按下断开),或Sys_Running自锁后急停断开,或任一故障发生。 Sys_Running线圈上的(S)表示置位,一旦启动条件满足就置位并保持。- 底部的
ResetPB用于在故障排除后,复位整个系统状态(需在其他网络复位相关标志和输出)。
4.2 网络2:启动过程定时器与步序逻辑
这是最核心的部分,我们使用一个TON定时器和一个比较指令。
Sys_Running TON_StartTimer.IN --| |----------------------( )--- | | | T#5s | | ---(PT)--- | | | TON_StartTimer | ---(TON)--- | | | TON_StartTimer.ET | ---[MOV]---> Start_Time_ElapsedSys_Running Motor_Step --| |-----------[MOV 1]------( )--- //启动瞬间,步序置1Motor_Step Start_Time_Elapsed T#5s --| |---[==1]---[>=]----------------( )--- //步序1时,计时>=5秒 | | | [MOV 2]---(Motor_Step) //步序进到2 | | | [TON_StartTimer.RESET] //复位定时器 | | | [TON_StartTimer.IN] //重新触发定时器(因IN一直为True,复位后立即开始新周期)Motor_Step Start_Time_Elapsed T#5s --| |---[==2]---[>=]----------------( )--- //步序2时,计时>=5秒 | | | [MOV 3]---(Motor_Step) //步序进到3 | | | [TON_StartTimer.RESET] //停止计时关键技巧:
- 定时器复用:
TON_StartTimer在步序1和步序2中被重复使用。每次满足时间条件、步序递增后,立即复位(RESET)该定时器。由于Sys_Running和TON_StartTimer.IN一直为True,定时器复位后会立刻从0开始重新计时,为下一步等待。 - 比较指令的应用:
[>=]比较指令用于判断定时器当前值(ET)是否达到设定间隔。这里将定时器的经过时间(ET)赋值给Start_Time_Elapsed再比较,是为了程序可读性和便于在线监控。你也可以直接比较TON_StartTimer.ET >= T#5s。 - 步序管理:通过
Motor_Step的值清晰地划分了阶段。在步序3时,定时器被复位且不再启动,因为启动过程已完成。
4.3 网络3:电机输出控制逻辑
电机输出由Motor_Step、Sys_Running、Sys_Stopping以及故障信号共同决定。
Motor_Step Sys_Running Fault_M1 --| |---[>=1]-----| |----------|/|---------( KM1 )Motor_Step Sys_Running Fault_M2 --| |---[>=2]-----| |----------|/|---------( KM2 )Motor_Step Sys_Running Fault_M3 --| |---[>=3]-----| |----------|/|---------( KM3 )逻辑解释:
- M1启动:只要系统在运行(
Sys_Running)且步序>=1(即步序1,2,3),并且M1自身无故障,则KM1得电。 - M2启动:系统在运行,步序
>=2(即步序2,3),且M2无故障。 - M3启动:系统在运行,步序
==3,且M3无故障。 - 任何一个电机的故障信号(
Fault_Mx)会直接切断其自身的输出,这是最基本的安全逻辑。故障的连锁停止逻辑将在下一节实现。
这种用>=比较指令来控制输出的方式,非常简洁地实现了顺序启动:步序到1,M1开;步序到2,M2开;步序到3,M3开。
4.4 网络4:逆序停止与故障连锁逻辑
停止逻辑是启动逻辑的“镜像”,但更复杂,因为它可能由正常停止或故障触发,且触发点可能在任何运行步序。
首先,我们需要一个网络来触发停止过程并设置目标步序(Target_Stop_Step)。
StopPB Sys_Running (S) //正常停止触发 --| |------------| |----------------( )---[MOV 0]---> Target_Stop_Step | | Fault_M1 | (S) //M1故障,目标步序0(全停) --| |------------| |----------------( )---[MOV 0]---> | | Fault_M2 | (S) //M2故障,目标步序1(停M2,M3) --| |------------| |----------------( )---[MOV 1]---> | | Fault_M3 | (S) //M3故障,目标步序2(停M3) --| |------------| |----------------( )---[MOV 2]--->当Sys_Stopping被置位后,启动逆序停止定时器TON_StopTimer,逻辑与启动定时器类似,但步序递减。
Sys_Stopping TON_StopTimer.IN --| |----------------------( )--- | T#3s | | ---(PT)--- | TON_StopTimer | ---(TON)---Sys_Stopping Motor_Step Target_Stop_Step --| |-----------[>]-----------------( )--- //当前步序大于目标步序,则需要执行停止步骤 | | TON_StopTimer.ET T#3s | ---[>=]-------------------( )--- //停止间隔时间到 | | | [DEC 1]---(Motor_Step) //步序减1 | | | [TON_StopTimer.RESET] //复位并重启停止定时器故障连锁的精髓:
- M3故障:
Target_Stop_Step设为2。此时若Motor_Step为3,则满足Motor_Step > Target_Stop_Step,进入停止流程,先将Motor_Step减到2(停M3),定时器计时,时间到再减到1...直到等于2,停止过程结束。由于M2、M1的故障条件为假,它们会继续运行。 - M2故障:
Target_Stop_Step设为1。系统会先将Motor_Step从3减到2(停M3),再减到1(停M2)。M1在步序>=1且无故障时保持运行,直到其自身的故障信号或停止命令将其停止。 - 急停:急停信号应直接复位
Sys_Running、Sys_Stopping、所有电机输出KMx,并将Motor_Step和Target_Stop_Step清零,定时器复位。
5. 程序调试、优化与常见问题排查
程序写完只是第一步,调试和优化才能让它真正可靠。我分享几个实战中总结的关键点。
5.1 在线调试与监控技巧
- 强制与修改值:在模拟或连接真实PLC后,充分利用编程软件的“强制”和“修改值”功能。例如,你可以强制
StartPB为True,然后在线观察Motor_Step、定时器ET值、Start_Time_Elapsed的变化,以及KMx输出的动作是否符合预期。切记,强制输出点(如Q点)在真实设备上非常危险,务必在确保机械安全的前提下进行,或仅用于模拟。 - 变量表监控:创建变量表,将
Motor_Step、Start_Time_Elapsed、Sys_Running、Sys_Stopping等关键变量添加进去,实时监视其变化。这对于分析故障触发时的逻辑流向至关重要。 - 分段调试:先屏蔽故障和急停逻辑,只调试正常的顺序启动和停止。调通后,再单独测试急停功能,最后测试各种故障场景。复杂逻辑不要试图一次性调通。
5.2 提升程序稳健性的优化措施
- 增加状态互锁:在启动逻辑中,可以增加对
Sys_Stopping的互锁,防止在停止过程中误触发启动。例如,启动条件里可以串联Sys_Stopping的常闭触点。 - 使用边沿检测:对启动、停止、复位按钮信号使用上升沿(
P)或下降沿(N)检测指令。避免因按钮信号抖动或长按导致逻辑多次执行。(StartPB) --|P|--。 - 定时器保护:在定时器
IN端增加更严格的条件。例如,启动定时器仅在Sys_Running为True且Motor_Step为1或2时为True,而不是简单地一直为True。这可以防止在非预期状态下定时器意外运行。 - 初始化组织块(OB):在
OB100(启动组织块)中,将所有用于控制的中间变量(如Motor_Step,Sys_Running,Sys_Stopping等)复位到初始状态。确保PLC从STOP切换到RUN模式时,系统处于确定的待机状态,避免“带电重启”导致设备误动作。 - 时间参数变量化:不要将
T#5s、T#3s这样的时间常量直接写在定时器或比较指令中。而是将它们定义为Time类型的全局变量或静态变量(如Start_Interval,Stop_Interval)。这样,以后需要修改时间参数时,只需在变量表中修改一处,无需翻找和修改程序,极大提高了可维护性,也方便做HMI连接。
5.3 典型问题排查清单
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 电机不按顺序启动,同时启动 | 1. 定时器未工作或时间设置过短。 2. Motor_Step逻辑错误,步序切换条件不满足。3. 电机输出控制逻辑未与 Motor_Step正确关联。 | 1. 在线监控定时器IN、PT、ET值是否变化。2. 监控 Motor_Step变量,看是否从1逐步递增到3。3. 检查控制KM2、KM3的输出网络,条件是否包含 Motor_Step>=2和==3。 |
| 停止时电机不按逆序停止,同时停止 | 1. 停止过程标志Sys_Stopping未正确置位。2. 逆序停止定时器未工作。 3. Target_Stop_Step计算或设置错误。4. Motor_Step递减逻辑未执行。 | 1. 监控停止按钮按下或故障时,Sys_Stopping是否变为True。2. 监控停止定时器。 3. 检查故障逻辑中 Target_Stop_Step的赋值是否正确。4. 监控 Motor_Step在停止过程中是否逐步递减。 |
| 故障时,前序电机未延时停止 | 故障连锁逻辑中,Target_Stop_Step设置错误,或停止定时器逻辑未在故障触发后正确激活。 | 模拟故障信号,监控Target_Stop_Step值。检查Sys_Stopping是否因故障置位,以及Motor_Step > Target_Stop_Step条件是否成立。 |
| 急停后恢复,电机乱动 | 急停复位后,程序状态变量(如Motor_Step,Sys_Running)未清零,或启动条件瞬间满足。 | 1. 确保急停程序段复位了所有关键状态标志和输出。 2. 在启动逻辑中,增加系统必须处于“完全待机状态”(如 Motor_Step==0)的条件。 |
| 时间参数修改不生效 | 时间常量直接写在指令中,未变量化。 | 将定时器PT管脚和比较指令中的时间值,替换为全局变量,并通过HMI或变量表修改该变量的值。 |
6. 从基础方案到高级演进的思考
用定时器和比较指令实现顺序控制是一个非常好的起点,它让我们深入理解了状态、时间和逻辑之间的关系。但在更复杂的项目中,我们可以考虑更优的架构。
方案一:使用计数器(Counter)简化步序管理我们可以用一个CTU(加计数器)来替代Motor_Step的部分功能。启动时,每步时间到,计数器加1;停止时,每步时间到,计数器减1。电机的启动条件变为计数器值 >= X。这样省去了对Motor_Step的显式赋值和比较,逻辑更紧凑。但故障时设置目标步序会稍微麻烦一些。
方案二:采用顺序功能图(SFC)或GRAPH编程对于步骤清晰、转移条件明确的顺序过程,西门子的GRAPH语言、三菱的步进顺控指令(STL)是更专业的选择。它们提供了“步”(Step)和“转移”(Transition)的专有结构,能直观地描述流程,并且自带步的激活、禁用管理,简化了编程和调试。当步骤超过5个,或者有并行分支、选择分支时,GRAPH的优势会非常明显。
方案三:面向对象(OOP)与函数块(FB)封装如果我们有多组相同的设备需要同样的顺序控制逻辑(比如多条相同的产线),那么为单台电机组编写一个函数块(FB)是最高效的。在这个FB内部,封装好所有的启动、停止、故障处理、定时逻辑,并对外提供Start、Stop、Reset、Fault等接口和Step_Current、Is_Running等状态输出。在主程序中,我们只需要实例化这个FB多次,并传入不同的参数(如电机数量、时间参数)即可。这极大地提高了代码的复用性和可维护性。
从最基础的定时器比较法,到更高级的架构,其核心思想都是一致的:明确状态划分、严格时间管理、规范信号传递。把这次分享的基础方案吃透,再去看那些高级的编程方法,你会更有底气,也更能理解它们为何要那样设计。
