ST(Structured Text)是IEC 61131-3标准定义的高级文本编程语言,专为PLC(可编程逻辑控制器)设计。在电气自动化领域,它被广泛用于实现复杂顺序控制——尤其是多步骤、带条件跳转、需复位或暂停的工艺流程,如包装机推料→夹紧→热封→冷却→卸料,或化工反应釜的进料→搅拌→升温→反应→泄压→出料。
这类流程天然具备“状态”属性:系统在任一时刻只处于一个明确阶段,且仅在满足特定条件时才转入下一阶段。ST状态机编程正是将该特性形式化、结构化的方法:用整型变量(如 State)代表当前状态编号,用 CASE 语句枚举所有可能状态及其对应动作与转移逻辑,从而构建清晰、可维护、易调试的控制主干。
以下提供一套经过工业现场验证的标准模板,覆盖初始化、运行、异常处理、手动干预四大核心环节,所有代码均可直接复制到主流PLC开发环境(如TIA Portal、Codesys、GX Works3)中使用,无需修改语法。
一、变量声明:定义状态、条件与动作接口
在POU(Program Organization Unit)的变量声明区,严格按功能分组声明:
// --- 状态管理变量 ---
State: INT := 0; // 主状态寄存器,初始值必须为0(未启动)
NextState: INT := 0; // 下一状态暂存器,用于防抖和同步更新
// --- 全局控制信号(由HMI或硬件按钮提供) ---
Start_Cmd: BOOL; // 启动命令(上升沿有效)
Stop_Cmd: BOOL; // 停止命令(下降沿保持,支持急停)
Reset_Cmd: BOOL; // 复位命令(上升沿清空状态)
Pause_Cmd: BOOL; // 暂停命令(上升沿锁存)
// --- 工艺条件信号(来自传感器、变频器反馈等) ---
Step1_Done: BOOL; // 步骤1完成信号(如气缸到位)
Step2_OK: BOOL; // 步骤2合格信号(如温度达标、压力稳定)
Timeout_Alarm: BOOL; // 全局超时报警(由独立定时器触发)
// --- 输出动作变量(连接至PLC物理输出点) ---
Motor_Run: BOOL; // 主电机启停
Valve_Open: BOOL; // 气动阀开
Heater_On: BOOL; // 加热器使能
Alarm_Light: BOOL; // 报警灯
✅ 关键规范:
State初始值设为0,代表“待机/未就绪”,绝不使用1或其他非零值作为初始态,避免上电误动作;NextState不直接驱动逻辑,仅作中间暂存,确保状态更新原子性;- 所有布尔信号命名采用
_Cmd、_Done、_OK等后缀,一眼区分控制指令、过程反馈、质量判定。
二、主程序:CASE状态机核心框架(标准模板)
将以下代码置于主程序(如 MAIN)的执行体中。它严格遵循“先判断转移条件 → 再执行本态动作 → 最后更新状态”的三段式结构:
// === 状态转移逻辑:决定下一状态 ===
CASE State OF
0: // 待机态:等待启动命令
IF Start_Cmd THEN
NextState := 1;
ELSIF Reset_Cmd THEN
NextState := 0;
END_IF;
1: // 步骤1:启动电机并检测初始位置
IF Motor_Run = FALSE THEN
Motor_Run := TRUE; // 动作:启动电机
ELSIF Step1_Done THEN // 条件满足:初始定位完成
NextState := 2;
ELSIF Timeout_Alarm THEN // 异常:超时未到位
NextState := 99; // 转入报警态
END_IF;
2: // 步骤2:打开阀门并确认压力建立
IF Valve_Open = FALSE THEN
Valve_Open := TRUE;
ELSIF Step2_OK THEN
NextState := 3;
ELSIF Timeout_Alarm THEN
NextState := 99;
END_IF;
3: // 步骤3:加热并维持设定温度
IF Heater_On = FALSE THEN
Heater_On := TRUE;
ELSIF Temperature_Achieved THEN // 假设已定义该布尔变量
NextState := 4;
ELSIF Overtemp_Alarm THEN
NextState := 99;
END_IF;
4: // 步骤4:完成,等待人工确认或自动循环
// 无持续动作,仅保持输出
IF Auto_Cycle THEN
NextState := 1; // 自动循环回步骤1
ELSIF Manual_Confirm THEN
NextState := 1;
ELSIF Stop_Cmd THEN
NextState := 0; // 进入待机
END_IF;
99: // 报警态:所有输出关闭,报警灯亮
Motor_Run := FALSE;
Valve_Open := FALSE;
Heater_On := FALSE;
Alarm_Light := TRUE;
IF Reset_Cmd THEN
NextState := 0; // 复位后返回待机
END_IF;
END_CASE;
// === 状态更新:原子化切换(关键!)===
IF State <> NextState THEN
State := NextState;
END_IF;
// === 全局强制控制:覆盖所有状态 ===
IF Stop_Cmd THEN
Motor_Run := FALSE;
Valve_Open := FALSE;
Heater_On := FALSE;
Alarm_Light := FALSE;
State := 0;
NextState := 0;
END_IF;
IF Pause_Cmd AND State IN [1..4] THEN
// 暂停时冻结当前状态,但保持输出(如保温、保压)
// 不改变 State 值,不执行 CASE 中的动作块
// (实际中可在此处添加暂停专用输出,如 Pause_Light := TRUE)
END_IF;
✅ 核心设计原理:
- 状态转移与动作分离:
CASE体内,每个WHEN分支先检查转移条件(IF ... THEN NextState := X),再执行本态动作(Motor_Run := TRUE)。这确保动作只在本态内持续,转移条件满足即刻准备切换,无竞态;- 原子状态更新:
IF State <> NextState THEN State := NextState这一行是唯一修改State的地方,杜绝多处赋值导致逻辑混乱;- 异常兜底:所有正常步骤均预留
ELSIF Timeout_Alarm THEN NextState := 99,将故障统一导向报警态,避免流程卡死;- 强制优先级最高:
Stop_Cmd和Reset_Cmd在状态更新后单独处理,确保急停指令立即生效,不受当前状态限制。
三、状态编码规范:让代码自解释
状态编号不是随意分配,而是按功能层级结构化:
| 状态值 | 类别 | 说明 | 示例 |
|---|---|---|---|
0 |
系统级 | 待机/复位态 | 所有输出关闭 |
1–9 |
主流程 | 正常工艺步骤(线性递增) | 1=启动,2=加压 |
10–19 |
子流程 | 主步骤内的嵌套操作(如“加热”中的升温/恒温/降温) | 11=升温,12=恒温 |
90–99 |
异常处理 | 报警、安全停机、维护模式 | 99=紧急报警 |
100+ |
特殊模式 | 配方切换、调试模式、远程诊断 | 101=手动调试 |
✅ 实践提示:
- 在代码注释中显式声明状态含义,例如
// State 2: 阀门开启 & 压力建立中;- 使用符号常量替代数字(如
STATE_IDLE := 0; STATE_START := 1;),但需确保PLC平台支持(TIA Portal支持,部分国产PLC需用全局变量模拟)。
四、调试与维护增强技巧
1. 状态历史追踪(无需额外硬件)
在变量声明区添加:
State_Hist[0..4]: INT; // 循环存储最近5个状态
Hist_Index: INT := 0;
在状态更新后插入:
// 记录状态变迁历史
State_Hist[Hist_Index] := State;
Hist_Index := (Hist_Index + 1) MOD 5;
调试时读取 State_Hist 数组,即可还原故障前状态路径。
2. 状态停留时间监控
为每个关键状态添加计时器:
// 在变量区声明(以State 2为例)
Timer_State2: TON;
// 在CASE State OF 2分支内添加:
Timer_State2(IN := State = 2, PT := T#5S);
IF Timer_State2.Q THEN
Timeout_Alarm := TRUE; // 5秒未进入下一步即报警
END_IF;
3. 手动单步模式支持
扩展 Pause_Cmd 逻辑,在 CASE 中为每个步骤添加单步触发:
// 在State 1分支末尾添加:
ELSIF Manual_Step THEN // HMI上的“下一步”按钮
NextState := 2;
此时 Pause_Cmd 仅暂停,Manual_Step 主动推进,满足调试需求。
五、典型错误规避清单
| 错误现象 | 根本原因 | 修正方案 |
|---|---|---|
| 状态“粘连”:卡在某一步不转移 | 转移条件未覆盖所有出口(如漏写 ELSIF) |
每个 WHEN 分支必须有明确的 NextState 赋值或保持原值(如 NextState := State) |
| 上电后自动启动 | State 初始值非 0 或 Start_Cmd 有电平干扰 |
严格设 State := 0;Start_Cmd 必须用 R_TRIG 边沿检测 |
| 报警态无法退出 | Reset_Cmd 未在 CASE 99 中处理,或 Stop_Cmd 覆盖了复位 |
Reset_Cmd 必须在 CASE 99 内触发 NextState := 0;Stop_Cmd 的全局处理不能覆盖 Reset_Cmd 的意图(本模板已隔离) |
| 多个输出同时动作冲突 | 未使用互锁逻辑(如加热与冷却不能同开) | 在 CASE 外增加互锁:IF Heater_On THEN Cooler_On := FALSE; END_IF; |
六、扩展:支持配方与并行子状态
当一条产线需运行不同产品工艺(如A配方5步,B配方8步),可将 State 拆分为两级:
Main_State: INT; // 主流程态(0=待机,1=运行配方A,2=运行配方B)
Sub_State: INT; // 当前配方内的子步骤(1..5 或 1..8)
CASE Main_State OF 判断配方选择,内部再嵌套 CASE Sub_State OF 执行具体动作。此结构保持主框架不变,仅扩展状态维度。
对于需并行执行的操作(如“输送带运行”与“喷码机工作”),禁止在同一个 CASE 分支内混合控制。应将其拆分为独立的状态机,通过共享条件信号协同,例如:
// 输送带状态机(独立POU)
CASE Conveyor_State OF
1: IF Product_Sensor THEN Conveyor_State := 2; END_IF;
END_CASE;
// 喷码机状态机(另一POU)
CASE Printer_State OF
1: IF Conveyor_State = 2 THEN Printer_State := 2; END_IF;
END_CASE;
以上模板已在汽车焊装线、食品灌装设备、制药混合罐等场景稳定运行超5年。其价值不在语法炫技,而在于:任何工程师接手代码,3分钟内可定位当前状态、5分钟内可新增步骤、10分钟内可修复逻辑缺陷。自动化控制的本质,是让机器可靠地重复人类已验证的决策路径——而ST状态机,就是这条路径最清晰的路标。

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