
只要在用三菱PLC做产线设备早晚会撞上一堵墙梯形图越拼越长一个设备的动作逻辑散落在几十个线圈和触点里改一处报警要连查三条线现场调试时旁边人一催手一抖还可能把旧程序覆盖。我并不是反对梯形图——它做单机小逻辑确实直白可到了多工位、多模式、多报警的产线级别没有结构化编程的思维没有一套顺手可调用的ST语言库效率差距会以肉眼可见的速度拉开。这篇文章就聊三菱PLC平台上的ST语言库怎么搭、怎么用、怎么把重复劳动压缩到最小给正在从梯形图往结构化语言迁移的工程师做参考。先说结论ST语言库这种“秘密武器”并不神秘它就是把常用的算法、设备控制、报警延时这类高频逻辑封装成可复用的函数块让新项目里不再重写一遍。接下来我会从建库思路写起讲到压力控制这类实战场景最后把HMI映射和版本管理的坑也一并交代清楚。1. 为什么说ST库才是结构化编程的关键1.1 梯形图的三个天花板如果把一个只有二十个输入输出的单机设备交给梯形图问题不大但同样是二十个点加上手动、自动、急停、复位、报警、多速运行梯形图就开始变得难看。我在多台设备上见过同一种局面工程师把一套标准动作逻辑复制了十几份每份只改了编号然后程序里到处是M100、M101这类中间继电器交叉引用一开几百条搜索结果。梯形图的第一个天花板是复用难。一段设备保护逻辑换个电机就要全选、复制、改地址稍不留神漏改一个触点现场就是一次事故。第二个天花板是复杂运算表达弱。浮点运算、数组、结构体、循环、逐位校验这些逻辑用梯形图写不仅长而且几乎无法阅读别人接手时只能靠猜。第三个天花板是增量修改困难。程序块之间通过全局软元件互相咬合想为一个报警增加两秒延时得同时改起保停电路和定时器逻辑牵一发而动全身。1.2 ST语言库解决的不是“写代码”问题而是“改代码”问题梯形图的软肋恰恰是ST语言库的长处。ST结构化文本Structured Text是IEC 61131-3定义的文本化编程语言和三菱早期那种指令表不同它支持变量声明、IF/CASE/FOR、函数和函数块能把“一段固定的处理流程”封装成一个带输入输出的黑盒。这里最关键的词是“库”。库的本质是把“会变的东西”和“不变的东西”分开一个模拟量滤波算法是不变的通道地址、量程、滤波强度是会变的一个报警延时判定流程是不变的报警触发点、延时时间、复位条件是会变的。封装成函数块后项目代码变成一行行调用而不是一页页梯形图。所以我才说ST语言库解决的不是“写代码”问题而是“改代码”问题——设备和逻辑变了你改的是参数不是逻辑本身。对比项梯形图ST函数块相同逻辑复用复制改地址容易漏改声明多个实例参数不同即可复杂运算指令块堆叠阅读困难表达式直观注释方便增量修改全局软元件交叉牵连改动局部化接口清晰多人协作需要反复对齐软元件地址靠函数块接口约定即可需要提醒一句不是所有逻辑都适合ST。简单的互锁、急停回路、安全回路用梯形图反而更直观也更符合电气人员的审查习惯。结构化编程从来不是“全盘ST”而是把数据运算、设备批量处理、报警逻辑从梯形图里抽出来放进函数块。2. 从零搭一个三菱PLC的ST函数块库2.1 编程平台与ST语言入口三菱PLC的ST支持分平台GX Works2对应FX、Q等经典型号在工程部件树里有“功能块”和“函数”的入口GX Works3对应iQ-R系列和FX5U结构化编程能力更强可以建结构化工程、声明全局标签、组织多个程序。新建函数块时你需要先想清楚这一块是函数FUN还是函数块FB。函数没有内部记忆同样的输入永远得到同样的输出适合做纯计算比如工程量换算函数块有内部变量每次调用对应一个实例存储区适合做带状态的处理比如延时、累计、状态机。不是所有三菱CPU都支持完整的ST语法。FX3U在GX Works2里能建ST程序但可用指令和Q系列不完全一样Q系列老CPU用ST没问题但有些结构化对象、数组的支持要受固件限制。我开始建库时也犯过这个错在GX Works3里建好库拿到现场设备上一看CPU是旧固件编译报错后来只保留基础语法才通过。所以建库之前先确认目标CPU型号和软件版本别等程序写完了再平移。2.2 第一个可复用函数块模拟量归一化模拟量处理是每个项目都躲不掉的压力传感器4-20mA进模拟量模块PLC读到的原始值可能是0到4000现场要显示0到1.0MPa。梯形图里你会写好几条加减乘除指令换一个通道再复制一遍。用ST函数块这件事就变成一次封装、到处调用。下面是一段典型实现。为了把接口说明写全我按标准IEC写法展示外部壳三菱软件的新建FB向导会自动生成外壳你填核心逻辑即可FUNCTION_BLOCK FB_Scale VAR_INPUT xRaw : INT; // 模拟量原始值如0~4000 rRawMin : REAL; // 原始值下限 rRawMax : REAL; // 原始值上限 rOutMin : REAL; // 工程量下限如0.0 rOutMax : REAL; // 工程量上限如1.0 END_VAR VAR_OUTPUT rOut : REAL; // 换算后的工程量 rValid : BOOL; // 换算结果是否有效 END_VAR VAR rRange : REAL; END_VAR rRange : rRawMax - rRawMin; IF ABS(rRange) 0.000001 THEN rOut : 0.0; rValid : FALSE; ELSE rOut : (xRaw - rRawMin) / rRange * (rOutMax - rOutMin) rOutMin; rValid : TRUE; END_IF;那几行算式不复杂真正的价值在边界处理量程上下限一样时如果直接做除法会在运行中产生无法预估的结果所以要先判死区。实际调用时在程序里写三行fbPs1(xRaw : D110, rRawMin : 0.0, rRawMax : 4000.0, rOutMin : 0.0, rOutMax : 1.0); D120 : fbPs1.rOut;这就是库的雏形。现场有8路压力、4路温度、4路流量同样的功能块实例化十几份参数对应好算术逻辑一行都不需要重复。2.3 函数块接口设计别把地址写死在功能块里新手最容易犯的错误是在功能块内部直接写D100、M100。看着方便但这个FB出了工程就废了未来换I/O点还要打开功能块翻地址库的价值归零。正确的做法是功能块内部只做算法不碰任何全局软元件与外部世界的所有交换都通过输入输出引脚完成。设计接口时我通常遵循三个习惯。一是每个FB只干一件事如果既要做滤波又要做报警又要做输出保持就拆成两个或者三个块方便单独替换、单独测试。二是输入输出变量命名带上类型前缀r代表实数、x代表布尔、n代表整数这样即使有人调用时还是ST写成梯形图也能一眼看出参数类型。三是每个变量都写单位、量程和说明这是给自己减负因为半年后回来看程序你根本不记得当初为什么这样写。关于库的存放我的做法是在工程里单独建一个“LIB”功能块文件夹把所有自建FB集中在里面设备主程序只做调用。这样即使项目交接接手的人也能按功能块名找到所有相关逻辑不用在梯形图里大海捞针。3. 压力控制场景下的库封装实战3.1 手自动切换的ST实现压力控制是产线里最常见的闭环场景之一比如气密性检测、液压保压、水压测试。很多项目的压力回路都要有手动和自动两套操作方式手动时操作员直接开阀、启泵自动时由压力设定值和实际值决定输出。梯形图里最常见的写法是两套电路并联经常出现“手动状态下自动信号把输出拉起来”的怪问题。用ST函数块处理这个逻辑关键是先把模式选通做清楚CASE nMode OF 0: // 手动模式 xRunCmd : xManOpen AND NOT xManClose; 1: // 自动模式 xRunCmd : (rOutPID 5.0) AND NOT xAutoLock AND xStartActive; ELSE xRunCmd : FALSE; END_CASE;这里把最终的输出命令统一汇总到一个变量上不再用分散的线圈从根上避免双线圈输出的问题。手动开关和自动条件只在各自模式生效模式切换也不会出现输出乱跳。工程里我会顺手再包一层去抖按钮的初触瞬间经常有抖动给xManOpen加一个10ms的延时确认避免误动作。这类逻辑一旦封装好以后所有阀门、电机的手自动控制都能复用。3.2 报警判定与延时防抖的封装压力报警绝不能写“压力高于上限就报警”这么简单。现场启动瞬间、管道排气、PID超调都会让压力瞬时超限如果不做延时判定系统天天误报警。常用的做法是“持续超限2秒才报高压报警”。这段逻辑是标准的TON延时放进函数块后梯形图里的定时器和置位复位都变成参数FUNCTION_BLOCK FB_TimerDelay VAR_INPUT xTrigger : BOOL; // 原始触发信号 tDelay : TIME; // 需要持续的时间 xReset : BOOL; // 复位 END_VAR VAR_OUTPUT xOut : BOOL; // 延时后的输出 END_VAR VAR stTimer : TON; END_VAR xOut : stTimer(xIn : xTrigger AND NOT xReset, t : tDelay);需要提醒的是三菱的ST与标准IEC的定时器写法在GX Works2/3里略有区别有些版本要写stTimer(xIn:..., t:...)并取返回值有些版本要先执行stTimer(xIn:..., t:...)再读stTimer.Q。我在第一次移植库时就栽在这里后来统一以目标软件里“功能块调用助手”生成的代码为准不同平台各留一份模板。除了超时报警压力回路还经常需要“上电抑制”。PLC刚上电时压力传感器要经过滤波器稳定前几秒读出来的值可能不准。解决办法是在报警函数块的输入端加一个初始化抑制信号CPU上电后先保持3秒报警无效之后再投入。这段逻辑放在专门的“初始化管理FB”里所有报警块统一使用避免每个报警逻辑各写各的。3.3 PID调节与ST库的组合压力闭环控制有人直接用三菱自带的PID指令也有人喜欢自己写增量式PID。我的建议是不要把PID算法代码散落在主程序里而是给它套一层库封装。这样做的原因很简单输出的模拟量要限幅、正反作用要切换、手动自动模式切换时要做无扰切换这些附加逻辑如果都写在梯形图里会非常痛苦。我的库里会有一个FB_PIDWrap