在结构化文本(Structured Text,ST)编程中,条件判断赋值是电气自动化控制逻辑最基础、最频繁使用的语法结构。它直接对应PLC(可编程逻辑控制器)对物理过程的实时响应——比如温度超限报警、液位过高停泵、电机过载切断电源等。你看到的这行代码:
IF Temp > 100 THEN Alarm := TRUE; ELSE Alarm := FALSE; END_IF;
表面只是一条赋值语句,背后却承载着工业现场的安全边界、设备寿命保障和系统可靠性。本文不讲抽象理论,只聚焦“怎么写对”“为什么这么写”“常见错在哪”“如何扩展更实用”,手把手带你写出稳定、可读、易维护的ST条件判断逻辑。
一、先拆解:这条语句每个字符都干什么用?
我们逐字符解析原始语句,不跳步:
IF —— 关键字,表示条件判断块开始。必须大写(IEC 61131-3标准规定ST关键字不区分大小写,但行业惯例全大写以提高可读性,且部分PLC编辑器(如TIA Portal、Codesys)默认高亮大写形式)。
Temp > 100 —— 布尔表达式,即“判断条件”。这里Temp是变量名(通常为REAL或INT类型),>是关系运算符,100是字面常量。整个表达式运算结果只能是TRUE或FALSE。
THEN —— 关键字,紧接在条件后,表示“当条件成立时,执行以下语句”。
Alarm := TRUE; —— 赋值语句。:=是ST中唯一合法的赋值运算符(注意:不是=,=在ST中仅用于相等比较)。Alarm是布尔型变量(BOOL),TRUE是预定义布尔常量。分号;是语句结束符,不可省略。
ELSE —— 关键字,表示“当条件不成立时,执行以下语句”。
Alarm := FALSE; —— 同上,给同一变量赋相反值。
END_IF; —— 关键字组合,表示整个IF块结束。必须带分号,且END_IF之间无空格(写作END_IF,不是END IF或END-IF)。
✅ 正确完整写法(含空格与分号规范):
IF Temp > 100 THEN Alarm := TRUE; ELSE Alarm := FALSE; END_IF;
注意:虽然单行写法IF Temp > 100 THEN Alarm := TRUE; ELSE Alarm := FALSE; END_IF;语法合法,但强烈建议分行缩进。原因有三:
- PLC调试时,编辑器按行报错,单行长句出错定位困难;
- 多个ELSEIF分支叠加时,单行无法阅读;
- 符合IEC 61131-3推荐的代码风格,便于团队协作与审核。
二、必须避开的5个典型错误(真实工程中高频发生)
错误1:混淆赋值:=与比较=
❌ 错误写法:IF Temp > 100 THEN Alarm = TRUE; END_IF;
→ 编译器报错:Syntax error: expected ':=' but found '='
✅ 修正:所有赋值必须用:=;比较两个值是否相等,才用=(如IF State = START THEN ...)。
错误2:忘记分号;
❌ 错误写法:
IF Temp > 100 THEN
Alarm := TRUE
ELSE
Alarm := FALSE
END_IF
→ 多数编辑器(如Unity Pro、PLCnext Engineer)会提示Missing semicolon,编译失败。
✅ 修正:每个语句末尾、END_IF后都必须有;。
错误3:变量类型不匹配
假设Temp定义为REAL(浮点数),而误写成IF Temp > 100.0 THEN ...看似合理,但若Temp实为INT,某些PLC(如旧版Modicon M340)可能隐式转换失败或触发警告。更危险的是:
❌ IF Temp > 100 THEN Alarm := 1; END_IF;
→ Alarm是BOOL,但1是整数,非标准布尔字面量。部分平台允许,但违反IEC 61131-3,跨平台移植必出错。
✅ 修正:布尔变量只赋TRUE或FALSE;数值变量用对应类型常量(100用于INT,100.0用于REAL)。
错误4:嵌套IF缺少END_IF配对
❌ 错误写法:
IF Mode = AUTO THEN
IF Temp > 100 THEN
Alarm := TRUE;
ELSE
Alarm := FALSE;
END_IF; ← 这里只闭合了内层IF,外层IF没有END_IF!
→ 编译报错:Expected 'END_IF' 或 Unexpected token。
✅ 修正:每层IF必须有且仅有一个对应END_IF,缩进对齐是自查关键。
错误5:条件表达式含未初始化变量
❌ Temp变量声明了但未在程序其他位置赋初值,首次扫描时其值为随机内存内容(如32767或0.0)。
→ 可能导致Alarm初始状态为TRUE,设备一上电就误报警。
✅ 修正:在INIT段(初始化段)或主程序首行显式初始化:
Temp := 0.0; // 若为REAL
Alarm := FALSE; // 显式置初始安全态
三、从“能运行”到“该这样写”:4种生产级优化写法
写法1:用ELSIF处理多区间判断(替代嵌套IF)
场景:温度分三级报警(高温停机、中温预警、正常)
❌ 嵌套写法(难读、易漏END_IF):
IF Temp > 150 THEN
Status := SHUTDOWN;
ELSE
IF Temp > 100 THEN
Status := WARNING;
ELSE
Status := NORMAL;
END_IF;
END_IF;
✅ 推荐写法(清晰、扁平、易扩展):
IF Temp > 150 THEN
Status := SHUTDOWN;
ELSIF Temp > 100 THEN
Status := WARNING;
ELSE
Status := NORMAL;
END_IF;
⚠️ 注意:
ELSIF是一个单词(无空格),不是ELSE IF。后者会被解释为ELSE后跟一个新IF块,逻辑不同。
写法2:单行条件赋值(简洁版,适合简单二值逻辑)
IEC 61131-3支持三元操作符风格的函数式赋值:
Alarm := (Temp > 100); // 直接将布尔表达式结果赋给BOOL变量
✅ 优势:1行解决,无分支开销,CPU扫描周期更短;
⚠️ 限制:仅适用于“条件结果直接等于目标变量值”的场景(即不需要ELSE分支做反向赋值)。
衍生技巧:可嵌套逻辑运算
Alarm := (Temp > 100) AND (Pump_Running = TRUE);
写法3:用CASE替代长链ELSIF(当判断离散值时)
场景:根据ErrorCode(INT类型)设置不同报警文本
❌ 长ELSIF链:
IF ErrorCode = 1 THEN
Msg := 'SENSOR_FAULT';
ELSIF ErrorCode = 2 THEN
Msg := 'COMM_LOST';
ELSIF ErrorCode = 3 THEN
Msg := 'OVERLOAD';
ELSE
Msg := 'UNKNOWN';
END_IF;
✅ 更优写法(CASE结构,CPU执行效率更高):
CASE ErrorCode OF
1: Msg := 'SENSOR_FAULT';
2: Msg := 'COMM_LOST';
3: Msg := 'OVERLOAD';
ELSE Msg := 'UNKNOWN';
END_CASE;
✅
CASE要求判断变量为整数或枚举类型;每个分支用冒号:结尾;ELSE处理未列情况。
写法4:封装为函数块(FB),实现逻辑复用
当同一判断逻辑在多个地方使用(如10个温度点都要超温报警),重复写IF语句会导致:修改一处要改10处、易遗漏、版本不一致。
✅ 正确做法:新建函数块FB_TempAlarm,接口如下:
| 参数名 | 类型 | 方向 | 说明 |
| :--- | :--- | :--- | :--- |
| InputTemp | REAL | INPUT | 实时温度值 |
| Threshold | REAL | INPUT | 报警阈值(可配置) |
| AlarmOut | BOOL | OUTPUT | 报警输出 |
函数块内部ST代码:
AlarmOut := (InputTemp > Threshold);
调用时只需:
TempAlarm_1(InputTemp := T_Tank1, Threshold := 95.0, AlarmOut => ALM_Tank1);
TempAlarm_2(InputTemp := T_Pump, Threshold := 80.0, AlarmOut => ALM_Pump);
→ 阈值集中配置,逻辑统一升级,故障隔离性强。
四、关键安全原则:为什么“ELSE分支不能省略”
初学者常写:
IF Temp > 100 THEN
Alarm := TRUE;
END_IF; // ❌ 省略ELSE
表面看功能相同(温度≤100时Alarm保持原值),但存在严重隐患:
- 若
Alarm初始值为TRUE(因未初始化或上次故障遗留),则温度回落至99℃时,Alarm仍为TRUE,无法自动复位; - 安全标准(如IEC 61508、ISO 13849)明确要求:安全相关输出必须有确定的默认状态,不能依赖“历史值”。
✅ 正确做法:任何安全输出变量,IF结构必须覆盖所有逻辑路径。
更进一步,采用“故障安全设计”:
IF (Temp > 100) AND (System_Ready = TRUE) THEN
Alarm := TRUE;
ELSE
Alarm := FALSE; // 所有非报警条件,强制清零
END_IF;
→ 即使System_Ready为FALSE(如急停按下),也确保Alarm为FALSE,避免误信号干扰上位机。
五、调试实战:3步快速定位IF逻辑问题
- 在线监控变量值:在PLC编辑器中,将
Temp、Alarm、System_Ready等变量加入在线监视表,实时观察值变化与IF执行是否同步。 - 插入临时测试点:在
THEN和ELSE分支内,各加一行TestFlag := TRUE;(TestFlag为BOOL型全局变量),通过监视TestFlag确认哪条路径被触发。 - 模拟边界值:手动修改
Temp为99.9、100.0、100.1,验证阈值动作点是否精准(注意浮点精度:100.0与100在REAL比较中等价,但100.0001 > 100.0成立)。
六、扩展:结合定时器实现延时确认报警(防抖)
真实工业场景中,传感器可能瞬时干扰导致误触发。需增加“持续超限3秒才报警”逻辑:
// 声明静态变量(保留在FB内,断电不丢失需加RETAIN)
VAR
tON_100: TON; // IEC标准定时器功能块
bConfirmed: BOOL;
END_VAR
// 主逻辑
IF Temp > 100 THEN
tON_100(IN := TRUE, PT := T#3S); // 启动3秒定时器
bConfirmed := tON_100.Q; // Q为定时完成标志
ELSE
tON_100(IN := FALSE); // 复位定时器
bConfirmed := FALSE; // 清除确认标志
END_IF;
Alarm := bConfirmed; // 报警仅在确认后置位
→ 此写法将条件判断与时间逻辑解耦,符合模块化设计思想。
七、终极检查清单(每次写完IF语句前必核对)
| 检查项 | 是/否 | 说明 |
|---|---|---|
IF/THEN/ELSIF/ELSE/END_IF 关键字全部大写? |
提升可读性与兼容性 | |
每个语句末尾都有分号;? |
包括END_IF; |
|
赋值一律用:=,比较一律用=? |
混用必报错 | |
| 所有变量已声明且类型匹配? | 特别检查BOOL变量只赋TRUE/FALSE |
|
ELSE分支是否存在?安全输出是否强制设默认值? |
防止状态残留 | |
多层嵌套时,缩进是否对齐?END_IF数量是否与IF数量相等? |
用编辑器“折叠代码”功能一键验证 | |
| 是否有未初始化的输入变量参与条件判断? | 初始化应在程序入口处完成 |
IF Temp > 100 THEN Alarm := TRUE; ELSE Alarm := FALSE; END_IF; 这行代码,不是语法练习,而是工程师对产线安全的一次郑重承诺。写对它,靠的不是记忆符号,而是理解每一个分号背后的执行顺序、每一个布尔值所代表的物理世界状态、每一次END_IF所封闭的责任边界。

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