3. IEC 61131-3编程模型:软件模型、程序组织单元(POU)、变量与数据类型、任务与调度
IEC 61131-3 是 IEC 61131 系列标准中最具革命性、也是工程应用价值最高的部分。它统一了可编程逻辑控制器(PLC)的编程语言和编程模型,使得不同厂商的 PLC 在程序结构、变量声明和任务调度上具备了逻辑上的一致性。理解这一章的核心,不在于死记硬背语法,而在于建立一套“软件架构思维”——即如何将一个复杂的工业控制需求,通过标准化的软件模型拆解为可管理、可复用、可调度的程序组织单元,并确保其在实时操作系统环境下稳定运行。本章将围绕软件模型、POU、变量与数据类型、任务与调度四大支柱展开深度解读。
上图清晰地展示了 IEC 61131-3 软件模型的层级关系:最上层是配置,它定义了整个控制系统的硬件拓扑和全局资源;中间层是资源,对应具体的物理处理单元(如 CPU 核);资源内部承载着任务,任务负责调度程序的执行;而程序、功能块和函数共同构成了程序组织单元(POU)。最底层是贯穿所有层级的变量与数据类型体系。下面我们将逐一深入剖析。
3.1 软件模型:从配置到资源的层级解构
核心原理:分层抽象与硬件解耦
IEC 61131-3 的软件模型并非简单的代码堆放,而是一种严谨的工程分层架构。其核心思想是将“软件逻辑”与“物理硬件”进行解耦。一个配置(Configuration)代表一个完整的控制系统,它包含了所有硬件资源、全局变量和通信路径。在大型分布式控制系统中,一个配置可能对应一条生产线;在小型设备中,一个配置就是一个单机控制器。配置内部可以包含多个资源(Resource),每个资源通常映射到一个独立的处理单元(如一个 CPU 核心或一个协处理器)。这种设计使得程序可以在不同资源间移植,而无需修改逻辑代码。
判断方法:如何划分配置与资源
在实际工程中,划分配置与资源的依据是物理隔离性与故障域。如果两个控制任务共享同一个 CPU 和电源域,它们应属于同一配置下的不同任务;如果它们运行在物理隔离的控制器中(例如通过以太网通信的两个 PLC),则应划分为两个配置。资源划分则更关注实时性要求:高速运动控制应独占一个资源,而普通逻辑控制可共享另一个资源。
| 层级 | 典型映射 | 作用域 | 示例 |
|---|---|---|---|
| 配置 | 整条产线/单台设备 | 全局变量、全局访问路径 | 汽车焊装线控制系统 |
| 资源 | CPU 核/独立处理器 | 任务调度、程序实例 | 运动控制核、逻辑控制核 |
| 任务 | 周期/事件调度器 | 程序执行触发 | 10ms 周期任务、中断任务 |
| 程序 | 应用主逻辑 | POU 组合 | 主控程序、安全程序 |
案例拆解:双资源运动控制系统的软件模型设计
某包装机械需要同时控制 6 轴伺服运动(周期 1ms)和温度/压力模拟量采集(周期 50ms)。若将所有逻辑放在同一资源中,1ms 任务的高频中断会频繁打断模拟量处理,导致采样抖动。正确做法是:在同一个配置下创建两个资源——Resource_Motion 和 Resource_IO。前者运行 1ms 周期任务,后者运行 50ms 周期任务。两个资源通过配置级全局变量(如共享的 REAL 数组)交换数据。实施后,运动轴跟随误差从 ±0.05mm 降至 ±0.02mm,模拟量采样波动从 ±3% 降至 ±0.5%。代价是需要额外规划资源间通信延迟(约 0.1ms),但收益远大于成本。
3.2 程序组织单元(POU):程序、功能块与函数
核心原理:三种 POU 的本质区别
POU 是 IEC 61131-3 中最基本的代码封装单元,分为三类:函数(Function)、功能块(Function Block, FB)和程序(Program)。函数是无状态、无静态变量的纯逻辑单元,相同的输入必然产生相同的输出,例如 ABS()、LIMIT()。功能块则是有“记忆”的,它内部可以声明静态变量(VAR),每次调用后状态会保留,例如定时器 TON、计数器 CTU。程序是最高层级的 POU,它相当于一个“容器”,内部可以调用多个功能块和函数,并直接与任务绑定。程序之间不能互相调用,但可以通过全局变量或通信接口交互。
操作流程:POU 的声明与实例化
在结构化文本(ST)中,函数和功能块的声明方式不同。函数直接通过函数名调用,而功能块必须先声明实例(Instance),再通过实例调用。例如:
// 函数调用(无状态)
result := LIMIT(0, 100, input_value);
// 功能块实例化与调用(有状态)
VAR
myTimer : TON; // 声明 TON 功能块实例
END_VAR
myTimer(IN := start_signal, PT := T#5s);
IF myTimer.Q THEN
// 定时时间到,执行动作
END_IF;
程序(Program)作为顶层 POU,通常在任务中直接关联。一个程序可以包含多个功能块实例,形成“程序-功能块-函数”的调用树。
案例拆解:功能块复用在多工位控制中的应用
某装配线有 8 个工位,每个工位都需要一个“夹紧-检测-松开”的时序控制。若每个工位单独编写逻辑,代码量巨大且难以维护。工程师设计了一个通用功能块 FB_ClampSequence,内部封装了状态机(IDLE → CLAMPING → CHECKING → RELEASING),输入为启动信号和检测结果,输出为夹紧/松开指令。在主程序中,声明 8 个实例:Station1 : FB_ClampSequence; 至 Station8 : FB_ClampSequence;。每个实例独立运行,互不干扰。最终代码量减少 60%,且新增工位时只需复制一行声明。复盘发现,功能块内部必须避免使用全局变量,否则多实例会互相干扰——这是初学者的常见误区。
3.3 变量与数据类型:强类型与存储限定
核心原理:强类型语言的安全保障
IEC 61131-3 是强类型语言,所有变量必须显式声明数据类型。标准定义了基础数据类型(BOOL、BYTE、INT、REAL、STRING、TIME 等)和衍生数据类型(ARRAY、STRUCT、枚举)。强类型机制在编译期即可发现类型不匹配错误,避免运行时数据损坏。此外,变量还分为不同的存储限定符:VAR(内部变量)、VAR_INPUT(输入参数)、VAR_OUTPUT(输出参数)、VAR_IN_OUT(输入输出参数)、VAR_GLOBAL(全局变量)、VAR_TEMP(临时变量)。其中 VAR_TEMP 在每次调用时重新分配内存,不保持状态,常用于中间计算。
判断方法:选择合适的数据类型
选择数据类型时需考虑数值范围、精度和内存占用。例如,计数器的值若可能超过 32767,应使用 DINT 而非 INT;模拟量转换结果应使用 REAL 以保留小数。对于时间相关变量,使用 TIME 类型(如 T#2s)比直接使用 INT 更直观且不易出错。下表列出了常用数据类型的典型应用场景:
| 数据类型 | 位宽 | 典型应用 | 注意事项 |
|---|---|---|---|
| BOOL | 1 bit | 开关量、状态标志 | 不可用于算术运算 |
| INT | 16 bit | 计数器、小范围整数 | 注意溢出风险 |
| REAL | 32 bit | 模拟量、PID 参数 | 避免直接比较相等 |
| STRING | 可变 | 报警文本、配方名称 | 长度需预先定义 |
| ARRAY | 可变 | 批量数据、配方表 | 索引从 0 或 1 开始(可配置) |
| STRUCT | 可变 | 组合数据(如电机参数) | 可嵌套定义 |
案例拆解:全局变量滥用导致的隐性故障
某项目使用全局变量 g_bEmergencyStop 作为急停标志,在多个 POU 中读写。某次调试中,维护人员在功能块 A 中误将其赋值为 FALSE,导致急停信号被覆盖,安全回路失效。排查过程耗时 3 小时。复盘结论:全局变量应仅用于跨程序通信,且必须遵循“单一写入者”原则。改进方案:将急停信号封装为功能块 FB_SafetyMonitor,通过输出引脚提供给其他 POU 只读访问。此案例警示我们,强类型语言虽能防止类型错误,但无法防止逻辑滥用,设计规范至关重要。
VAR_TEMP 变量在功能块中不保持状态,若误将其用于跨周期累加,会导致数据丢失。务必区分“需要保持的变量”和“临时计算变量”。
3.4 任务与调度:实时性的核心保障
核心原理:任务是程序执行的驱动引擎
在 IEC 61131-3 中,程序本身不会自动执行,必须由任务(Task)触发。任务定义了程序的执行条件:周期执行(如每 10ms 执行一次)、事件触发(如上升沿触发)或系统触发(如开机执行)。任务还拥有优先级属性,高优先级任务可以抢占低优先级任务。调度器根据优先级和触发条件决定哪个程序获得 CPU 时间。理解任务模型是掌握实时控制的关键——错误的优先级设置会导致控制周期抖动,甚至系统崩溃。
操作流程:任务配置与优先级分配
配置任务时,需遵循以下步骤:
- 识别实时性需求:运动控制通常需要 1-2ms 周期,温度控制 50-100ms,人机交互 100ms 以上。
- 分配优先级:周期越短、越重要的任务优先级越高。例如,1ms 运动任务优先级设为 0(最高),10ms 逻辑任务设为 1,100ms 通信任务设为 2。
- 设置看门狗:为每个任务设置最大执行时间,超时则触发报警或停机。
- 避免任务过载:确保任务的平均执行时间不超过其周期的 70%,留出余量应对突发负载。
// 任务配置示例(CODESYS 风格)
TASK MotionTask (INTERVAL := T#1ms, PRIORITY := 0, WATCHDOG := T#5ms);
TASK LogicTask (INTERVAL := T#10ms, PRIORITY := 1, WATCHDOG := T#20ms);
PROGRAM MotionProgram (MotionTask);
PROGRAM LogicProgram (LogicTask);
案例拆解:任务优先级反转导致的运动抖动
某设备在高速运行时,伺服电机出现周期性抖动(约每 100ms 一次)。通过示波器观察,发现位置偏差在抖动时刻明显增大。分析任务配置发现:运动任务(1ms)优先级为 0,但通信任务(50ms)优先级也为 0。当通信任务执行时(耗时约 8ms),运动任务被阻塞,导致控制周期拉长至 9ms,引发抖动。解决方案:将通信任务优先级降为 2,并增加通信任务的看门狗。修改后抖动消失,位置偏差恢复至 ±0.01mm。此案例说明,优先级分配必须基于任务的实时性敏感度,而非功能重要性。
综上所述,IEC 61131-3 的编程模型通过软件模型的分层解耦、POU 的模块化封装、强类型变量体系以及灵活的任务调度机制,为工业控制软件提供了严谨的工程化框架。掌握这四大支柱,不仅能够编写出结构清晰、易于维护的 PLC 程序,更能从系统层面保障控制系统的实时性与可靠性。在实际项目中,建议工程师在编码前先完成软件架构设计,明确配置/资源划分、POU 接口定义和任务优先级矩阵,这将极大减少后期调试成本。