IEC61131标准与PLC编程:五种语言核心解析与实战指南
1. IEC61131标准是什么以及它为什么值得你花时间学如果你跟带控制的设备打过几年交道一定见过这样的场景车间里同时跑着几个不同厂商的控制器每个品牌的编程软件界面千差万别PLC程序写法更是各成一套。在这家学会的梯图逻辑换到另一家的软件里连功能块的名字都对不上。更要命的是一旦控制器故障需要紧急处理资历老的电工师傅对这款设备不熟年轻工程师又只擅长某一种品牌现场排查常常陷入被动。IEC61131标准就是为了终结这种混乱局面而出现的。它是国际电工委员会制定的PLC可编程逻辑控制器及其相关系统的国际标准覆盖了PLC的硬件设计、编程语言、通信协议、测试规范等方方面面。其中大众最常听到、也最直接决定程序怎么写的是第三部分——IEC 61131-3。这一部分定义了五种PLC编程语言包括梯形图LD、功能块图FBD、结构化文本ST、指令表IL和顺序功能图SFC并规定了通用的编程模型、变量类型、程序结构以及执行控制机制。对刚接触PLC的人来说记住一个关键结论IEC61131标准并不是某家厂商的产品说明书而是一套被全球主流控制器共同认可的“通用语法框架”。学会了这套东西你等于掌握了一门跨平台的“普通话”。之后无论用哪个品牌的软件都能迅速找到对应的概念和操作而不是每次都从零攻克一套新的私有逻辑。这篇文章我想用完整的技术拆解方式聊聊这IEC61131标准到底包含哪些内容、五种编程语言各自适合什么场景、PLC程序是怎么一步步跑起来的以及我在实际编程和现场调试中踩过的坑和总结的排查方法。文章的阅读对象是这么几类人刚进入自动化行业、准备接触PLC编程的新人已经会使用某个品牌PLC、想要拓展视野、了解通用标准的电气工程师以及带设备、负责产线维护的现场工程师——你们多半已经碰到过“程序里看得到逻辑但逻辑怎么执行却想不通”的困惑这部分内容尤其值得参考。2. 标准背后的工程困境为什么一定要有IEC611312.1 标准出现前的“PLC方言时代”PLC从上世纪六七十年代诞生以来经过了几十年的发展。早期每个厂家都有自己的指令体系梯形图的画法差别还不算大但是功能指令、数据块定义、子程序调用规则、布尔逻辑的处理方式就完全是“各自为政”了。做过设备改造的人应该深有体会一台老设备用A品牌的PLC你想加两个工位、改一下动作顺序首先得把原来四十多张程序注释打印出来一点一点翻译成B品牌的写法这个过程极其容易出错。那个年代工程师之间流传一个经验跳槽换一家公司如果PLC品牌换了前三个月基本是在重新“学外语”。很多资深的继电器控制师傅本来对电气逻辑非常熟练但因为编程工具的隔阂面对新品牌界面时反而无从下手。这种局面既增加了用人成本也阻碍了自动化设备在不同厂家之间快速迁移和调试。2.2 统一标准的核心设计哲学IEC61131标准的制定者面对的核心矛盾是既要提供足够统一的编程框架又不能让标准僵化到阻碍各家发挥硬件性能。所以他们采用了一种“分层标准化”的思路——标准规范高层逻辑和程序结构把底层物理实现和指令效率的竞争空间留给厂商。拿IEC 61131-3来说它并不规定你必须使用某一种语言而是给出了五种语言每种适合不同的场合。更重要的是它定义了一个完整的编程模型包括程序组织单元POU模型程序、功能块、函数三种基本模块如何划分变量体系全局变量、局部变量、直接表示变量、I/O映射变量怎么声明数据类型的规范从布尔量、整数到字符串、数组、结构体的完整集合执行控制机制任务Task怎样触发程序周期运行多任务优先级如何设定。这套模型的精妙之处在于它把“程序逻辑”和“硬件接线”解耦了。你在程序里写的变量Q0.0或者OUT1可以通过I/O映射表与实际物理端子对应而不是必须在程序里把物理地址写死。这意味着如果你换了设备型号、改了接线端子很多时候只需要改映射关系核心逻辑可以原封不动。很多人在初学PLC时理解成了“接线决定程序”——需要哪个输出线圈得电就去地址表里找对应位。用IEC61131的编程范式来看这个思路已经过时了。现代PLC工程更接近软件开发先定义接口变量、再写逻辑、最后做地址绑定。3. 五套语言一套内核IEC 61131-3编程语言全拆解3.1 梯形图LD电气思维的天然延伸梯形图是绝大多数工程师接触PLC的第一门语言。它的特点是图形化表达左右两条母线相当于电源的正负极中间是触点和线圈电流从左往右流动。学过继电器控制的人几乎可以无缝迁移常开触点对应继电器的常开接点常闭触点对应常闭接点输出线圈对应继电器线圈。梯形图的优势在于直观。现场排查故障时手持显示屏或电脑在线监视一眼就能看出来哪条回路是通的、哪个触点该闭合却被机械卡住导致信号没到位。它的劣势也同样明显复杂算法处理能力差如果程序里有大量数学计算、字符串处理或者复杂的数据排序用梯形图写会非常吃力程序也变得臃肿。我的经验是梯形图最适合用来写设备的主逻辑——电机启停、阀门开关、气缸动作、报警汇总这类以“条件—结果”为主的控制逻辑。它不擅长的事情不要硬塞给它。3.2 功能块图FBD信号看得见、逻辑连得清功能块图比梯形图更接近电子线路图。程序由一个个功能块组成块的输入引脚接收信号块内部完成特定的运算或控制逻辑输出引脚连接到下一个块的输入或者最终连接到物理输出。这种语言在过程控制领域用得非常多比如PID调节、模拟量信号处理、传感器数据校准。把几个功能块连起来一个复杂的信号链路就搭好了——传感器送来的4-20mA电流信号先经过线性变换块再经过滤波块然后进入PID控制器最后输出到变频器给定端。整个过程像搭积木一样清晰排查的时候也很直观顺着连线就能找到异常环节。功能块图另外一个优点是易于封装复用。你可以把一段常用的逻辑封装成一个自定义功能块比如“电机保护逻辑块”然后程序里反复调用。每次调用只需要给输入引脚赋值块的内部逻辑不用再关心——这就是IEC61131提倡的模块化思想。3.3 结构化文本ST会写代码的人看这个最轻松如果你有C语言或者Pascal语言的底子结构化文本几乎是零门槛入手的。ST语言的语法接近高级编程语言用:做赋值用IF...THEN...ELSE做条件分支用CASE做多分支跳转用FOR和WHILE做循环。很多复杂数学计算、通信报文解析、数组批量处理用ST写比用梯形图或少一两倍的代码量。举个例子要计算一组模拟量数据的平均值梯形图可能要写十几个比较和累加指令还要配循环指针读起来费劲ST只要几行就完成了。sum : 0; FOR i : 1 TO 10 DO sum : sum values[i]; END_FOR; average : sum / 10;不只是简洁ST的变量类型定义也更接近通用编程习惯。你可以定义结构体——比如把一台设备的运行时间、故障代码、累计次数打包成一个变量组程序清晰度立刻提升一个档次。我推荐所有PLC编程人员一定要熟练掌握ST原因很简单现在的现场设备越来越复杂做通讯、做配方管理、做数据记录都绕不开高级语言处理。ST是五种语言里最接近现代软件开发的表达方式。3.4 指令表IL最接近硬件的底层语言指令表是一种类似汇编语言的PLC编程语言所有指令都是“操作码操作数”的格式比如LD装载、AND与、OR或、ST存储程序按顺序逐条执行。它是五种语言里最底层的表达形式执行效率最高但可读性最差。目前在实际工程中纯用IL写的程序已经非常少了。更多场景是编程软件在梯形图和IL之间自动切换显示因为IL的底层表达可以把梯形图翻译成一行行指令。碰到老设备、老程序——特别是早期从欧洲进口的设备——IL还是很常见的看懂它对于做设备维护的人来说仍然有价值。如果你做新项目我不建议主动用IL写逻辑。它的体力活收益比太低现代PLC处理速度早就过剩了没必要为了节约几条指令的时间牺牲程序可读性。3.5 顺序功能图SFC流程控制的高效抽象顺序功能图SFC面向的是流程型逻辑比如一条流水线有几个工序每个工序之间有先后顺序和跳转条件。SFC的基本元素是步Step和转换Transition。步表示一个稳定的动作阶段转换代表从当前步进入到下一步的条件。整个流程像一个状态机非常有条理。我用SFC写过一套带烘干工序的流水线控制程序。整个流程分成六个步进料、定位、夹紧、加工、烘干、卸料每步之间的转换条件靠传感器信号和定时器完成。程序写完之后现场调试人员看着SFC图就能明白设备现在处于哪个环节、下一步要满足什么条件才能动作比纯看几十段梯图轻松太多了。SFC的注意事项是——不要试图把所有逻辑都塞进步里。一个步内部适合放一组并发的输出动作和对应的条件判断但不适合放过于复杂的计算逻辑。核心流程用SFC组织细节计算用ST主逻辑再用梯形图解耦这种混合使用才是实际项目中最舒服的方式。3.6 我的语言选型建议接触到的项目越多越能体会到“用对工具”比“炫耀工具”重要。我个人的实战配比大概是主流程控制用梯形图或SFC复杂数据处理用ST模拟量链路和信号调理用FBDIL基本不主动用只在排查老程序时阅读。具体可以参考这个表格语言类型核心优势主要弱点推荐应用场景LD 梯形图直观、易排查、电气背景友好复杂计算表现差主逻辑、互锁、报警FBD 功能块图连线清晰、信号流可追踪逻辑链路过长时难阅读模拟量处理、PID控制ST 结构化文本表达能力强、开发效率高对纯电气背景人员不够友好算法、通讯、数据处理IL 指令表底层执行效率高可读性差、开发慢老设备维护、指令级排查SFC 顺序功能图流程可视化、状态机清晰步内部不适合复杂逻辑工序类、流程类控制4. 核心原理PLC程序到底怎么“跑”起来的4.1 扫描周期一种“无限循环”的工作方式PLC的工作原理和电脑上运行的软件差别很大。电脑上的程序是事件驱动的——点击一个按钮相关代码执行一次然后等待下一个事件。PLC则采用“周期扫描”的工作方式上电之后它永远在重复执行同一个大循环读取输入信号 → 执行用户程序 → 刷新输出信号。这个循环的三个阶段分别对应过程映像区输入、用户程序存储区、输出映像区的操作。先读一遍输入端子的电平状态记录到内存然后程序里的每一个指令基于这个内存数据做逻辑运算运算结果写进输出映像寄存器最后统一把输出映像的内容赋值给物理输出端子。这里有一个很多新手容易犯的误解以为程序执行过程中PLC会实时响应输入的跳变。实际上在同一个扫描周期内所有输入信号在扫描开始时已经“拍快照”了程序里后续的操作看到的都是这个快照而不是实时波形。这意味着如果输入在程序执行到一半的时候发生变化那也要等到下一个扫描周期的读输入阶段才会被程序感知。4.2 扫描周期不稳定的隐患一个完整的扫描周期除了用户程序还包括系统自诊断、通信处理等步骤。程序越复杂扫描周期越长。工业控制里对扫描周期有硬性要求——比如安全联锁逻辑的响应时间必须在毫秒级如果程序里塞了大段的数据通信处理扫描周期可能被拖到几十毫秒那安全逻辑的响应就来不及了。解决思路是把任务划分优先级。IEC 61131-3的标准模型里提供了多任务机制你可以把安全联锁逻辑放到高优先级任务里让它以5ms的周期独立运行把通信处理放到低优先级任务里放宽它的执行周期——即使通信慢了几十毫秒也不影响核心的安全逻辑响应。4.3 程序组织单元POU怎么划分IEC 61131-3把程序代码划分为三种POU函数Function、功能块Function Block和程序Program。函数没有内部状态同样的输入永远给出同样的输出比如加法、取绝对值、比较大小。你可以理解成一把计算器按同一个数字组合永远得到同一个结果。功能块有内部状态同一个输入在不同时刻进入输出可能不同。最典型的就是定时器TON功能块——给一个持续5秒的输入信号你在第2秒看它的输出和第4秒看输出结果完全不同因为它内部记录着计时累积值。程序是若干个函数和功能块的组合负责具体关联到输入输出映射。实际编程时我的习惯是把重复使用的算法封装成函数把设备级的控制逻辑封装成功能块比如一个“气缸控制FB”内部管理气缸伸出、缩回、到位检测、超时报警然后在程序里把这些功能块实例化、连接I/O信号。这个思路推广到整个设备——程序就变成了“由多个功能块实例协作组成的大系统”清晰度比在梯图里揉在一起的写法强得多。5. 实操第一步从零构建一个符合IEC61131的PLC程序5.1 场景设定与I/O规划用一个最常见的场景来完整走一遍流程一套电机启停控制带有启动按钮、停止按钮、热继电器保护触点同时要求电机运行累计达到设定时间后自动停机报警。这种控制是每家电工班都会遇到的它的改造版本会出现在各种实际设备里。先做I/O规划。这一步看似简单却是整个项目中最容易返工的地方。信号类型名称地址/变量方向说明输入启动按钮START_BTN数字量输入常开按下导通输入停止按钮STOP_BTN数字量输入常闭按下断开输入热继电器THERMAL_OK数字量输入常闭正常时导通输出接触器线圈MOTOR_RUN数字量输出控制电机主回路输出报警指示灯TIMEOUT_LAMP数字量输出超时指示这里有一个经验要提醒停止按钮接入PLC时尽量采用常闭触点程序中用常开读取。为什么因为如果停止按钮的接线断了或者外部线路被碰掉程序读到的是断开信号系统会立刻判定为“停止请求”从而实现失效安全fail-safe。反过来如果用常开做停止按钮线路断了程序根本不知道设备就会在失去急停能力的情况下继续运行——这是非常危险的事。5.2 变量声明与程序骨架按IEC 61131-3的规范变量需要用关键字显式声明。放在程序开头的是变量声明区我们在编辑器里写VAR START_BTN : BOOL; // 启动按钮 STOP_BTN : BOOL; // 停止按钮 THERMAL_OK : BOOL; // 热继电器正常信号 MOTOR_RUN : BOOL; // 电机运行输出 TIMEOUT_LAMP: BOOL; // 超时报警灯 RUN_TIMER : TON; // 运行计时器 RUN_LIMIT : TIME : T#30M; // 允许最长运行时间30分钟 END_VAR这里注意两个细节第一TON是一个功能块类型的变量使用前必须实例化第二TIME类型的时间数值直接支持分钟的单位写法这比用秒数换算要直观得多IEC61131在处理工程时间量上的贴心之处。很多新手会用整数加一个“单位注释”来表示时间一旦注释跟不上修改就很容易把30分钟写成3000秒甚至30秒酿成事故。直接用TIME类型可以完全避免这种单位换算失误。5.3 主逻辑梯形图解读主体逻辑用梯形图实现。可以这样梳理逻辑链路第一行自锁回路启动按钮闭合后线圈MOTOR_RUN得电MOTOR_RUN的常开触点并联在启动按钮两端形成自锁。这样松开启动按钮电机仍然继续运行。第二行停止与保护停止按钮、热继电器都串接在这个回路里任意一个断开线圈失电。这里体现了“串联即与、并联即或”的继电器逻辑。第三行定时与报警MOTOR_RUN作为定时器TON的使能输入它的计时输出Q在达到设定时间后置位用计时输出Q驱动报警灯同时将Q取反后串入主回路实现超时自动断开。在梯形图软件里完整的连线看起来像这样逻辑结构示意启动按钮START_BTN ——| MOTOR_RUN自锁触点 ——| 停止按钮STOP_BTN ——| 热继电器THERMAL_OK ——( MOTOR_RUN线圈 ) | —— |TIMEOUT_Q取反| ——这里的重点是理解“取反”在梯形图里的表达方式——一个常闭触点就是取反。定时器计时到后它的输出Q为TRUE取反后变为FALSE相当于在主回路上断开一个常闭触点电机自然停止。这种设计比额外用一条“定时到—停止线圈”的指令更可靠因为它把安全条件直接嵌进了导通回路不依赖程序执行的先后顺序。5.4 为什么有时需要用ST重构这段逻辑上面这套梯形图逻辑非常适合给电工师傅看调试方便但如果你需要把“累计运行30分钟”升级成“分阶段累计、每个阶段按配方不同设定时间、还要求把最近5次运行时长记入历史”梯形图就非常吃力了。这时用ST重构是更好的选择。// 伪代码示例配方阶段运行控制 CASE current_step OF 1: // 阶段1运行直到位置信号到位或超时 IF RUN_TIMER.Q THEN step_timeout : TRUE; END_IF; 2: // 阶段2等待人工确认 IF CONFIRM_BTN THEN current_step : 3; END_IF; END_CASE;ST的表达能力优势在这种“非纯开关逻辑”的场景里就体现出来了。它可以写数组、循环、枚举、结构体、字符串处理而这些在梯形图里要么极难表达要么根本不可能。实践建议是同一个项目里核心设备联锁用梯形图数据管理和配方用ST流程调度用SFC互相配合。不要为了“统一”而强行用一种语言写所有逻辑那样反而会增加维护难度。6. 数据类型、任务配置与调试排查的实战经验6.1 数据类型的坑与I/O映射的讲究IEC61131的数据类型体系覆盖了从BIT1位到LREAL64位浮点的完整层次。常用的有BOOL、BYTE、WORD、DWORD、LWORD、SINT、INT、DINT、LINT、REAL、LREAL、STRING、TIME、DATE等。看起来简单工程上却经常有人掉坑。最常见的坑是隐式类型转换。很多PLC编程软件在默认情况下允许INT和REAL混用但标准严格区分这两者。你写一个赋值语句REAL_VAR : INT_VAR在允许隐式转换的环境里它悄悄转成了浮点数看似一切正常但如果INT_VAR的值超过2^24浮点的精度会丢失数值就不再精确了。正确的写法是用转换函数REAL_VAR : INT_TO_REAL(INT_VAR)。类型转换虽然啰嗦但明确了意图避免了隐藏的错误。I/O映射方面IEC 61131-3标准建议将物理I/O和逻辑变量解耦。程序里不要直接用%I0.0这种直接地址而是先做变量映射。比如把物理输入%IX0.0映射到内部变量START_BTN再在程序里只用START_BTN。如果你的设备重新分配了端子只需要改映射表上的地址程序逻辑不用动。这种习惯在项目后期改线、换柜时能节省大量的排查时间。6.2 任务配置与扫描周期设置的权衡PLC编程软件里通常能设置多个任务比如“快速任务”“慢速任务”“事件任务”“自由运行任务”。快速任务执行时间短、优先级高适合处理高速计数、安全联锁等慢速任务适合执行耗时较长的通讯处理、配方管理等。我调过的一个设备上为了做一个大量的数组平均值计算把所有逻辑都塞在同一个任务里。结果本来5ms的扫描周期被拖到了接近15ms一个高速气缸动作的时序出现了明显的不稳定。最后把计算移到慢速任务每50ms执行一次快速任务恢复到了5ms问题消失。任务是一种资源分配手段不是为了好看而配置的。注意一点跨任务访问变量时要关注数据一致性。快速任务读到慢速任务正在写入的变量时可能读到半更新的中间值。解决方法是使用标准提供的全局变量同步机制或者避免多任务同时写同一个变量。6.3 调试时最磨人的几个问题调试IEC61131风格的程序时我总结了一些高频率出现的故障模式。第一个是“程序下载了但设备没反应”。排查顺序是先看PLC是否处于运行RUN状态再看看输入模块上的指示灯是不是真的亮了然后用在线监视看变量的状态。很多情况下输入信号已经到模块了但程序里对应的变量始终是FALSE那多半是I/O映射没有建立或者变量绑定到了错误的地址。不要一上来就怀疑程序逻辑先确认数据从“物理世界”到“程序变量”这第一步是否走通。第二个是“输出有值了但设备不动作”。程序监视里变量已经是TRUE继电器却不吸合。这种要查输出模块的通道接线、保险丝和供电电源。常见的坑是漏接输出模块的公共端COM信号回路断掉程序“看起来”是对的但电流根本流不出去。用万用表从模块输出端往后测量一步一步就可以定位了比反复修改程序高效得多。第三个是定时器不准确。很多人定时器明明设了5秒实际却要等更久才动作。原因是定时器在一个扫描周期内只能累积一次时间增量如果定时器的使能条件不是每个扫描周期都持续为TRUE——比如使能信号本身是脉冲——计时就会断断续续。改为持续使能信号或者使用累积定时器RTON来累计非连续的运行时间。6.4 排查工具与现场经验用在线监视替代“盲改盲试”。几乎所有的现代编程软件都支持将变量做成监视表单实时查看布尔量和数值变量的变化还能强制输入输出。我调试时的习惯是把所有关键信号放进一张监视表启动条件、停止条件、保护信号、运行状态、故障代码。任何一步不满足都能一眼定位。另外一个非常实用的功能是强制Force。当设备处于停机状态、确认安全的前提下可以强制一个输入变量为TRUE模拟按钮按下的效果验证程序分支是否正确响应。但强制有两件事必须牢记调试完必须解除所有强制否则设备会带病运行强制只应该在安全环境中使用绝不允许在带载运行时乱动输出强制否则机械设备可能突然动作造成事故。6.5 程序备份与版本管理这一点被很多小团队的工程忽视。一个项目迭代了十几次之后“程序V8_最终版”和“程序V8_真最终版”并存的情况实在太常见了。等现场出问题需要回滚到上一版本分不清哪个是哪个风险极高。我现在的做法是每个阶段修改前先导出一次程序源文件文件名带日期和修改内容摘要放在统一目录下生产设备上的程序固化后再从PLC里上载一份存档。这不能依赖记忆否则半年以后谁也说不清楚。还有一个相关的小技巧调试完毕带上PLC的上传功能做“在线比对”确认正在生产程序与你电脑上的工程文件完全一致再退出调试模式。有些老设备被人临时改过但没留工程文件现场最怕遇到这种“程序对了但工程对不上”的状况。7. 一些我对IEC61131的个人体会和扩展建议聊到最后说点我在实操中的感受。IEC61131标准最有价值的地方并不是五种语言或者那些语法细节而是它给整个工业自动化领域带来了一种“工程化思维”——把编程从“电工配线”的范畴提升到了“软件开发”的范畴。学这门标准本质上是在学一种结构化的、面向逻辑与状态建模的方法。我这些年接触了不少PLC工程师深深地感到传统“抄梯图”式的学习方式越来越跟不上设备迭代的速度了。一台标准设备七八年不换逻辑的时代已经过去现在的新设备动不动就带几十个配方、上百个报警、还要对接MES系统。只会画继电器回路谈不上是扎实的自动化工程师能把自己的思路用清晰的POU结构表达出来、让下一位接手的人半小时内看懂程序框架这才是真正值钱的能力。所以我对新人的建议是一开始先好好练梯形图把继电器逻辑、自锁互锁这些基本功练扎实接着把ST语言练熟这会是你以后做复杂逻辑的底气再回头用标准的结构重新整理自己的程序——变量怎么命名、功能块怎么划分、I/O怎么映射。这三步走完不管换什么品牌的PLC你都能在很短的时间内适应。后续可以怎么扩展呢有两条线值得深入。一条是朝运动控制和过程控制方向走把IEC61131与伺服控制、PID整定的知识结合起来深入到具体工艺中去另一条是朝信息化方向走学习OPC UA这类通信标准把PLC的数据和设备上层系统对接起来。底层逻辑通了上层怎么搭都不会慌。最后再分享一个多年的习惯每次在现场处理完一个故障我都会在项目文件的备注里写一段几十字的总结——根因是什么、用了什么方法定位、怎么避免再犯。这些零散的记录积累起来比很多教材都管用。自动化这个行当经验是最难复制的东西但用自己的方法把经验固化成文档是每个工程师都能做到的。希望这篇关于IEC61131标准与PLC编程基础的梳理也能成为你经验库里有价值的一块。