电气自动化中,电机启停自锁控制是最基础、最典型、也最易出错的逻辑之一。它看似简单——按一下启动按钮,电机转;再按一下停止按钮,电机停;运行中松开启动按钮,电机仍保持运转——但恰恰是这种“理所当然”的行为,一旦在结构化文本(Structured Text, ST)中写错,轻则设备无法自保持、重则引发误动作甚至安全事故。
下面以 Motor := (Start OR Motor) AND NOT Stop; 这一行核心代码为线索,手把手拆解:为什么这么写?每个符号代表什么?变量怎么定义?何时执行?边界条件如何处理?实际工程中还要补哪些关键环节? 全程不依赖图形、不假设你懂PLC底层,只靠文字和可复现的步骤带你写出安全、可靠、符合IEC 61131-3标准的ST程序。
一、先搞清三个核心变量的作用与来源
ST是文本语言,不是电路图。所有信号都必须明确其数据类型、物理来源和更新时机。
-
Start是什么?
读取现场启动按钮的常开触点信号(通常接PLC数字输入DI0)。它是一个布尔型(BOOL)变量,值为TRUE仅当按钮被按下且硬件扫描周期内检测到电平有效(如24V接入)。注意:它不是脉冲信号,也不是“按下一次就永远为TRUE”——只要按钮持续按下,Start就持续为TRUE;松开即变FALSE。 -
Stop是什么?
读取现场停止按钮的常闭触点信号(通常接PLC数字输入DI1)。同样为BOOL类型。工业惯例要求:停止按钮必须使用常闭触点(NC) 接线,这样当按钮卡死、导线断开或端子松脱时,Stop自动变为TRUE,强制停机,实现“故障导向安全”。因此,NOT Stop的含义是:“只有当停止按钮未被按下且线路完好时,才允许运行”。 -
Motor是什么?
它是被控对象的状态变量,也是本逻辑的“记忆单元”。它有两个身份:- 作为输出变量:
Motor的值最终控制接触器线圈(通过DO点,如Q0.0),决定电机是否得电; - 作为内部反馈变量:在等号右侧参与运算,形成“自己维持自己”的闭环。
必须声明为VAR_IN_OUT或VAR(非VAR_INPUT),且初始值建议设为FALSE(上电默认停机)。
- 作为输出变量:
✅ 正确声明示例(在POU变量声明区):
VAR Start : BOOL; // DI0,启动按钮(常开) Stop : BOOL; // DI1,停止按钮(常闭) Motor : BOOL := FALSE; // Q0.0,主接触器控制位 END_VAR
二、逐字符解析核心语句:Motor := (Start OR Motor) AND NOT Stop;
这行代码是典型的“置位优先+复位强制”逻辑。它不是数学等式,而是每个扫描周期执行一次的赋值操作。
| 字符/符号 | 含义说明 | 关键细节 |
|---|---|---|
Motor := |
将右边结果赋给左边变量 | := 是ST中的赋值运算符,不可写成 =(那是比较运算符) |
(Start OR Motor) |
启动触发条件 | OR 是逻辑或。只要 Start 为 TRUE(按钮按下),或 Motor 已为 TRUE(已在运行),整体即为 TRUE。这是实现“自锁”的核心:运行中 Motor 自己喂给自己,维持 TRUE |
AND NOT Stop |
安全使能条件 | NOT Stop 将停止信号取反。因 Stop 在按钮未按下时为 TRUE(常闭接线),故 NOT Stop 在按钮未按下时为 FALSE —— 等等,这不对?别急,下一条解释 |
AND 连接作用 |
强制串联安全链 | 整个表达式只有在 (Start OR Motor) 为 TRUE 且 NOT Stop 也为 TRUE 时,Motor 才被赋值为 TRUE。任意一个为 FALSE,Motor 就变成 FALSE |
⚠️ 关键澄清:Stop 接常闭触点 → 按钮未按下时,输入端子通路 → Stop = TRUE;按钮按下时,触点断开 → Stop = FALSE。
所以 NOT Stop 的真值表是:
| 按钮状态 | Stop 值 |
NOT Stop 值 |
含义 |
|---|---|---|---|
| 未按下(正常) | TRUE |
FALSE |
“允许启动”为假?不对!→ 这说明我们漏了关键前提 |
✅ 正确理解:NOT Stop 的设计目标,是让“停止按钮按下”这个事件直接导致 Motor = FALSE。
而按钮按下 → Stop = FALSE → NOT Stop = TRUE?不,那反而成了“按下才允许运行”——明显逻辑颠倒。
真相是:Stop 必须定义为“停止请求有效”信号,而非原始输入。
因此,实际工程中应做一层信号转换:
StopReq : BOOL := NOT Stop; // StopReq = TRUE 表示“用户按下停止按钮”
然后主逻辑改为:
Motor := (Start OR Motor) AND NOT StopReq;
此时:
StopReq = TRUE→ 用户按下停止按钮 →NOT StopReq = FALSE→Motor被强制置FALSEStopReq = FALSE→ 按钮未按下 →NOT StopReq = TRUE→ 不阻断运行
但为简化入门理解,多数教材直接写 NOT Stop 并隐含约定:Stop 变量已代表“停止有效”(即已对硬件信号取反)。因此,在你的变量声明里,必须明确:
Stop : BOOL; // 已定义为“停止请求有效”,即:按钮按下时 = TRUE
🔧 如何确保
Stop是“按下即 TRUE”?
在硬件接线时仍用常闭触点,但在PLC程序首行立即取反:Stop := NOT %I0.1; // %I0.1 是DI1原始地址,Stop是加工后信号
三、为什么不能写成 Motor := Start OR (Motor AND NOT Stop);?
这是初学者常见错误写法,表面看也像“启动或(运行中且未停止)”,但存在致命时序漏洞。
分析执行顺序(ST严格从左到右、括号优先):
- 先算
Motor AND NOT Stop:若此刻Motor = TRUE但Stop = TRUE(按钮按下),则结果为FALSE; - 再算
Start OR FALSE:若Start = FALSE(按钮已松开),则整体为FALSE; Motor被赋值为FALSE→ 电机停。
✅ 这看似正确?问题出在下一个扫描周期:
- 上一周期末
Motor已被赋FALSE; - 新周期开始,
Motor AND NOT Stop变成FALSE AND ... = FALSE; - 即使
Stop已松开(Stop = FALSE),只要Start没再按,Motor就永远卡在FALSE—— 自锁彻底失效。
而原式 Motor := (Start OR Motor) AND NOT Stop 的优势在于:
Start OR Motor 部分优先保留历史状态。只要上周期 Motor = TRUE,本周期即使 Start = FALSE,(Start OR Motor) 仍为 TRUE,再经 AND NOT Stop 判断是否允许继续保持。
这就是“置位优先”(Set-dominant)逻辑:启动信号拥有最高优先级建立状态,停止信号拥有最高优先级清除状态。
四、必须补充的5个工业级安全要素(缺一不可)
仅有一行核心代码,离实际可用还差很远。以下是真实项目中必须增加的硬性要求:
-
硬件互锁:接触器辅助触点反馈
仅靠PLC软逻辑无法检测接触器是否真正吸合。必须接入接触器KM的常开辅助触点至另一个DI点(如DI2),定义为KM_OK : BOOL,并加入校验:Motor := (Start OR Motor) AND NOT Stop AND KM_OK;若启动后
KM_OK = FALSE(接触器未动作),Motor下一周期即被拉低,防止“指令发出但电机不动”的假运行。 -
过载保护输入
热继电器或电机保护器的脱扣信号(常闭触点)必须接入DI点(如DI3),定义为OL : BOOL(过载有效),并串联进条件:Motor := (Start OR Motor) AND NOT Stop AND NOT OL; -
输出强制刷新与去抖
Start和Stop原始信号需软件消抖(如延时10ms确认稳定),否则按钮机械弹跳会导致Motor频繁通断。典型做法:Start_DB : BOOL := R_TRIG(CLK := Start, TP := T#10ms); Stop_DB : BOOL := F_TRIG(CLK := Stop, PT := T#10ms);然后用
Start_DB.Q和Stop_DB.Q替代原始信号。 -
急停独立回路(硬线)
急停按钮(蘑菇头)绝不允许接入PLC程序逻辑。必须走独立安全继电器回路,直接切断接触器线圈电源。PLC只做状态监视(如读取急停继电器触点),用于HMI报警,不参与控制决策。 -
启动失败超时保护
加入定时器:若Motor = TRUE但KM_OK = FALSE超过2秒,触发故障报警并自动复位Motor:IF Motor AND NOT KM_OK THEN Timer(IN := TRUE, PT := T#2s); IF Timer.Q THEN Fault_Motor_Start := TRUE; Motor := FALSE; END_IF ELSE Timer(IN := FALSE); END_IF
五、完整可运行ST代码示例(含注释)
// ======== 变量声明区(在POU顶部)========
VAR
// 输入信号(硬件映射)
Start_HW : BOOL; // %I0.0,启动按钮(常开)
Stop_HW : BOOL; // %I0.1,停止按钮(常闭)
KM_OK : BOOL; // %I0.2,接触器辅助触点(常开)
OL : BOOL; // %I0.3,热继电器(常闭)
// 消抖后信号
Start : BOOL;
Stop : BOOL;
// 输出与状态
Motor : BOOL := FALSE; // %Q0.0,主接触器线圈
Fault_Motor_Start : BOOL := FALSE;
// 定时器
Timer : TON;
END_VAR
// ======== 程序主体(在MAIN或FB中循环执行)========
// 步骤1:信号消抖
Start := R_TRIG(CLK := Start_HW, TP := T#10ms).Q;
Stop := F_TRIG(CLK := Stop_HW, PT := T#10ms).Q;
// 步骤2:核心启停自锁(含安全联锁)
Motor := (Start OR Motor) AND NOT Stop AND KM_OK AND NOT OL;
// 步骤3:启动失败保护
IF Motor AND NOT KM_OK THEN
Timer(IN := TRUE, PT := T#2s);
IF Timer.Q THEN
Fault_Motor_Start := TRUE;
Motor := FALSE;
END_IF
ELSE
Timer(IN := FALSE);
Fault_Motor_Start := FALSE;
END_IF
✅ 此代码满足:
- IEC 61131-3语法规范
- 故障导向安全(Failsafe)设计原则
- 可直接编译下载至主流PLC(倍福、施耐德、汇川、信捷等)
六、调试与验证 checklist(实操必做)
- 上电初始化检查:强制
Start=FALSE,Stop=FALSE,KM_OK=FALSE,OL=FALSE,观察Motor是否为FALSE; - 启动测试:置
Start=TRUE→Motor应在1个扫描周期内变TRUE;松开Start→Motor保持TRUE; - 停止测试:在
Motor=TRUE时置Stop=TRUE→Motor应在1个周期内变FALSE; - 故障注入测试:
- 断开
KM_OK信号(模拟接触器未吸合)→Motor应在2秒后自动复位; - 置
OL=TRUE(模拟过载)→Motor应立即变为FALSE;
- 断开
- 抗干扰测试:快速抖动
Start信号(<10ms脉冲)→Motor不应响应。
七、常见错误及修复方案
| 错误现象 | 根本原因 | 修复方式 |
|---|---|---|
| 电机一闪即停 | Stop 未取反,或 Stop 接线用了常开触点 |
检查 Stop 变量定义,确认硬件接常闭,程序中 Stop := NOT %I0.1 |
| 松开启动按钮后电机停转 | Motor 参与运算时被错误覆盖(如写成 Motor := Start AND NOT Stop) |
确保使用 (Start OR Motor) 结构,禁止省略 OR Motor |
| HMI显示运行但电机不转 | 未接入 KM_OK 反馈,或 Motor 输出未映射到正确DO点 |
用万用表测 %Q0.0 电压,同时查 KM_OK 实际状态 |
| 启动后立即报“启动失败” | KM_OK 信号延迟或接触器响应慢于2秒 |
将 T#2s 改为 T#3s,或检查接触器选型与电源电压 |
Motor := (Start OR Motor) AND NOT Stop; 这行代码,是电气自动化世界的“Hello World”。它短小,却承载着安全、时序、硬件协同的全部底层逻辑。写对它,不是背公式,而是理解:每一个布尔变量背后都是真实的电压、触点、线圈与风险。

暂无评论,快来抢沙发吧!