用IEC 61131这套标准串起PLC编程这件事,是很多工程师绕了远路之后才意识到必须做的事。我见过太多人只会用某个品牌环境的工具栏点来点去,换一个牌子的PLC就抓瞎;也见过有经验的老法师,能把梯形图画得像天书一样漂亮,但程序一移植到新平台,整张图直接废掉。这篇文章就把IEC 61131以及它背后的PLC编程基础知识彻底理一遍,重点讲清楚标准到底解决了什么问题、五种编程语言各自适合什么场景、一个真实的启保停程序该怎么从零搭出来,以及我在现场踩过的那些坑。不管你是什么基础,看完至少能建立起一套“无论换哪个平台都通用”的PLC编程心智框架。
1. 为什么IEC 61131值得认真学习
1.1 标准到底解决了什么问题
在IEC 61131出现之前,PLC编程基本是每个厂家各玩各的。指令集不一样,编程软件不一样,变量声明方式不一样,甚至同一个逻辑在不同品牌里的实现思路都截然不同。这意味着什么?意味着你在一家公司的设备上积累的经验,换个品牌就打了折扣,项目代码换到另一条产线几乎没有任何复用价值。对个人是苦功重复练,对公司则是重复投入技术成本。
IEC 61131这个系列标准,把PLC从硬件组成、设备测试、编程语言、通信接口,到功能安全相关的使用要求,全体系地规范了一遍。其中IEC 61131-3是关于编程语言的核心标准,它把编程语言统一成五种规范语言,同时定义了一套独立的软件模型和程序组织单元机制。换句话说,它给了这个行业一套“通用语法”。有了这套语法,你写出来的程序结构,至少在概念层面对任何遵守标准的平台都是成立的。实际做项目的时候,我感受最深的一点是:遵从IEC 61131-3组织出的程序,换平台时主要工作是重新映射IO和调整厂商差异,核心逻辑代码的迁移成本明显低很多。
有人把IEC 61131当成一个高深的理论标准,其实它更像一本行业共同遵守的“沟通手册”。当你和同事、和外部供应商协作时,你说“程序组织单元”、“任务配置”、“功能块实例”,对方能立刻明白你在说什么,而不是各自用一套黑话。这个价值在多人协作和跨公司项目里被放得很大。
1.2 哪些人在学它,学到什么程度算入门
我身边学PLC的人大致分四类:第一类是刚入行的自动化工程师,需要快速上手项目;第二类是设备维护人员,主要为了看懂程序、快速定位故障;第三类是做上位机或软件的工程师,想补充底层控制逻辑的知识盲区;第四类是高校相关专业的学生,需要建立完整概念体系。人群不同,切入角度也不同,但万变不离其宗,都要回到IEC 61131这棵大树上来。
关于“学到什么程度算入门”,我的观点很朴素:能独立用一个标准语言写启保停、定时、计数、顺序控制,并且能解释扫描周期和数据生命周期对逻辑的影响,基本就算入行了。很多人工作好几年还在靠复制粘贴老程序过日子,程序能跑但说不上为什么能跑,遇到断电恢复后设备不启动就发懵,这种状态其实是知识体系中缺了IEC 61131软件模型那一块。
我当年入行时就是在某项目里被一个“程序下载后不执行”的问题卡了两天,后来被一位老同事点拨说看看任务有没有挂上,我才第一次意识到,PLC程序不是编译下载就自动在跑的,它需要一个“任务”作为调度入口。这一下子把我从“照着抄程序”的状态拽到了“理解软件模型”的路上。所以文章中凡是涉及软件模型、任务扫描、变量生命周期这些概念,我都会重点展开,因为这些恰恰是教科书里一笔带过、却在现场最能救命的常识。
2. IEC 61131标准全景拆解:从软件模型到POU体系
2.1 标准不是只有编程语言
先把概念边界理清楚。IEC 61131是一个系列标准,很多人一听到它就想到了编程语言,实际上编程语言只是这个家族的第三部分。完整的家族结构大致是:
- 第1部分:通用信息。定义PLC的基本术语、系统结构、功能特性,比如CPU、存储器、IO系统、外围设备的通用描述。
- 第2部分:设备要求与测试。规定PLC设备在电气、机械、环境、电磁兼容方面的硬性要求,以及测试方法。
- 第3部分:编程语言。也就是PLC程序员天天打交道的核心,规定了编程语言的语法、软件模型和通用元素。
- 第4部分:用户指南。指导用户怎么选型、安装、维护PLC系统。
- 第5部分:通信。定义PLC与PLC、PLC与上位机之间的通信模型和总线接口要求。
- 第6部分:功能安全。针对安全相关应用,规定了安全PLC的编程和使用要求,涉及到停机等级、安全逻辑的可靠性等。
- 第7部分:模糊控制编程。为模糊控制在PLC上的实现提供参考。
实际做项目时,第3部分是编程主力,但我不止一次遇到因为不看第5部分导致现场通信不上,或者因为不懂第2部分的EMC要求导致模拟量信号被变频器干扰得没法看的情况。所以建议不要只读编程语言那一章,等做过的项目多了,再回头把设备、通信、安全这几个部分补上,知识体系才完整。
2.2 IEC 61131-3的软件模型到底在说什么
IEC 61131-3里最被低估的概念,其实是它的软件模型。这个模型自上而下分成配置、资源、任务、程序几个层次,理解了这个模型,你再看任意一款IDE的工程树,就会发现所有那些看着杂乱的节点其实都逃不出这个骨架。
配置对应整个控制系统,也就是一台PLC,或者一套分布式控制系统中某个控制器逻辑上的完整软件描述。资源配置定义控制器里的处理单元,例如一个配置里可以包含多个CPU资源。任务则决定了程序的调度行为,比如一个周期任务以10毫秒为周期循环执行某几个程序,另一个事件触发任务在某个信号边沿来临时才执行。程序挂在任务下面,由任务决定它什么时候运行。程序内部再组织函数和功能块。
这个模型的工程价值在于排查思路。很多人遇到“程序没跑起来”就疯狂改逻辑,但更高效的做法是先看工程结构:这个程序挂到任务上没有?任务周期是多少?任务有没有被禁用?程序里调用的功能块有没有独立实例?这就像排查一台机器不转的时候先看有没有接通电源,而不是急着拆电机。
有一次我在某项目里修改一个设备控制程序,下载下去之后一切正常,但第二天早上设备突然间响应异常,现场来看又查不出硬件故障。后来打开工程树,发现那个程序同时被两个任务引用,一个是周期任务,一个是事件任务,两个任务都在写同一个输出变量,导致输出状态完全不可预测。这就是软件模型没理清楚带来的经典问题:资源配置和任务归属混乱。如果我们一开始就按配置-资源-任务-程序的层次做好规划,这种问题完全可以避免。
2.3 数据类型、变量与POU体系
IEC 61131-3的基本数据类型覆盖了BOOL、BYTE、WORD、DWORD、LWORD,以及有符号整型SINT、INT、DINT、LINT,还有REAL、LREAL浮点数、STRING字符串、TIME时间、DATE日期等。这里最容易出问题的是整型选择。例如INT在大多数平台上是16位,范围是-32768到32767。如果你用INT累加一个持续增加的计数值,超过32767之后的行为在不同厂家实现里可能不一样,有的回绕到负数,有的直接报错。所以涉及大范围计数或者累加的变量,我一般直接上DINT,32位,安全得多。
变量声明方面,VAR是局部变量,VAR_GLOBAL是全局变量,VAR_INPUT、VAR_OUTPUT、VAR_IN_OUT对应功能块的输入、输出和输入输出参数,VAR_TEMP则是临时变量。很多人把VAR和VAR_TEMP混着用,尤其刚接触ST的工程师,喜欢用VAR_TEMP存中间计算结果,然后下次调用时发现值变成了随机数,因为VAR_TEMP在每次调用结束后不保证保留。如果你需要一个跨调用周期保持的值,一定把它声明为VAR,或者把逻辑放进功能块里用功能块的实例化内存。
POU体系是IEC 61131-3的另一个核心概念:程序、函数、功能块。程序是执行单元,挂在任务下;函数没有内部状态,同样的输入必然得到同样的输出,典型的加法运算、位运算都是函数;功能块则不同,它每次被调用时都带着自己的内部记忆,比如定时器、计数器、PID控制器都是标准里拿来举例的功能块。理解函数和功能块的区别极其重要,很多人写复杂算法时,在函数里偷偷“记住”上一次的状态,却没把变量声明成功能块的实例,结果程序的表现在版本升级之后彻底改变,怎么查都查不出来。
3. 五种编程语言怎么选:梯形图、功能块图、ST、IL与SFC实战对比
3.1 梯形图与功能块图的用武之地
五种语言各有各的脾气,选型选好了,维护成本低一大半。
梯形图(LD)的形态和继电器电路非常像,左母线、右母线、触点、线圈、定时器、计数器,电气工程师几乎零门槛上手。它的最大优势是直观,现场电工老师傅也能看懂你写的逻辑,这对设备维护极其友好。所以电机启停、正反转、阀控、连锁保护这些以开关量逻辑为主的场景,我几乎默认用梯形图。
功能块图(FBD)更像信号流程图,它用连线把函数和功能块连接在一起,体现出清晰的数据流动方向。PID回路、模拟量滤波、信号处理这类连续控制算法,用功能块图表达到底比梯形图舒服得多。你看一张功能块图,输入在哪、处理后往哪走、输出给谁,一目了然。但要注意,混用语言时一定要克制。我的习惯是主控制逻辑保持一种语言风格,算法局部可以用ST或者FBD,但不要一个程序里梯形图、FBD、ST三种语言来回穿插。维护的人会疯掉的——本来顺着梯形图看逻辑,突然跳到一个FBD块,还得去翻输入输出连接关系。
3.2 结构化文本与指令表的使用场景
结构化文本(ST)我非常偏爱,因为它接近通用高级语言,支持IF、CASE、FOR、WHILE这些语句,写复杂算法就像写普通程序一样顺。数组遍历、数据打包、CRC校验、曲线拟合、状态机逻辑,这些东西用梯形图写会写到怀疑人生,用ST则清晰得多。可以说,凡是数学运算和算法逻辑密集的部分,ST是首选。
指令表(IL)更像汇编语言,一个指令一行,很古老。它在存储空间极其紧张的老式PLC上有价值,但可读性确实低。现在的新项目几乎不会用IL来写主逻辑了,但维护老设备时还是会碰到。我自己的策略是:读得懂IL的基本节奏,真要用它开发新逻辑的时候尽量避免,毕竟维护成本和沟通成本都太高。
做个简单的选型对比:
| 语言类型 | 核心优势 | 适合场景 | 不适合场景 |
|---|---|---|---|
| 梯形图LD | 直观、适合电气逻辑 | 开关逻辑、互锁、继电器电路替代 | 复杂数学运算、大数据处理 |
| 功能块图FBD | 数据流清晰 | PID、模拟量处理、功能组合 | 复杂流程状态管理 |
| 结构化文本ST | 接近高级语言、灵活 | 算法、数据处理、复杂逻辑 | 纯电气维护人员查看 |
| 指令表IL | 紧凑、底层 | 老设备维护、简单逻辑 | 可读性差、新项目不推荐 |
| 顺序功能图SFC | 状态流程清晰 | 顺序控制、流程状态机 | 单纯组合逻辑 |
3.3 顺序功能图的高级用法
顺序功能图(SFC)是处理流程控制的一把好手。它把控制逻辑抽象成一步一步的状态,步与步之间用转移条件衔接。流水线、包装线、产线顺序启动这类场景,用SFC画出来,整个流程像看流程图一样清楚,维护的人能直接看出当前停在哪个工步。
高级应用中,SFC还支持并行分支、选择分支、跳转和循环。比如一条流水线上两台设备可以并行运行,各自走各自的步骤序列,到某个汇合点再同步,用并行分支表达就非常自然。选择分支则适合那种“根据条件走不同路径”的逻辑。
但用SFC也有一个常见坏习惯:把所有动作都堆在同一个步里。我见过某些同事把一步写成“同时操作十个输出、还要做一堆数据处理”,表面上看步数很少,实际上这个步内部的复杂度堪比一个完整的子程序。调试时一旦这个步出问题,光是理清里面的操作顺序就要半天。我坚持的原则是:一个步一个职责,最多两三个关联输出,复杂动作就用独立程序或者功能块去封装,转移条件写在步与步之间,保持SFC图的清爽。
4. 从零上手:环境准备、启保停程序与扫描周期实操
4.1 硬件与环境准备
学PLC最理想的方式当然是实物练手,但多数人一开始受条件限制,接触不到完整设备。现在很多编程软件自带仿真器,顺序逻辑和算法完全可以在PC上跑,等基本概念掌握了再上真实硬件验证。如果没有完整的实验台,强烈建议先把仿真玩熟,再找真机体验。
如果准备搭建一套入门环境,大概需要这些:一台装有PLC编程软件的PC;一个基础型CPU模块,建议带模拟量输入,这样将来做模拟量处理不至于再补硬件;一套按钮和指示灯面板,用于仿真真实的操作输入;一个24V直流电源;导线和接线端子若干。这套配置足够覆盖PLC入门和中级练习的内容。
接线有个特别容易踩的坑:传感器电源和控制器的参考地必须一致。如果传感器用一路电源、控制器用另一路电源,两个电源的参考电位又不一致,轻则信号波动,重则损坏IO通道。所以接线之前,先画一张电源分配图,把所有设备的0V统一接到同一个参考点上,再动手。
4.2 用结构化文本写启保停逻辑
启保停逻辑是所有PLC程序的基本功。它描述的是这样的控制要求:按下启动按钮,输出保持运行;按下停止按钮,输出停止;如果运行中断电,重新上电后,绝对不会自动启动。这个“断电后不能自启动”在许多设备安全规范里是强制要求,防止意外启动造成人身伤害。
用结构化文本写这个逻辑,最朴素的版本大概是这样:
// 启动按钮边沿检测 IF EdgeStart THEN RunCmd := TRUE; END_IF; // 停止按钮电平触发,停止优先 IF StopBtn THEN RunCmd := FALSE; END_IF; // 急停信号为TRUE时,无条件断开输出 IF EStopActive THEN RunCmd := FALSE; END_IF; // 输出映射 MotorOut := RunCmd;这段代码里最值得琢磨的不是语法,而是程序内部的“状态保持”。启动按钮和停止按钮通常是瞬时按钮,不是自锁开关,程序必须自己记住“现在是否在运行”这个状态,这就是RunCmd这个内部变量存在的意义。它相当于一个软件自锁:按钮按下时置位,要想保持下去,必须靠程序周期执行时继续保存这个值。
我在实际项目里还会叠加几个额外的安全考虑:急停信号必须用常闭逻辑,同时在硬件层面用独立的急停回路直接切断动力电源。程序里的急停只是第二层保护,绝对不要觉得“程序里写了急停就万事大吉”。这个认知很多刚转行的人没有,一旦急停回路被人为短接,程序根本拦不住,后果不堪设想。另外,启动条件的复位逻辑也要考虑:很多设备要求启动前先复位报警,报警不复位不允许启动,这就是一个典型的联锁条件。把这些联锁全部用输入变量组合出来,不要只判断一个启动按钮,程序安全性会提升一个层级。
4.3 扫描周期与任务配置的关键点
PLC的运行可以抽象成三个步骤循环:读输入、执行程序、写输出。这个循环就是扫描周期。IEC 61131-3里的任务配置决定了程序在这个循环里的调度方式。
入门的时候不要一下子配置一堆复杂任务,先用一个周期任务,循环时间取1毫秒到50毫秒之间都行,根据你控制的设备惯性来定。如果控制的是普通电机阀门,10到20毫秒的周期很常见;如果涉及高速编码器计数,周期就要设得更短,或者用专门的事件任务来应对。配好任务之后,可以在程序末尾写一个输出翻转的小逻辑,用示波器或者端子指示灯观察翻转频率,能直观地感受到扫描周期的存在。
这里有一个关键认知:在大多数周期扫描模型里,程序执行阶段读到的输入值,其实是上一个周期末尾刷新进来的快照。这意味着你的程序看到的IO状态天然存在一个周期的滞后。这种滞后对普通逻辑没问题,但如果你的设备对响应时间很敏感,比如需要快速停机或者捕捉一个短暂脉冲,就必须用沿检测、事件任务或者硬件中断能力来绕开周期滞后问题。
我调试时的一个习惯是:能用沿检测就不用电平判断。例如判断一个按钮被按下,不要在循环里直接读“按下了”这个电平值,而是检测它“从0变成1”的边沿。这样即使按钮被按住好几秒,也只触发一次动作,不会因为CPU扫描周期短而重复触发。用ST写的时候,边沿检测就是保存上一次状态,然后比较当前值和上次值,这在功能块里封装一次,后面调用就很方便了。
5. 常见问题与排查技巧实录:任务、IO、变量与状态全排查
5.1 程序能下载却跑不起来的典型原因
不少新手第一次实操会碰到一个非常诡异的场景:程序编译下载全都正常,CPU却没有输出,甚至直接进入停止状态。遇到这种情况,我的排查顺序是固定的。
第一,查任务配置。程序没有挂到任何任务上,后续一切免谈。这在工程树里一眼就能看出来,程序图标前面的任务引用是空的,它就是一个孤立程序,永远不会被执行。第二,查变量映射。IEC 61131并不强制要求变量名和物理IO地址一致,如果你在程序里写的只是内部变量,而没有把它关联到某个输入通道或输出通道上,那这个变量和物理世界之间没有联系,程序逻辑再正确也没有实际输出。用IDE里的变量交叉引用表,能快速确认每个变量到底有没有和IO地址绑定。第三,查硬件安全回路。很多设备的程序里包含急停和安全门联锁逻辑,如果急停信号被强制为0,程序就会一直处于“安全锁定”状态。不看硬件端子的指示灯和诊断缓冲,光看程序是看不出这个问题的。
这三种情况每次出现都像面板上贴的“程序已下载”一样迷惑人,只要按顺序查,基本能在十分钟内定位。
5.2 在线监视数据与预期不符的排查思路
在线监视是PLC调试最核心的手段。数据不对时,我有一套固定的排查步骤。
先把PLC切换到运行态,看诊断缓冲区有没有报错。如果CPU在STOP,所有监视都是虚的。第二步,确认你要监视的程序确实按照期望的周期在运行,检查任务配置里程序的引用是否还在。第三步,回到数据源头:输入变量是否如实反映了物理信号?这个时候用信号发生器模拟输入信号是最有效的,它能排除现场传感器故障的干扰。第四步,检查中间变量的生命周期。如果某个监视值在预期之外不断丢失,检查它是不是被声明成了VAR_TEMP,或者被某个函数内部的局部变量覆盖了。第五步,检查数据类型范围和字节序,尤其是REAL和DINT之间的转换,以及跨平台通信时整形的高低字节顺序。
这里随便举一个我遇到过的实例:某项目里一段ST代码用REAL做累加,累加到很大数值后,监视值忽然不再上升。排查到最后发现,REAL浮点精度在数值变大后分辨率下降,整数部分代表的最小步进已经大于每次累加的量,所以显示上“卡住不动”。换成LREAL或者改用DINT做定点运算后问题消失。这种问题只有对数据类型的精度边界有概念时,才能快速想到。
5.3 关于移植性、多人协作和版本管理的体会
用IEC 61131体系组织程序的长期收益,是在更换PLC平台时有底气。但我也要说实话:完全无缝移植是不存在的,各家实现总有差异,厂商库和硬件抽象层也不兼容。我长期坚持的做法是把程序架构和硬件访问剥离开:核心逻辑程序只使用输入输出变量作为边界,不直接写死物理地址,所有硬件绑定都放在统一的映射层或者IO配置层里。这样换平台时,主要工作是重做映射层和确认厂商特有功能块的对应关系,核心逻辑几乎原样平移。
多人协作的PLC项目,我特别看重两条纪律:一是全局变量越少越好。能通过功能块的输入输出传递的数据,绝不要用全局变量互相耦合。全局变量一多,程序之间就形成隐形的“蜘蛛网”,改一个地方牵动一片,是最常见的事故源。二是变量命名规则要提前约定。比如输入用I前缀,输出用Q前缀,内部变量用M前缀,功能块实例用功能名字加编号,让所有人看名字就能判断变量的作用和来源。
版本管理这里我也想说一下。很多PLC原厂IDE的工程文件是单文件或者多文件组合,直接扔在共享盘里互相覆盖,是绝大多数项目事故的温床。现在主流IDE基本都支持外部的版本管理工具对接,把工程文件纳入版本管理之后,每次修改都有记录,哪天改坏了还能回溯到昨天的可用版本。我见过太多“这个版本昨天还能跑,今天怎么就不行了”的现场,最后发现是别人不小心覆盖了源文件。版本管理解决的就是这种本不该发生的灾难。
最后分享一点我自己的体会。IEC 61131这套标准真正改变我的用法,不是让我死记硬背五种语言的语法,而是让我明白了PLC程序背后的运行模型和组织方式。最开始我看老工程师写梯形图,只想照着模仿;后来真正理解了扫描周期、任务调度、功能块实例化这些概念之后,再看程序就是在看数据流向和状态变化,思路完全不一样了。如果你现在刚开始接触PLC,我的建议很简单:先别沉迷于某一个品牌的界面操作,尽早把IEC 61131-3的核心软件模型过一遍。哪怕一开始觉得抽象,等你有过现场调试经验之后再回头翻,你会发现每一页都在解释你踩过的坑。