2. PLC编程基础回顾

在深入PLC功能块封装与结构化编程之前,必须首先夯实IEC 61131-3标准所定义的编程语言基础。该标准由国际电工委员会制定,旨在统一全球PLC编程的语法与模型,解决不同厂商设备之间程序不可移植、维护成本高的问题。本章将系统梳理五种标准编程语言(LD、FBD、ST、SFC、IL)的定位与适用场景,并重点阐述结构化编程的核心思想——即如何将复杂的自动化任务分解为可复用、可测试、可维护的功能块单元。理解这些基础,是后续进行功能块封装、接口设计、状态机建模与代码重用的前提。

IEC 61131-3 标准 LD 梯形图 电气逻辑图 FBD 功能块图 信号流/数据流 ST 结构化文本 高级语言/算法 SFC 顺序功能图 状态/步进控制 IL 指令表 汇编风格 结构化编程核心思想 模块化分解 功能封装为FB/FC 接口清晰、独立测试 数据管理 全局/局部变量规范 避免数据竞争 状态与流程控制 SFC/状态机建模 异常处理与恢复

上图展示了IEC 61131-3标准下五种编程语言与结构化编程三大核心支柱之间的关系。五种语言并非相互孤立,而是可以在同一项目中混合使用,以发挥各自优势。结构化编程思想则贯穿于语言选择、程序组织与数据管理的全过程。下面我们将逐一剖析每种语言的本质特征、适用场景与工程实践要点。

2.1 IEC 61131-3标准概述与编程语言定位

核心原理:标准化的分层模型

IEC 61131-3定义了PLC软件的配置(Configuration)→ 资源(Resource)→ 任务(Task)→ 程序(Program)→ 功能块(FB)→ 功能(FC)的层级模型。其中,功能块(Function Block)是结构化编程的核心载体,它拥有内部状态(静态变量)和外部接口(输入/输出变量),能够封装算法、定时器、计数器或通信协议。而功能(Function)则无内部状态,如数学运算、类型转换等。标准还规定了变量类型(BOOL、INT、REAL、STRING等)、数据类型(数组、结构体)以及作用域规则(局部、全局、直接表示)。

层级说明工程示例
配置整个PLC系统,包含硬件与通信资源一套西门子S7-1500站点
资源处理单元(CPU)及其外围CPU 1516-3 PN/DP
任务周期性或事件驱动的执行调度OB1循环扫描,OB35定时中断
程序用户逻辑的集合,可调用FB/FCMain_Program
功能块带内部状态的算法单元电机控制FB、PID调节FB
功能无状态的纯函数温度线性转换FC

判断方法:如何选择编程语言

选择语言的核心依据是控制逻辑的复杂度、数据运算强度、维护人员的习惯以及行业惯例。对于继电器控制逻辑的改造,LD梯形图最直观;对于连续过程控制(如PID、流量补偿),FBD功能块图便于信号流追踪;对于复杂算法(如数组排序、字符串处理、数学建模),ST结构化文本效率最高;对于批量生产中的步进顺序控制,SFC顺序功能图是首选;IL指令表则已逐渐被边缘化,仅在旧设备维护或极小存储空间场景下使用。

经验提醒:在TIA Portal、Codesys、Studio 5000等现代IDE中,LD、FBD、ST、SFC可以自由混用。建议以FBD或LD作为主程序框架,将复杂算法用ST编写为FC/FB,将顺序流程用SFC表达,这样既保证可读性又提升开发效率。

案例拆解:一个混合编程的电机控制场景

假设需要实现一台三相异步电机的星三角启动控制,要求包含过载保护、定时切换、故障复位功能。我们采用如下混合方案:

  • 主逻辑(LD):绘制启动/停止按钮、接触器线圈、热继电器常闭触点,形成清晰的电气逻辑图。
  • 定时切换(FBD):调用TON定时器功能块,设定6秒延时,输出切换信号。
  • 故障诊断(ST):编写一段ST代码,判断过载、缺相、堵转等故障码,并生成报警字符串。
  • 顺序流程(SFC):定义“待机→星形启动→三角形运行→故障停止”四个步骤,每个步骤关联对应的LD或FBD逻辑。

这种混合方式使得电气工程师能快速理解主回路,软件工程师能高效编写诊断算法,调试时又能通过SFC观察当前状态。最终程序在1200行代码内完成了全部功能,比纯LD实现减少约40%的代码量,且故障定位时间缩短了60%。

常见误区与总结复盘

风险提示:不要盲目追求“纯ST”或“纯LD”。纯ST编写的程序虽然紧凑,但不利于现场电工维护;纯LD处理复杂数学运算时极其繁琐。另外,IL语言在IEC 61131-3第三版中已标记为“不推荐使用”,新项目应避免采用。

复盘要点:语言选择应基于团队技能矩阵与项目生命周期。若项目后期由外部集成商维护,建议在程序头注释中明确语言使用规则。同时,所有FB/FC的接口变量必须定义完整的数据类型和注释,避免使用M区(位存储区)直接寻址,而应通过符号名访问。

2.2 结构化编程的基本思想与设计方法

核心原理:从“线性编程”到“模块化封装”

传统PLC程序往往将所有逻辑写入一个OB1块中,形成“面条代码”。结构化编程则强调自顶向下分解、功能内聚、接口最小化。其基本单元是功能块(FB),每个FB封装一个独立的功能(如阀门控制、电机启停、模拟量滤波),对外只暴露输入/输出参数,内部状态对外不可见。这种设计带来了三大优势:可复用性(同一FB可被多个程序调用)、可测试性(单独模拟输入即可验证逻辑)、可维护性(修改内部实现不影响外部调用)。

操作流程:功能块封装的标准步骤

  1. 需求分析:明确该功能块的输入信号(传感器、命令)、输出信号(执行器、状态)、内部参数(定时值、阈值)。
  2. 接口定义:在IDE中创建FB,声明VAR_INPUT、VAR_OUTPUT、VAR_IN_OUT、VAR(静态变量)。
  3. 算法实现:选择合适语言编写内部逻辑,建议使用ST或FBD。
  4. 模拟测试:编写测试用例,通过强制变量或仿真表验证所有分支。
  5. 文档化:在FB属性中填写版本号、作者、修改记录,并在接口注释中说明每个参数的单位与范围。

案例拆解:模拟量滤波功能块的设计

某项目需要采集压力传感器信号(4-20mA),但现场存在高频噪声。我们设计一个名为FB_AvgFilter的功能块:

FUNCTION_BLOCK FB_AvgFilter
VAR_INPUT
    bEnable : BOOL;      // 使能信号
    rRawValue : REAL;    // 原始模拟量值
END_VAR
VAR_OUTPUT
    rFiltered : REAL;    // 滤波后值
    bValid : BOOL;       // 数据有效标志
END_VAR
VAR
    arrBuffer : ARRAY[0..9] OF REAL;  // 环形缓冲区
    nIndex : INT := 0;
    rSum : REAL := 0.0;
    bInitialized : BOOL := FALSE;
END_VAR
// 滤波算法:移动平均
IF bEnable THEN
    IF NOT bInitialized THEN
        FOR i := 0 TO 9 DO
            arrBuffer[i] := rRawValue;
        END_FOR;
        rSum := rRawValue * 10.0;
        bInitialized := TRUE;
    ELSE
        rSum := rSum - arrBuffer[nIndex] + rRawValue;
        arrBuffer[nIndex] := rRawValue;
        nIndex := (nIndex + 1) MOD 10;
    END_IF;
    rFiltered := rSum / 10.0;
    bValid := TRUE;
ELSE
    bValid := FALSE;
END_IF;

该FB在OB35(定时中断,如10ms周期)中被调用。通过环形缓冲区实现滑动平均,避免了每次重新累加的开销。实际测试中,原始信号噪声峰峰值为±0.5bar,滤波后降至±0.05bar,且响应延迟仅为100ms,满足工艺要求。该FB被复用于三个不同测点,节省了重复开发时间。

常见误区与总结复盘

关键教训:封装功能块时,切忌将过多不相关的功能塞入同一个FB。例如,将电机控制和温度采集放在一起,会导致复用困难。应遵循“单一职责原则”,一个FB只做一件事。另外,FB内部禁止直接访问全局变量(如%M、%Q),所有数据必须通过接口传递,否则会破坏封装性。

复盘:结构化编程的收益并非立竿见影,而是在项目后期维护和扩展时体现。例如,当需要将电机控制从星三角改为软启动器时,只需修改FB_MotorControl的内部实现,调用处的接口不变,程序改动量从原来的200行缩减到20行。因此,在项目启动阶段投入20%的时间进行功能块规划,能节省后期60%的调试时间。

2.3 五种编程语言的对比与工程选型

核心原理:语言特性与执行机制

LD基于继电器逻辑图,适合布尔逻辑和互锁控制;FBD以图形化数据流为核心,适合连续控制算法;ST类似Pascal语法,支持复杂数据类型和循环;SFC基于Petri网模型,适合步进控制;IL是低级汇编风格,现已少用。现代PLC均采用编译执行,不同语言最终被编译为相同的机器码,因此执行效率差异不大,差异主要体现在开发效率和可读性上。

语言典型应用优点缺点推荐指数
LD电机启停、安全联锁电气工程师易上手复杂数学运算困难★★★★★
FBDPID控制、模拟量处理信号流清晰逻辑分支不直观★★★★☆
ST算法、数据处理、通信表达能力强需要编程基础★★★★★
SFC批量生产、流程控制状态转换直观不适合连续控制★★★★☆
IL旧设备维护占用空间小可读性差★☆☆☆☆

判断方法:根据控制类型选择

对于组合逻辑(如安全回路),优先LD;对于闭环调节(如温度、压力控制),优先FBD或ST;对于顺序控制(如自动分拣线),优先SFC;对于数据处理(如报表生成、配方管理),优先ST。实际项目中,通常以LD或FBD作为主程序,SFC用于流程框架,ST用于底层算法。

案例拆解:一个自动化仓库的混合编程

某自动化立体仓库需要控制堆垛机、输送线和分拣机器人。我们采用如下架构:

  • SFC:定义入库流程(接收指令→定位→取货→输送→入库→确认),每个步骤调用对应的FB。
  • LD:实现输送线电机的正反转、互锁和急停逻辑。
  • FBD:实现堆垛机水平/垂直速度的PID调节。
  • ST:实现条码解析、库存数据比较和异常报警生成。

项目共封装了23个FB和15个FC,代码总量约8000行。由于模块化设计,调试时能够单独测试堆垛机定位FB,而无需运行整个流程。最终项目提前2周完成验收,且后续新增一个巷道时,仅需复用现有FB,新增配置数据即可。

常见误区与总结复盘

风险提示:不要在一个SFC步骤中编写大量LD逻辑,这会导致步骤内部过于复杂,难以追踪。SFC的每个步骤应只包含一个动作或调用一个FB。另外,避免在ST中使用GOTO语句,应使用IF/ELSE或CASE结构,保持代码结构化。

复盘:语言选型没有标准,但必须保持一致性。建议在项目启动时制定《编程规范》,明确每种语言的使用场景、变量命名规则(如前缀b表示BOOL,r表示REAL)、FB命名规则(如FB_前缀)。这能显著降低团队协作的沟通成本。

2.4 结构化编程的工程实践与数据管理

核心原理:变量作用域与数据一致性

结构化编程要求严格管理变量作用域。全局变量(如全局DB块)应仅用于跨程序共享的数据,如设备模式、生产计数。局部变量(FB内部的VAR)用于封装内部状态。接口变量(VAR_INPUT/OUTPUT)是FB与外部通信的唯一通道。这种隔离机制防止了意外修改,也便于单元测试。

操作流程:数据字典的建立

  1. 列出所有输入/输出信号(I/O列表),分配物理地址或符号名。
  2. 定义中间变量,明确数据类型、初始值、单位、范围。
  3. 设计全局数据块(如DB_Global),按功能分组(如DB_MotorData、DB_ProcessData)。
  4. 为每个FB创建背景数据块(Instance DB),保存其静态变量。

案例拆解:数据管理不当导致的故障

某食品包装线曾出现偶发停机,排查发现是多个FB直接访问了同一个全局M区地址%M10.0作为“设备忙”标志。当两个FB同时检测到该位为TRUE时,产生竞争条件。解决方案是:将“设备忙”状态封装到各自的FB内部,通过输出bBusy传递状态,并增加互锁逻辑。修改后,故障彻底消失。

常见误区与总结复盘

经验总结:在TIA Portal中,建议使用PLC数据类型(UDT)来定义结构体,例如TYPE Motor_Data包含速度、电流、温度等字段。这样在创建多个电机FB时,只需实例化不同的UDT变量,避免重复定义。此外,定期使用“交叉引用”功能检查变量使用情况,删除未使用的全局变量,保持程序整洁。

复盘:数据管理是结构化编程的基石。一个良好的数据字典能减少30%以上的调试时间。建议在项目交付时,同时提供变量清单和FB接口说明文档,便于后续维护人员快速上手。