IEC 61131-3编程实战:五种PLC语言选型与避坑指南

发布时间:2026/10/24 12:01:20
IEC 61131-3编程实战:五种PLC语言选型与避坑指南

1. 从继电器柜到软PLC:为什么今天还要啃IEC 61131

干了十几年工控,我越来越觉得IEC 61131这个标准像一本"老黄历"——刚入行的人觉得它过时,老手却把它当字典翻。但现实是,不管你用的是哪家的PLC,只要打开编程软件,那些LD、FBD、ST、SFC的选项,全都是从这个标准里长出来的。你可以不背标准号,但你绕不开它定义的这套语言体系。

IEC 61131是国际电工委员会给可编程控制器定的"通用语法书",一共分了十个部分,从概述、硬件要求、编程语言、用户指南到通信、模糊控制、安全,基本把PLC从里到外管了个遍。其中跟我们日常写程序关系最紧的,是第三部分——编程语言。它规定了五种语言:梯形图(LD)、功能块图(FBD)、顺序功能图(SFC)、指令表(IL)和结构化文本(ST)。前四种偏图形化,ST偏高级语言,IL现在基本被淘汰了,新标准里已经把它边缘化。

这套标准解决的核心问题就一个:让不同品牌的PLC程序能互相看懂、互相移植。以前A家的梯形图和B家的梯形图符号不一样,工程师换个品牌就得重新学一遍,项目交接更是灾难。标准统一之后,你只要懂LD的扫描逻辑,换到另一家平台,无非是快捷键和界面不同,底层思维是通的。

这篇文章适合谁看?如果你是刚转行做PLC的电气工程师,或者从单片机、嵌入式转过来的开发者,又或者是自动化专业的学生,那这篇内容能帮你把"会用软件"和"懂原理"之间的那道墙拆掉。我不打算照本宣科讲标准条文,而是把标准里的关键点拆开,结合我实际做项目踩过的坑,告诉你哪些地方必须较真,哪些地方可以灵活处理。

2. 五种编程语言到底怎么选:别再用梯形图硬写所有逻辑

2.1 梯形图LD:不是画电路图,是在描述扫描周期

很多人第一次接触梯形图,以为就是把继电器电路搬到屏幕上。这个理解对了一半,但漏掉了最关键的一点:PLC是循环扫描的,梯形图的"能流"不是同时流动的,而是从左到右、从上到下逐行计算的。

我见过太多新手写出这样的逻辑:一个按钮同时触发两个输出,结果第二个输出偶尔不动作。原因就是他把梯形图当成了并行电路,实际上PLC在每个扫描周期里,先算第一行,更新了内部状态,再算第二行。如果第二行依赖的状态在第一行被改变了,结果就跟预期不一样。

梯形图的优势在于布尔逻辑直观,处理开关量、互锁、联锁这类逻辑特别顺手。但它不适合做复杂运算、循环、字符串处理。我个人的经验是:纯开关量逻辑用LD,超过三层的条件嵌套就考虑换ST。

2.2 功能块图FBD:搞过程控制的人更爱它

FBD用方框和连线表示逻辑,看起来像数字电路图。它在欧洲和过程控制领域用得比较多,尤其是模拟量处理、PID控制、滤波算法这些场景。一个PID功能块,输入输出引脚一接,参数一填,比用LD搭一堆加减乘除清爽得多。

但FBD的坑在于连线容易乱。项目一大,功能块之间的连线像蜘蛛网,排查问题的时候得顺着线一根根找。我的做法是:按功能分区,每个区不超过两屏,跨区信号用标签变量中转,别让线直接飞过去。

2.3 顺序功能图SFC:设备动作流程的"剧本"

SFC是五种语言里最被低估的。它把设备动作拆成"步"和"转换条件",特别适合描述有明确先后顺序的流程,比如一台包装机的上料、压合、保压、开模、取件。

我做过一个多工位转盘设备,一开始用LD写,几百行逻辑缠在一起,改一个动作要翻半天。后来改用SFC重写,每个工位一个步序,转换条件写在步与步之间,逻辑一目了然。调试的时候直接看当前停在哪个步,问题定位快了一倍。

注意:SFC不是所有PLC都完整支持,选型前要确认目标平台对SFC的支持程度。有些小型PLC只支持LD和ST,SFC是阉割版。

2.4 结构化文本ST:复杂运算和算法的唯一出路

ST长得像Pascal,有IF、CASE、FOR、WHILE这些结构。凡是涉及数组操作、配方管理、通信协议解析、复杂数学运算的,我都用ST写。用LD写一个冒泡排序试试?能写,但维护的人会想打人。

ST的难点不在语法,而在扫描周期意识。新手容易写出一个FOR循环跑几千次,结果扫描周期从5ms飙到200ms,设备直接报警。我的原则是:ST里不做耗时操作,大循环拆成状态机,每个周期只处理一小部分。

2.5 指令表IL:知道它存在就行

IL是低级语言,类似汇编,可读性差,新标准已经不再主推。除非你维护的是十几年前的老设备,否则没必要专门学。看到老程序里的IL,能看懂大概意思就够了。

语言最适合场景学习难度我的使用频率
LD开关量逻辑、互锁低高
FBD模拟量、PID、滤波中中
SFC流程控制、步序中中
ST运算、算法、通信中高高
IL老设备维护高极低

3. 变量、数据类型与任务:标准里最容易被跳过的硬骨头

3.1 变量命名不是小事,它决定了程序能不能交接

IEC 61131把变量分成了几类:全局变量、局部变量、输入输出变量、临时变量。标准里对命名没有强制规定,但实际项目里,命名混乱是维护成本的最大来源。

我接手过一个项目,变量名叫M1、M2、M3一直到M200多,没有任何注释。花了整整两天才理清楚哪个M对应哪个气缸。后来我给自己定了规矩:变量名必须包含"设备位号+功能+类型",比如CV01_Cylinder_Extend_Cmd,一看就知道是1号气缸伸出命令。

标准里还定义了变量的作用域。全局变量在整个程序里都能读写,方便但危险;局部变量只在当前POU(程序组织单元)里有效,安全但需要传递。我的经验是:能用局部就不用全局,必须共享的状态才放全局,并且集中管理。

3.2 数据类型选错,精度和性能都遭殃

IEC 61131定义了一套标准数据类型:BOOL、BYTE、WORD、DWORD、INT、DINT、REAL、TIME、STRING等等。看起来简单,但选型有讲究。

举个实际例子:一个温度值范围是0到200摄氏度,保留一位小数。如果你用INT存,只能存整数,小数丢了;用REAL存,精度够了,但占4个字节,运算慢;更好的做法是用INT存放大10倍的值,比如205代表20.5度,显示的时候再除10。这样既保精度又省资源。

再比如计数器,很多人不管三七二十一就用INT。但如果计数可能超过32767,INT就溢出了,得用DINT。我踩过一次坑:一个包装计数用INT,跑到三万多次的时候突然变成负数,查了半天才发现是溢出。

数据类型位数范围典型用途
BOOL10/1开关量、标志位
INT16-32768~32767中小计数、模拟量原始值
DINT32±21亿大计数、累计量
REAL32浮点温度、压力、PID
TIME32时间延时、超时判断
STRING可变字符串配方名、通信报文

3.3 任务配置:程序不是从头跑到尾的

这是很多新手完全忽略的部分。IEC 61131里,程序不是一条直线跑到底,而是按任务来调度的。任务分周期任务和事件任务。周期任务每隔固定时间执行一次,事件任务由特定条件触发。

为什么这个重要?因为不同逻辑对执行频率的要求不一样。急停逻辑要求最快响应,可能1ms跑一次;温度PID控制10ms跑一次就够了;数据记录1s跑一次都嫌快。如果全塞在一个任务里,要么快的被拖慢,要么慢的白占CPU。

我通常这样分配:高速任务1~5ms放安全逻辑和位置控制,中速任务10~20ms放PID和逻辑联锁,低速任务100ms~1s放数据记录和通信。这样CPU负载均衡,响应也及时。

4. 从零写一个电机星三角启动程序:五种语言实战对比

4.1 需求拆解与IO分配

拿一个最经典的案例:三相异步电机星三角降压启动。控制要求是:按下启动按钮,主接触器和星接触器先吸合,延时5秒后星接触器断开、角接触器吸合,电机进入正常运行。按下停止按钮,所有接触器断开。热继电器动作时,立即停机并报警。

IO分配如下:

  • 输入:启动按钮I0.0、停止按钮I0.1、热继电器I0.2
  • 输出:主接触器Q0.0、星接触器Q0.1、角接触器Q0.2、报警Q0.3
  • 内部变量:启动延时T1、星角切换互锁标志

4.2 梯形图实现与扫描逻辑分析

梯形图写法大家都会,但我要强调的是互锁。星接触器和角接触器绝对不能同时吸合,否则电源短路。所以Q0.1和Q0.2的线圈前面必须互相串对方的常闭触点。

另外,星角切换的延时用TON功能块。TON的输入IN从0变1开始计时,计时到设定值后Q输出1。注意:TON在IN保持为1时,Q一直为1;IN变0后,Q立即变0,当前时间清零。这个特性决定了你不能用TON的Q去直接驱动角接触器,得用它的Q去复位星接触器、置位角接触器。

我见过有人用TON的Q直接接角接触器线圈,结果星接触器不断开,两个同时吸合,砰一声。这就是没理解TON输出特性的后果。

4.3 用ST重写核心逻辑

同样的逻辑用ST写,代码更紧凑:

IF I0.2 THEN Q0.0 := FALSE; Q0.1 := FALSE; Q0.2 := FALSE; Q0.3 := TRUE; ELSIF I0.0 AND NOT I0.1 THEN Q0.0 := TRUE; IF NOT T1.Q THEN Q0.1 := TRUE; Q0.2 := FALSE; ELSE Q0.1 := FALSE; Q0.2 := TRUE; END_IF; ELSIF I0.1 THEN Q0.0 := FALSE; Q0.1 := FALSE; Q0.2 := FALSE; Q0.3 := FALSE; END_IF; T1(IN := Q0.0 AND Q0.1, PT := T#5S);

这段ST里,T1的调用放在最后,保证每个周期都更新。注意T#5S是IEC标准的时间字面量写法,比某些平台用5000毫秒更规范。

4.4 SFC描述步序更清晰

如果用SFC,整个流程就是:初始步→按启动→星启动步→延时5秒→角运行步→按停止→回初始步。每个步里写该步的输出,转换条件写在步之间。调试的时候直接看当前激活的是哪个步,比翻梯形图快得多。

4.5 三种写法的取舍

这个案例简单,三种写法都能实现。但我的建议是:逻辑简单用LD,流程清晰用SFC,运算复杂用ST。不要为了炫技硬用某一种,工具是拿来解决问题的,不是拿来表演的。

5. 调试与排错:那些标准不会告诉你的实战经验

5.1 扫描周期引起的"幽灵故障"

有个项目,设备偶尔会漏动作,一天出现一两次,怎么查都查不出来。后来用示波器抓PLC的扫描周期,发现偶尔会从8ms跳到50ms。原因是程序里有个ST的FOR循环,循环次数取决于一个外部变量,外部变量偶尔会变成很大的值,循环跑了几万次。

排查思路:先看扫描周期是否稳定,再看有没有条件循环、大数组操作、通信阻塞。标准里不会告诉你这些,但实际项目里这是最常见的性能陷阱。

5.2 变量未初始化导致的随机行为

IEC 61131规定变量有初始值,BOOL默认FALSE,INT默认0。但有些平台的临时变量不初始化,值是不确定的。我遇到过一次,一个临时变量没赋值就参与运算,结果每次上电行为都不一样。

避坑方法:所有变量声明时显式赋初值,临时变量在使用前必须赋值。别依赖平台的默认行为。

5.3 浮点数比较的坑

REAL类型比较不能用=,因为浮点运算有精度误差。0.1+0.2不等于0.3,这在PLC里同样成立。正确做法是判断差值绝对值小于一个很小的数,比如ABS(A-B) < 0.001。

5.4 常见问题速查表

现象可能原因排查方向
输出偶尔不动作扫描周期波动检查循环、通信阻塞
上电行为不一致变量未初始化检查临时变量和保持变量
模拟量跳动大滤波不足或干扰加滤波、检查屏蔽接地
通信断断续续任务优先级冲突调整通信任务周期
计数器突然变负数据类型溢出换DINT或加溢出判断

6. 标准之外的工程习惯:让程序能被人看懂

IEC 61131管的是语法和结构,但管不了你的程序好不好维护。我做了这么多年,总结了几条标准里不写但必须遵守的规矩。

第一,每个POU只做一件事。一个功能块里又做逻辑又做运算又做通信,出了问题根本没法定位。拆开,每个块职责单一。

第二,注释写"为什么"不写"是什么"。Q0.0 := TRUE; // 启动主接触器这种注释没意义,代码本身就说明了。要写的是// 这里延时5秒是因为星角切换需要等电机转速降下来,解释设计意图。

第三,版本管理。PLC程序也要进版本库,每次修改记录改了什么、为什么改。我见过太多项目,程序改了十几版,最后不知道哪版是现场在用的。

第四,仿真先行。现在主流平台都支持仿真,逻辑先在电脑上跑通,再去现场调试。现场调试时间宝贵,别把仿真能解决的问题带到现场。

第五,留调试接口。程序里预留一些强制变量、模拟量手动输入、步序跳转的接口,调试的时候能省大量时间。正式运行时把这些接口屏蔽掉就行。

这些习惯跟IEC 61131标准本身没关系,但它们决定了你的程序是"能跑"还是"好用"。标准给你语法,工程习惯给你质量。两样都有,才算是真正入了PLC这行的门。