IEC 61131-3 编程标准实战:五种语言选型、POU 设计与跨品牌移植经验
发布时间:2026/10/25 0:40:22 锦皓数字建站

1. 从继电器柜到软逻辑IEC 61131到底解决了谁的痛点刚入行那会儿我接手过一个老产线的改造项目。电气柜里密密麻麻的继电器、时间继电器、计数器接线端子排长得像蜈蚣排查一个故障得拿着图纸一根线一根线地量。老师傅跟我说这套逻辑要是用PLC重写半天就能搞定。那时候我才真正意识到IEC 61131标准存在的意义不是给编程添规矩而是把工业控制逻辑从“硬件接线”的泥潭里拽出来变成可复用、可移植、可维护的软件资产。很多人第一次接触PLC编程脑子里蹦出来的问题是“我该学西门子还是三菱”。但真正该先问的是这套控制逻辑换一个品牌的PLC还能不能跑IEC 61131就是回答这个问题的。它是国际电工委员会制定的可编程控制器编程语言标准把PLC的编程语言、数据类型、程序组织单元、通信接口等做了一套统一的约定。你可以把它理解成工业控制领域的“普通话”——不管你是哪个厂家的人说普通话大家都能听懂。这套标准最早在1993年发布后来经过多次修订目前主流参考的是第二版和第三版的内容。它定义了五种编程语言规定了变量声明方式还引入了程序组织单元POU的概念。说白了它想让PLC程序像高级语言一样有函数、有结构体、有命名空间而不是一堆散乱的梯形图网络堆在一起。那这套标准具体适合谁来学我的判断是三类人一是刚入行的电气自动化工程师需要建立正确的编程思维框架二是从传统继电器控制转过来的老师傅需要理解“软逻辑”和“硬接线”的本质区别三是做设备出口的团队因为海外客户经常要求程序符合IEC 61131-3的规范方便后期维护和二次开发。接下来我会从标准的核心架构讲起把五种编程语言、数据类型、POU组织方式逐一拆开再结合我实际项目中踩过的坑聊聊怎么从零搭建一个符合标准思维的程序框架。文章会涉及具体代码示例和配置思路但不会绑定某个特定品牌的软件因为标准本身是跨平台的。2. 五种编程语言不是让你全学而是让你会选IEC 61131-3定义了五种编程语言很多人一看就懵了难道我要把五种都学会其实不是。这五种语言的设计初衷是针对不同的应用场景和不同的工程师背景你可以根据项目特点和个人习惯来选择。我见过只用梯形图走天下的老工程师也见过全程用结构化文本写复杂算法的年轻人两种做法都没问题关键是选对场景。2.1 梯形图LD电气工程师的母语梯形图是PLC编程里最直观的语言它的符号体系直接继承自继电器控制电路。常开触点、常闭触点、线圈、定时器、计数器这些元素在梯形图里的画法和电气原理图几乎一一对应。对于从继电器控制转过来的工程师来说梯形图几乎没有学习门槛——你以前怎么画电路图现在就怎么画梯形图。但梯形图有个明显的短板处理复杂逻辑和数学运算时非常吃力。比如你要做一个PID控制算法或者对一组数据做排序用梯形图写出来会像蜘蛛网一样可读性极差。我个人的经验是梯形图适合写开关量逻辑、互锁关系、设备启停顺序控制这些场景下它的直观性是其他语言比不了的。提示梯形图里尽量一个网络只做一件事不要在一个网络里塞太多并联和串联分支。后期排查故障时网络越简洁定位越快。2.2 结构化文本ST复杂算法的首选结构化文本的语法类似Pascal和C有IF-THEN-ELSE、CASE、FOR、WHILE这些控制结构支持数组、结构体、函数调用。如果你写过任何一门高级语言上手ST会非常快。我在做运动控制、过程控制、数据处理这类项目时基本都用ST来写核心算法。ST的优势在于表达能力强、代码紧凑。同样一个冒泡排序梯形图可能要画几十个网络ST几行就搞定了。但ST的缺点是调试时不如梯形图直观变量之间的依赖关系需要靠阅读代码来理解。所以我的习惯是用ST写功能块内部逻辑用梯形图做顶层调用和状态监控两者结合使用。FUNCTION_BLOCK FB_MotorControl VAR_INPUT Start : BOOL; Stop : BOOL; Fault : BOOL; END_VAR VAR_OUTPUT Run : BOOL; END_VAR VAR State : INT : 0; END_VAR CASE State OF 0: // 停止状态 IF Start AND NOT Fault THEN State : 1; END_IF; 1: // 运行状态 Run : TRUE; IF Stop OR Fault THEN State : 0; END_IF; END_CASE;上面这段代码展示了一个简单的电机控制功能块用CASE语句实现状态机。这种写法在ST里非常自然换成梯形图就会很别扭。2.3 功能块图FBD信号流一目了然功能块图用方块表示功能块用连线表示信号流向。它特别适合过程控制领域因为过程控制里大量使用PID、滤波、标定、报警这些标准功能块用FBD连起来就像画信号流图一样清晰。很多DCS系统就是基于FBD的编程思路。FBD的局限性在于它不太适合表达复杂的条件分支和循环逻辑。你很难用FBD画出一个带嵌套判断的算法。所以FBD通常和ST配合使用FBD做顶层信号流ST写底层功能块。2.4 顺序功能图SFC流程控制的利器顺序功能图是专门为顺序控制设计的语言。它把控制过程分解成一个个“步”Step步与步之间用“转换”Transition连接每个步里可以挂动作Action。这种编程方式特别适合包装机械、装配线、注塑机这类有明显工序划分的设备。SFC最大的好处是逻辑清晰、易于调试。设备卡在哪个步一眼就能看出来。而且SFC天然支持并行分支和选择分支可以表达复杂的工序跳转。我做过一个多工位装配设备用SFC写主流程每个步里调用ST写的功能块整个程序结构非常清爽。2.5 指令表IL正在被淘汰的“汇编语言”指令表是一种低级语言类似汇编用操作码和操作数逐条写指令。它是最早的PLC编程语言之一但现在新项目里已经很少用了。IEC 61131-3第三版已经把IL列为“逐步淘汰”的语言。我的建议是了解即可不必深学。除非你维护的是十几年前的老设备否则没必要花时间在IL上。语言最适合场景学习难度我的使用频率梯形图LD开关量逻辑、互锁、启停控制低高结构化文本ST算法、数据处理、状态机中高功能块图FBD过程控制、信号流低中顺序功能图SFC顺序流程、工序控制中中指令表IL老设备维护高极低这张表是我个人经验的总结不是标准的规定。标准只是定义了这五种语言并没有规定你必须用哪一种。实际项目中混合使用多种语言才是常态。3. 数据类型和变量作用域程序稳定的地基很多人写PLC程序变量命名随手就来M0.0、M0.1、V100、V101程序写完自己都记不住哪个变量是干什么的。这种习惯在小项目里还能凑合一旦程序规模上去维护成本会指数级上升。IEC 61131-3对数据类型和变量作用域有明确的规定用好这些规定程序的可读性和稳定性会提升一个档次。3.1 基本数据类型别再用WORD走天下了IEC 61131-3定义了一套标准的数据类型包括布尔型BOOL、整型SINT/INT/DINT/LINT、无符号整型USINT/UINT/UDINT/ULINT、浮点型REAL/LREAL、字节和字BYTE/WORD/DWORD/LWORD、字符串STRING/WSTRING、时间TIME/DATE/TOD/DT等。我见过很多老程序所有数值都用WORD或INT温度用INT计数用INT连布尔标志也用INT的0和1表示。这种写法在早期PLC内存紧张的时候可以理解但现在完全没必要。用对数据类型好处有三个一是编译器能帮你做类型检查减少隐式转换的bug二是代码可读性更好看到REAL就知道是模拟量看到BOOL就知道是开关量三是不同品牌PLC之间移植时标准数据类型兼容性更好。注意REAL是32位浮点数精度有限。做累计流量、高精度位置计算时要考虑用LREAL64位或者改用整数运算避免精度损失。我曾经在一个累计流量项目里用REAL累加跑了三天后发现累计值偏差了0.5%后来改成DINT按最小单位累加才解决。3.2 派生数据类型结构体和数组让程序有“骨架”除了基本类型IEC 61131-3还支持派生数据类型最常用的就是结构体STRUCT和数组ARRAY。结构体可以把一组相关的变量打包成一个整体。比如你要描述一台电机的状态可以定义一个MotorType结构体里面包含运行状态、故障状态、电流、转速、运行时间等成员。这样你在程序里传递电机数据时只需要传一个结构体变量而不是五六个分散的变量。TYPE MotorType : STRUCT Run : BOOL; Fault : BOOL; Current : REAL; Speed : REAL; RunHours : DINT; END_STRUCT END_TYPE数组则适合处理批量数据比如多工位设备的工位状态、多路温度采集值等。数组可以和FOR循环配合用几行代码处理几十路信号比梯形图里一个个网络画过去效率高得多。3.3 变量作用域全局变量是万恶之源IEC 61131-3把变量分为局部变量和全局变量。局部变量在POU内部声明只在该POU内可见全局变量在所有POU中都可以访问。我的经验是全局变量越少越好。全局变量多了程序里任何一个地方都可能修改它出了问题很难定位。正确的做法是功能块内部用局部变量功能块之间通过输入输出接口传递数据。这样每个功能块就像一个黑盒子你只需要关心它的输入和输出不需要关心它内部怎么实现。变量类型声明位置可见范围我的使用建议局部变量POU内部仅本POU优先使用全局变量全局变量表所有POU仅用于系统级配置输入输出变量POU接口调用者可见功能块间通信临时变量POU内部仅本POU不保持循环计数等这张表的核心思想是封装。把变化限制在功能块内部功能块之间的接口保持稳定整个程序的可维护性就会好很多。4. 程序组织单元把程序拆成积木而不是揉成面团IEC 61131-3把程序组织单元POU分为三种程序Program、功能块Function Block、函数Function。这三种POU的区别决定了你写的代码是“一次性消耗品”还是“可复用资产”。4.1 程序、功能块、函数的本质区别程序是最高层的POU相当于整个控制程序的入口。一个PLC项目通常有一个主程序主程序里调用各种功能块和函数。程序可以访问全局变量也可以有局部变量。功能块是带记忆的POU。它有输入和输出内部有静态变量调用一次执行一次但内部状态会保持到下一次调用。比如一个定时器功能块你调用它的时候传入使能信号和设定时间它会记住当前计时值下次调用时继续累加。功能块是PLC编程里最核心的复用单元。函数是不带记忆的POU。同样的输入永远得到同样的输出内部没有静态变量。比如一个计算平均值的函数传入数组返回平均值调用多少次结果都一样。函数适合做纯计算不适合做状态控制。POU类型是否有记忆能否调用功能块典型用途程序有能主控流程功能块有能设备控制、状态机函数无不能数学计算、类型转换这张表里最关键的一条是函数不能调用功能块。因为函数没有记忆而功能块需要记忆两者在语义上冲突。很多初学者在这里踩坑写了一个函数里面想调用一个定时器功能块编译器直接报错。4.2 功能块的设计原则高内聚、低耦合我写功能块有一个习惯一个功能块只做一件事。比如电机控制功能块就只管电机的启停和故障处理不要在里面掺入报警输出、数据记录这些杂七杂八的逻辑。报警和数据记录应该由上层程序或者专门的功能块来处理。这样做的好处是功能块可以复用。今天做A项目用这个电机控制功能块明天做B项目还能用只需要改一下输入输出映射就行。如果功能块里掺了太多业务逻辑换一个项目就得大改复用价值就没了。功能块的接口设计也有讲究。输入变量尽量用标准数据类型不要用自定义的结构体作为输入除非这个结构体是通用的。输出变量要明确不要通过全局变量往外传数据。我见过一个功能块内部直接修改了十几个全局变量调用者根本不知道它会改哪些变量这种功能块就是“定时炸弹”。4.3 程序组织单元的实际项目结构以一个典型的设备控制项目为例我的程序结构通常是这样组织的主程序Program负责模式选择、急停处理、设备整体使能。设备控制功能块FB每个设备一个功能块比如电机、气缸、加热器。工艺功能块FB实现具体的工艺逻辑比如温度PID、位置控制。工具函数Function做单位转换、数据滤波、报警判断。通信功能块FB处理与上位机、其他PLC的数据交换。这种分层结构的好处是每一层只关心自己的职责。主程序不关心电机怎么控制只关心什么时候调用电机功能块电机功能块不关心工艺怎么走只关心自己有没有故障。出了问题先定位是哪一层的问题再深入排查效率比一锅粥的程序高得多。5. 从标准到落地我踩过的坑和总结的经验标准读起来是一回事实际用起来是另一回事。IEC 61131-3给了你一套框架但具体怎么落地每个项目都有不同的答案。下面这几个坑是我在实际项目中真实踩过的分享出来希望能帮你少走弯路。5.1 变量命名别让三个月后的自己骂现在的你我刚工作时写程序变量名都是M0、M1、V100、V101当时觉得省事。三个月后设备出故障我拿着程序排查完全想不起来M37是干什么的。后来我强制自己用有意义的命名比如Conveyor1_RunCmd、TankLevel_HighAlarm、Motor2_Fault。虽然打字多了一点但排查故障时省下的时间远远超过打字的时间。IEC 61131-3没有规定命名规则但大多数编程环境支持长变量名。我的建议是采用匈牙利命名法加驼峰命名的组合前缀表示数据类型或用途后面用驼峰表示具体含义。比如bMotorRun表示布尔型电机运行信号rTankLevel表示实型罐体液位fbPID表示功能块实例。这样一眼就能看出变量的类型和用途。5.2 状态机比一堆IF-ELSE靠谱得多很多初学者写顺序控制喜欢用一堆IF-ELSE嵌套。设备有五个步骤就写五层IF-ELSE。这种写法在步骤少的时候还能看步骤一多就变成“箭头型代码”缩进深得屏幕都放不下。我的做法是用CASE语句写状态机。把设备的每个步骤定义成一个状态编号用CASE根据当前状态执行对应的动作动作完成后切换到下一个状态。这种写法结构清晰每个状态做什么一目了然增加步骤也只需要加一个CASE分支。CASE Step OF 0: // 等待启动 IF Start THEN Step : 10; END_IF; 10: // 气缸伸出 Cylinder_Extend : TRUE; IF Cylinder_Extended THEN Step : 20; END_IF; 20: // 延时 IF Timer_Done THEN Step : 30; END_IF; 30: // 气缸缩回 Cylinder_Extend : FALSE; IF Cylinder_Retracted THEN Step : 0; END_IF; END_CASE;这种状态机写法在ST里非常自然在梯形图里也可以用步进指令实现。关键是把状态和动作分离状态决定当前该做什么动作只负责执行。5.3 模拟量处理滤波和标定不能省模拟量输入是PLC编程里最容易出问题的地方。传感器信号有噪声直接拿来用会导致控制抖动。我见过一个温度控制项目热电偶信号没做滤波温度值在设定值附近来回跳加热器频繁启停接触器几个月就坏了。我的标准做法是模拟量输入先做滤波再做标定最后做报警判断。滤波用一阶低通或者滑动平均标定把原始值转换成工程单位报警判断用标定后的值。这三步缺一不可。滤波参数的选择要看信号特性。温度信号变化慢滤波时间可以长一点比如10秒压力信号变化快滤波时间要短比如0.5秒。滤波时间太长会导致响应滞后太短又起不到滤波效果。我通常会在调试时用趋势图观察找到一个既能滤掉噪声又不影响响应的平衡点。5.4 程序版本管理别再用“最终版”“最终版2”了PLC程序也需要版本管理。我见过太多工程师用“程序_最终版”“程序_最终版2”“程序_最终版_改”这样的文件名最后自己都分不清哪个是最新的。我的做法是每次下载到PLC的程序都导出一份存档文件名包含日期和版本号。比如20250115_v1.3_产线A。同时在程序里加一个版本变量HMI上可以查看当前运行的版本号。这样现场出问题时能快速确认PLC里跑的是哪个版本和存档对比就能知道有没有被改过。如果团队有条件可以用Git或者SVN做版本管理。PLC程序虽然是二进制文件但很多编程环境支持导出为XML或文本格式这样就可以用版本管理工具跟踪变更了。5.5 跨品牌移植标准是底线但不是万能药IEC 61131-3的目标之一是提高程序的可移植性但实际项目中跨品牌移植远没有标准说的那么轻松。不同厂家对标准的实现有差异比如数据类型名称可能不同功能块的接口可能不一样编译器的扩展语法也各有各的玩法。我的经验是核心算法用标准ST写硬件相关部分用厂家专用功能。比如PID算法、状态机、数据处理这些逻辑用标准ST写移植时基本不用改。但硬件配置、通信设置、特殊模块读写这些每个厂家都不一样移植时肯定要重写。所以移植前要先评估工作量别指望一键迁移。移植内容可移植性注意事项标准ST算法高注意数据类型名称差异梯形图逻辑中指令符号可能不同硬件配置低必须重写通信设置低协议实现有差异HMI画面低通常绑定厂家这张表是我多次移植项目后的经验总结。核心思想是把可移植的部分和不可移植的部分分开可移植的用标准写不可移植的用厂家专用功能封装起来换平台时只需要重写封装层。6. 给不同阶段工程师的学习路径建议IEC 61131-3的内容很多一口气全学完不现实。根据我自己的学习经历和带新人的经验不同阶段的工程师应该有不同的侧重点。刚入行的新手先把梯形图和基本指令学扎实。梯形图是PLC编程的基础开关量逻辑、定时器、计数器这些必须熟练。同时要理解扫描周期、输入输出刷新、变量作用域这些基本概念。这个阶段不要急着学ST和SFC先把梯形图写顺了再说。有一两年经验的工程师开始学结构化文本和功能块设计。ST能帮你处理梯形图搞不定的复杂逻辑功能块能帮你把代码组织成可复用的模块。这个阶段要多看别人写的功能块学习接口设计和状态机写法。同时要养成好的命名习惯和注释习惯。有三到五年经验的工程师重点研究程序架构和标准化。怎么分层、怎么解耦、怎么设计可复用的功能块库这些是区分普通工程师和高级工程师的关键。这个阶段可以研究一下IEC 61131-3第三版的新特性比如面向对象编程的扩展虽然很多PLC平台还不支持但了解一下没坏处。带团队的工程师要建立团队的编程规范和代码审查机制。变量命名规则、功能块接口标准、版本管理流程这些看起来是小事但团队规模上去之后没有规范会乱成一锅粥。我见过一个团队五个人写同一个项目变量命名五花八门最后整合的时候花了整整一周时间改名字。最后说一个我自己的体会标准是死的项目是活的。IEC 61131-3给了你一套工具但怎么用取决于你的项目需求和团队习惯。不要为了“符合标准”而把程序写得复杂无比也不要因为“以前都这么写”而拒绝新的方法。找到适合自己团队的平衡点才是最重要的。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。