IEC 61131标准详解:PLC编程语言、软件模型与实战排查

发布时间:2026/10/19 0:59:26
IEC 61131标准详解:PLC编程语言、软件模型与实战排查 用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之后的行为在不同厂家实现里可能不一样有的回绕到负数有的直接报错。所以涉及大范围计数或者累加的变量我一般直接上DINT32位安全得多。变量声明方面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的核心软件模型过一遍。哪怕一开始觉得抽象等你有过现场调试经验之后再回头翻你会发现每一页都在解释你踩过的坑。