3. Codesys基础回顾

在深入Codesys开源库应用与自定义库封装之前,必须夯实IEC 61131-3编程语言的基础。Codesys作为全球领先的软PLC开发环境,其核心引擎完全遵循IEC 61131-3标准,支持五种标准编程语言:结构化文本(ST)、功能块图(FBD)、梯形图(LD)、顺序功能图(SFC)和指令表(IL)。这五种语言并非孤立存在,而是可以在同一个工程中混合使用,通过POU(程序组织单元)进行模块化封装。本章将系统回顾这五种语言的核心语法、适用场景以及Codesys工程组织的逻辑结构,为后续的库开发与封装建立坚实的语法与架构基础。

IEC 61131-3 编程模型 ST 结构化文本 高级语言/算法 FBD 功能块图 数据流/信号处理 LD 梯形图 逻辑/继电器控制 SFC 顺序功能图 流程/状态机 IL 指令表 汇编风格/底层 工程组织:Project → Application → POU(PRG/FB/FUN)→ 任务调度 库封装:将FB/FUN封装为 .library 文件 版本管理 / 文档生成 / 访问权限控制 ST FBD LD SFC IL

上图展示了IEC 61131-3编程模型的核心架构。五种语言围绕同一个控制逻辑核心,通过Codesys工程组织进行统一调度。理解每种语言的语法特征和最佳应用场景,是后续开发高质量库文件的前提。下面我们将逐一深入剖析。

3.1 结构化文本(ST):高级算法与复杂逻辑的首选

核心原理

ST语言是一种类似Pascal的高级编程语言,它支持复杂的数据类型、循环、条件分支、函数调用等结构化编程特性。ST语言在Codesys中是最灵活、功能最强大的语言,特别适合实现复杂的数学运算、数据处理、通信协议解析以及状态机逻辑。其编译器优化程度高,执行效率接近C语言。

核心语法要素

语法类别关键字/示例说明
赋值语句A := B + 1;使用 := 进行赋值,语句以分号结束
条件分支IF...THEN...ELSIF...ELSE...END_IF;支持多条件嵌套判断
选择分支CASE...OF...ELSE...END_CASE;适合多值离散判断,比IF更清晰
循环语句FOR...DO...END_FOR;
WHILE...DO...END_WHILE;
支持定长和不定长循环
函数调用Result := F_Calc(Param1, Param2);调用自定义函数或库函数
注释(* 注释内容 *)支持多行注释

实战场景:温度PID控制算法实现

在工业温度控制场景中,我们通常使用ST语言编写PID算法。以下是一个典型的ST代码片段:

PROGRAM PRG_TempControl
VAR
    rSetPoint    : REAL := 100.0;   (* 目标温度 *)
    rPV          : REAL;            (* 过程变量 *)
    rError       : REAL;
    rIntegral    : REAL;
    rDerivative  : REAL;
    rOutput      : REAL;
    rKp          : REAL := 2.5;
    rKi          : REAL := 0.8;
    rKd          : REAL := 0.1;
    rPrevError   : REAL;
    rSampleTime  : TIME := T#100MS;
END_VAR

(* 主控制循环 *)
rError := rSetPoint - rPV;
rIntegral := rIntegral + rError * TIME_TO_REAL(rSampleTime);
rDerivative := (rError - rPrevError) / TIME_TO_REAL(rSampleTime);
rOutput := rKp * rError + rKi * rIntegral + rKd * rDerivative;
rPrevError := rError;

(* 输出限幅 *)
IF rOutput > 100.0 THEN
    rOutput := 100.0;
ELSIF rOutput < 0.0 THEN
    rOutput := 0.0;
END_IF;
经验提醒:在ST编程中,务必注意数据类型的一致性。例如,TIME_TO_REAL() 转换函数是必须的,因为 TIME 类型不能直接与 REAL 进行算术运算。此外,积分饱和问题需要通过输出限幅和积分清零逻辑来处理。

常见误区

  • 滥用全局变量:在ST中直接访问全局变量会导致程序耦合度高,难以维护和复用。应通过功能块的输入/输出接口传递数据。
  • 忽略初始化:ST中的变量默认初始化为零值,但自定义复杂结构体或数组时,必须显式初始化,否则可能产生未定义行为。
  • 循环陷阱:在 WHILE 循环中忘记更新退出条件,会导致PLC看门狗超时,触发系统停机。

3.2 功能块图(FBD)与梯形图(LD):逻辑控制的双璧

核心原理

FBD和LD都是图形化编程语言,它们通过连线表示数据流和逻辑流。FBD侧重于信号处理和数据流,适合模拟量处理和复杂功能块组合;LD则源自继电器控制电路,适合数字量逻辑控制,如电机启停、互锁保护等。在Codesys中,这两种语言可以互相转换,且都支持调用ST编写的功能块。

操作流程:LD编程的关键步骤

  1. 定义变量:在变量表中声明输入(如启动按钮 bStart)、输出(如接触器 bMotor)和中间变量。
  2. 放置触点/线圈:在LD编辑器中,使用常开触点(--| |--)和线圈(--( )--)构建逻辑。
  3. 添加功能块:拖入定时器TON、计数器CTU等标准功能块,并连接输入输出。
  4. 编译检查:使用Codesys的编译功能检查连线错误和类型不匹配。

案例拆解:电机星三角启动控制

在电机控制柜中,星三角启动是常见的降压启动方式。使用LD语言实现时,需要三个接触器(主接触器KM1、星接触器KM2、角接触器KM3)和一个定时器T1。逻辑要求:启动时KM1和KM2吸合,延时5秒后KM2断开、KM3吸合。同时必须保证KM2和KM3不能同时吸合,否则短路。

步骤动作LD实现方式
1按下启动按钮常开触点 bStart 闭合
2KM1吸合并自锁KM1线圈并联自身常开触点
3KM2吸合,定时器启动KM2线圈串联KM3常闭触点,TON定时器启动
45秒后切换TON输出Q置位,断开KM2,吸合KM3
5停止停止按钮 bStop 常闭触点断开所有线圈
风险提示:在LD编程中,必须添加硬件互锁和软件互锁双重保护。软件互锁通过KM2和KM3的常闭触点串联实现,硬件互锁则需要在接触器控制回路中增加机械联锁。仅依赖软件互锁在PLC故障时可能失效。

常见误区

  • 线圈重复输出:同一个线圈在LD中只能输出一次,否则编译报错。若需多处控制,应使用中间变量或置位/复位指令。
  • 忽略扫描周期:LD程序按从左到右、从上到下的顺序扫描。如果逻辑依赖扫描顺序,可能导致意想不到的结果。建议使用显式的边沿检测指令(R_TRIG/F_TRIG)。

3.3 顺序功能图(SFC)与指令表(IL):流程控制与底层操作

核心原理

SFC是一种描述顺序控制过程的图形化语言,它将复杂的控制流程分解为多个步骤(Step)和转换条件(Transition)。SFC非常适合批处理、流水线控制等具有明确状态顺序的应用。IL则是一种类似汇编的低级语言,使用累加器(ACCU)进行操作,目前在工程中已较少使用,但在某些遗留系统或性能极敏感的场合仍有价值。

SFC核心结构

  • 步骤(Step):包含一组动作(Action),可以是ST代码或LD逻辑。
  • 转换(Transition):定义从一个步骤切换到下一个步骤的条件,通常是一个布尔表达式。
  • 分支与合并:支持选择分支(IF...ELSIF)和并行分支(AND),用于处理多路径流程。

实战场景:自动化灌装线流程

一个典型的灌装线包含以下步骤:待机 → 空瓶到位 → 灌装 → 封盖 → 送出。使用SFC可以清晰表达:

步骤 S0: 待机
  动作: 所有执行器关闭
  转换 T0: 启动按钮按下 AND 空瓶到位传感器 ON

步骤 S1: 灌装
  动作: 打开灌装阀,启动灌装泵
  转换 T1: 液位传感器达到高限

步骤 S2: 封盖
  动作: 关闭灌装阀,启动封盖电机
  转换 T2: 封盖完成传感器 ON

步骤 S3: 送出
  动作: 启动传送带电机
  转换 T3: 送出传感器 ON → 返回 S0
设计建议:SFC的每个步骤都应设置超时监控。例如,灌装步骤超过10秒未完成,应触发报警并跳转到安全步骤。这可以通过在步骤动作中调用TON定时器实现。

IL语言简述

IL语言使用类似 LD(加载)、ST(存储)、ADD(加法)等指令操作累加器。例如:

LD  Var1
ADD Var2
ST  Result

这段代码将Var1加载到累加器,加上Var2,然后将结果存储到Result。IL语言在Codesys中仍受支持,但官方推荐优先使用ST或FBD。

常见误区

  • SFC死锁:如果转换条件永远不满足,流程会卡死在当前步骤。必须设计超时或强制跳转逻辑。
  • IL可读性差:IL代码难以调试和维护,除非有特殊需求,否则不建议在新项目中使用。

3.4 Codesys工程组织:从任务到库的架构思维

核心原理

Codesys的工程组织遵循分层架构:Project(工程)→ Application(应用)→ POU(程序组织单元)→ Task(任务)。POU是代码复用的基本单元,分为三种类型:程序(PRG)、功能块(FB)和函数(FUN)。PRG由任务调度执行,FB和FUN则被PRG或其他FB调用。

工程组织最佳实践

层级内容管理要点
Project包含设备配置、网络通信、全局变量使用版本控制(如SVN/Git)管理工程文件
Application独立的运行环境,可包含多个任务每个应用有独立的变量命名空间
POUPRG/FB/FUNFB应封装独立功能,FUN不应有静态变量
Task定义执行周期和优先级将实时性要求高的任务设为高优先级

操作流程:创建自定义功能块并封装为库

  1. 创建FB:在工程中新建功能块,定义输入/输出变量和内部变量。
  2. 编写逻辑:使用ST或FBD实现功能。
  3. 测试验证:在本地工程中编写测试PRG,模拟输入并监控输出。
  4. 封装库:右键点击FB,选择“保存为库元素”,设置版本号和文档说明。
  5. 生成库文件:通过“库管理器”导出为 .library 文件。
关键提醒:在封装库之前,必须确保FB内部没有直接引用全局变量或外部硬件地址。所有外部依赖都应通过输入接口传入,否则库的复用性将大打折扣。

案例拆解:将PID控制器封装为可复用库

假设我们已经编写了一个PID功能块 FB_PID,现在要将其封装为库供多个项目使用。首先,检查FB的接口:输入为 rSetPoint、rPV、rKp、rKi、rKd,输出为 rOutput。内部变量全部声明为VAR(非VAR_GLOBAL)。然后,在库管理器中创建新库,将FB拖入,填写版本号1.0.0.0,添加帮助文档。最后,编译生成 PID_Lib.library 文件。在其他工程中,只需通过“库管理器”安装此文件,即可像使用标准库一样调用 FB_PID。

常见误区与复盘

  • 任务周期设置不当:将PID控制放在周期为1秒的任务中,会导致控制效果极差。应根据被控对象的响应速度设置任务周期(如10ms-100ms)。
  • 库版本混乱:库更新后未同步更新版本号,导致不同项目使用不同版本的库,排查问题时难以定位。
  • 忽略库的依赖关系:如果库A依赖库B,封装时必须声明依赖关系,否则在目标工程中加载会报错。
总结复盘:掌握IEC 61131-3五种语言的核心语法是Codesys开发的基础。ST适合算法、FBD适合信号流、LD适合逻辑控制、SFC适合顺序流程、IL作为补充。而工程组织的核心在于模块化思维:将功能封装为FB,通过任务调度执行,最终沉淀为可复用的库文件。下一阶段,我们将深入探讨如何利用这些基础构建高效的Codesys开源库。