
做PLC程序这么些年我对“ST和梯形图混编”这件事的态度经历了好几轮变化一开始觉得混编就是给自己找麻烦梯形图写得好好的干嘛要掺和ST后来发现纯梯形图处理复杂计算时真的会写到怀疑人生再后来在几个项目里正儿八经地把两种语言混着用踩过坑、返过工、半夜在车间改过程序才慢慢摸出一些门道。今天这篇文章就把我实际用过的三种ST与梯形图混编写法摊开来讲清楚包括每种的思路、适用场景、典型机型的落地过程以及那些没人写在手册里的坑。1. 混编不是炫技而是机器现实需要1.1 梯形图擅长的和ST擅长的完全不是一回事先说一个我自己的判断标准梯形图的本质是“看得见的继电器逻辑”它模拟的是硬件接线所以对电气工程师、维修电工特别友好。现场设备不动了打开梯形图在线监视看着哪一行的触点没闭合、哪个线圈没得电有时候比万用表还好用。像正反转互锁、急停回路、安全门、手动自动切换这些逻辑我到现在仍然坚持用梯形图写理由很简单能在线监视、能强制、维修师傅看得懂、出问题不容易误判。ST则是完全另一套思维。它像C语言、Pascal这类高级语言有IF、CASE、FOR、WHILE支持数组、结构体、函数块做数据运算、参数计算、状态机迁移、配方处理、通信报文解析时效率比梯形图高一个数量级。你在梯形图里写一个复杂的温度PID公式或者推算一个电机加速曲线的脉冲数那场面真的很难看一串看不到头的MOV、FMUL、DIV指令别说维护自己过两天回看都费劲。同样的算法用ST写几行代码清清楚楚。但是现实中的PLC程序往往一半是硬逻辑、一半是软算法。生产线上的设备既要求安全互锁可靠直观又要求定位计算、数据处理、流程状态管理高效简洁。你非要用一种语言包打天下结果就是两边都别扭。所以混编不是哪个工程师的爱好而是设备的现实需求倒逼出来的。1.2 先想清楚边界再动手选写法这些年我总结出一个经验不要上来就纠结用ST还是梯形图先想清楚这个程序要干什么哪些任务属于“看得见的逻辑”哪些属于“算得清的数据”然后才谈得上怎么写。我一般会先画一个很粗的边界安全回路、主互锁、手动操作、点动按钮、硬件急停、报警输出默认梯形图。状态机、流程步骤、配方管理、运动曲线计算、通信数据解析、模拟量处理、批量运算默认ST或函数块。速度、位置、脉冲数的换算这种谁来写都行但要固定在一个地方不要一会梯形图一会ST。边界画清楚之后再来选混编的具体形态。实际工程里常用的形态大概能归成三种梯形图为主、ST填算法格子ST为主、梯形图守安全以及工程级按块混合。下面拆开讲。2. 三种常用混编写法拆解2.1 写法一梯形图搭框架ST填算法格子这是我推荐大多数项目优先考虑的写法也是“混编”最朴素的形态整个程序的主干、状态流转、互锁、输出驱动全部用梯形图搭好遇到需要复杂计算或者数据处理的地方不要直接在梯形图里硬写指令而是用ST写一个函数块或者子程序然后从梯形图里调用。打个比方梯形图是厂房里的传送带系统负责把工件从一个工位送到下一个工位每一段都很容易观察和维护ST则是设备里的几台计算器放在几个固定的工位边上传送带把数据送进去、把结果带出来。计算器内部干了什么你不一定天天看但它和传送带之间的接口是清晰的。具体实现上不同品牌叫法不太一样但思路一致。以西门子TIA Portal为例你可以在程序里建立一个FC或者FB编程语言选SCL就是西门子家的ST然后在OB1或者某个FC里用梯形图调用这个块。调用的时候梯形图上看起来就是“一个功能块指令”输入输出参数都列在引脚上。我在一个贴标机上这么干过贴标的位置补偿量计算很啰嗦要根据色标传感器的两次触发时间差、输送速度、标签长度算出一个动态补偿值。这个计算如果用梯形图写至少要二三十行数学指令改一个公式得翻半天我用SCL写了一个FC_Compensation输入是时间差、速度、标签长度、当前补偿值输出是新的补偿值。梯形图主程序在每个贴标周期里调一次这个块逻辑照样看得懂算法也好维护。这种写法的好处很多第一PLC扫描逻辑的主线仍然是梯形图现场工程师顺着梯形图就能理清整个设备的动作过程第二ST只管“算”不管“开”和“关”不会破坏安全互锁的直观性第三算法被封装成一个带输入输出的块复用性高同一套计算逻辑可以用在多台设备上。缺点也不是没有如果你把一个FB设计得很重、功能很多梯形图一侧的引脚会密密麻麻反而影响可读性。所以我的习惯是ST函数块尽量“小”和“纯”一次只解决一个问题输入输出不要超过五六个。2.2 写法二ST搭框架梯形图守安全第二种写法刚好反过来。整个程序的主要流程和核心控制用ST写梯形图只用来实现那些“必须一眼能看明白”的安全和手动逻辑。这种写法在运动控制、视觉检测、数据处理占比很高的设备上非常实用。比如一台有视觉定位的自动点胶机主流程是“拍照→计算偏差→修正轨迹→点胶→固化→流出”中间还有配方切换、连续运行计数、不良品剔除队列管理。这些流程用ST的状态机写法非常舒服用CASE语句分状态每个状态里做对应的动作和跳转条件代码结构清晰扩展新流程就像往CASE里加一行。但机器上绝不能少的急停、门锁、原点回归允许、手动试喷按钮这些硬逻辑我会单独用梯形图写然后通过一个布尔变量或者DB地址交给ST主程序去“读”。甚至有些设备上我直接让梯形图控制安全中间继电器的输出回路ST根本不允许直接操作这些输出点。这就是“ST搭框架、梯形图守安全”的核心把不那么依赖人的判断、但是绝对不容出错的东西留给最直观的语言。这里有一个关键点梯形图“守安全”不是说梯形图里写了就绝对安全而是要保证安全逻辑的“可见性”和“独立性”。我见过一个项目把安全逻辑写在一个大型ST函数块里后来设备调试时维修师傅死活不愿意在线强置ST里的变量因为看不到互锁关系生怕弄错。换了梯形图之后大家都敢操作了。这种写法的代价是要求写ST的人有较强的结构化编程能力状态机划分、变量作用域、函数块封装都要心里有数否则代码很容易变成一团乱麻。而且ST为主的项目在线监视的直观性会下降调试时往往要开着变量监视表一边看状态变量一边看梯形图的输出。2.3 写法三工程级分层按块混编第三种写法不是把ST和梯形图写在同一段程序里而是从整个工程的角度做功能分区不同的程序块、不同的功能单元按各自特点选择语言块之间通过输入输出参数、全局数据块来交互。我去年做的一条输送线项目就是这种思路。整个程序分成几大块OB1主组织块用梯形图做里面是一个大循环调用各功能块同时处理全线的启动、停止、复位条件。FC_ConveyorLogic输送逻辑用梯形图写包含各段传送带的互锁、积料检测、自动手动切换。FB_MotionAxisX / FB_MotionAxisY运动控制用SCL写封装了一整套定位控制逻辑使能、回零、相对移动、绝对移动、触发条件。FB_RecipeManager配方管理用ST写负责配方的读取、校验、下发里边大量使用数组和结构体。FC_AlarmHandler报警处理用梯形图写把所有报警位汇总出来统一触发声光报警和触摸屏显示。这种方式的好处是每个程序块的职责非常单一块与块之间的接口固定多人协作时不会“互相打架”。编SCL的人不需要关心梯形图里有多少个互锁触点写梯形图的人也不需要理解配方数据在ST里是怎么排布的。现场调试时哪块出了问题就扎进哪块去查定位效率比前面两种写法都高。当然这种写法对项目前期的架构设计要求更高。如果一开始没有把功能边界划分清楚写着写着就会出现“这个功能到底放梯形图好还是ST好”的纠结甚至出现两个块同时操作同一个输出变量的情况。后边我会专门讲这个坑。2.4 三种写法对比速查表对比维度写法一梯形图为主ST算法块写法二ST为主梯形图守安全写法三工程级按块混编适合场景逻辑密集、安全互锁多的设备算法密集、流程复杂的设备多模块、多人协作的大中型项目程序主线梯形图清晰可读ST状态机控制各块职责独立在线监控直观性好一般需要变量表辅助取决于具体块整体还行对工程师要求中等ST会写函数块即可较高需要结构化编程能力高前期架构设计能力维护便利性维修电工能看懂大部分依赖ST程序员模块化维护边界清晰典型风险算法块接口设计不合理导致引脚爆炸安全逻辑被淹没不敢修改模块间接口不明确时容易混乱3. 三种真实机型上的实操记录3.1 西门子S7-1200SCL算脉冲梯形图发脉冲先拿西门子S7-1200举个例子。这个平台在TIA Portal里对ST和梯形图的混编支持得很舒服OB、FC、FB都可以单独选择编程语言相互调用特别自然。之前做一台小型步进电机送料机构就是典型的“正反转步进电机定位”场景启动后根据工件长度计算需要发多少个脉冲电机前进到位等待再反转退回原点。梯形图主逻辑负责启动按钮、停止按钮、原点传感器、正反转互锁。我把脉冲数的计算放在一个SCL写的FC里输入是目标行程、丝杆导程、驱动器细分数输出是脉冲总数和方向标志。FUNCTION FC_CalcPulse : VOID VAR_INPUT Travel_mm : REAL; // 目标行程 mm Lead_mm : REAL; // 丝杆导程 mm DivFactor : INT; // 驱动器细分倍数 END_VAR VAR_OUTPUT PulseCount : DINT; // 需要的脉冲数 DirForward : BOOL; // 正转方向 END_VAR VAR_TEMP Revolutions : REAL; END_VAR Revolutions : Travel_mm / Lead_mm; // 电机需要转多少圈 PulseCount : REAL_TO_DINT(Revolutions * 200.0 * INT_TO_REAL(DivFactor)); DirForward : Travel_mm 0.0; END_FUNCTION然后在梯形图里调用这个FC把计算出来的PulseCount和DirForward接到后面的定位指令输入上。定位指令在S7-1200里可以用MC_MoveRelative或者直接用PTO/PWM这里我就不细展开了。关键是整个程序从上往下看梯形图主流程是通的控制器输出的启停、方向互锁清清楚楚而脉冲数怎么来的、细分数怎么换算的被SCL封装了起来改一个丝杆导程不用翻几十行梯形图。这样做的直接好处是排版干净。我想看动作流程就看OB1和FC里的梯形图我想验证计算逻辑就打开SCL盯公式互不干扰。3.2 信捷XD3-24T-E伺服正反转的ST与梯形图配合信捷XD3-24T-E算是国产小型PLC里性价比很高的型号它带高速脉冲输出做步进和伺服控制很常见。这个平台的软件XCP Studio支持在同一个程序里混用梯形图和ST实际操作起来有几种姿势一种是梯形图主程序调用ST子程序另一种是在梯形图里插入一段ST“动作”逻辑。我做的一个小设备是伺服控制的翻板机构需要根据传感器信号判断翻板角度执行正转、反转、停留再回归。这里我用梯形图写了主流程和正反转互锁用ST子程序写了“根据当前传感器组合计算目标角度”的逻辑。梯形图侧大概长这个样子用指令表表示:// 启动条件手动模式允许 正转请求 LD M0_ManualOk AND M1_ForwardReq ANI M2_ReverseReq OUT Y0_ServoPulse这里的M1_ForwardReq、M2_ReverseReq不是直接从按钮来的而是ST子程序根据几个传感器状态算出来的。ST子程序内部类似// 根据产品到位、位置1、位置2、翻板角度传感器计算出动作请求 IF bPartReady AND NOT bPos2 THEN bForwardReq : TRUE; bReverseReq : FALSE; ELSIF bPartReady AND bPos2 THEN bForwardReq : FALSE; bReverseReq : TRUE; ELSE bForwardReq : FALSE; bReverseReq : FALSE; END_IF;可能有人会觉得就这点逻辑用梯形图写也不难何必用ST。但实际设备的判断条件远比这个复杂牵扯到角度模拟量、速度分段、延时补偿写在ST里就是十几行放在梯形图里就是一片触点网。信捷XD3-24T-E这种小型机算力有限ST写逻辑时只要不滥用FOR和嵌套执行速度完全没问题。3.3 三菱FX3U在梯形图里调用ST写的FB三菱FX3U在这个话题里有点特别。很多老工程师手里全是FX3UGX Works2环境下FX3U的程序主体还是以梯形图为主ST的出现更多是作为“函数块内部的实现语言”。换句话说你在梯形图里放一个功能块这个功能块内部的代码用ST来写这就是FX3U上很常见的混编方式。我之前维护过一台FX3U控制的灌装机配方里有十几组参数每一组都要经过温度补偿、压力修正、灌装量换算三步计算。梯形图写这些计算简直是灾难后来我把整套换算逻辑写成一个ST语言的FB输入是配方号和原始量输出是修正后的灌装量在梯形图里实例化调用。用ST写的FB在三菱GX Works2里看起来就是一块带引脚的功能块这个形态对梯形图使用者非常友好。要注意的是FX3U这种老CPU对ST的支持在数据类型和指令方面有边界别在FB里写过于复杂的数组操作和浮点高级函数编译出来程序容量大还不好查错。3.4 三种写法在工具链上的落地差异不同品牌的编程软件对混编的支持力度差别挺大。西门子TIA Portal做得最开放几乎每个块都能自由选语言信捷XCP Studio支持在梯形图程序段里插入ST块灵活但要注意调用顺序三菱GX Works2里ST通常以FB内部实现的形式出现老平台对ST的约束多一些。如果你是新手想练混编我建议从西门子S7-1200起步因为它对写法和调用方式的限制最小报错信息也相对友好。如果你手头就是信捷XD、三菱FX3U这类设备也没关系原理是通用的只要肯花点时间看软件里的帮助文档搞明白每个块用哪种语言编辑、能不能被其他语言调用就能开始动手。4. 混编常见的坑和排查实录4.1 同一变量被两处写程序却不按你想的执行这是混编里最典型的坑。PLC扫描是顺序执行的CPU从上到下、从左到右扫完一个程序块再扫下一个。如果你在梯形图里给某个M变量置位又在ST里给同一个变量赋值最终结果取决于谁后执行而不是谁“看起来更重要”。我有一台设备调试时出现过灵异现象ST里写了一个报警产生条件梯形图里也有一个报警复位按钮的逻辑。按理说报警触发后按复位应该能消除报警。但实际测试中报警总是消不掉。查了半天发现ST程序块在梯形图复位逻辑之后执行ST每一次扫描都会重新把报警位置为TRUE梯形图刚复位完ST又给置回来了。这个问题的解决思路不是调换块的调用顺序那么简单而是要建立“一个变量只允许一个归属块写其他块只能读”的规矩。报警位由报警处理块统一写复位按钮只是给这个块一个复位信号而不是直接在梯形图里“覆盖”报警位。4.2 数据类型和转换函数的坑ST里数据类型一个不小心就成了大坑。我见过有人把PLC里计算出来的脉冲数用INT类型存结果行程一长、细分数一高脉冲数超过了32767电机直接跑飞方向都反了。这种问题在梯形图里因为指令长度限制反而不容易犯因为梯形图里写DINT运算指令更麻烦大家会小心对待而ST里写程序很顺手容易忽略数据宽度。我的经验是凡是和脉冲数、计数有关的一律用DINT或者更大范围的类型凡是运动换算用的浮点数必须确认梯形图和ST之间传递时做了正确的类型转换。在S7-1200里SCL互转函数写起来方便但别偷懒省略转换。在三菱和信捷里INT和DINT混用时尤其要小心运行时数据溢出不会直接报错而是出来一个离谱的数值排查时非常费劲。4.3 ST里一不小心把扫描周期跑爆ST写循环结构时特别容易上头。你在ST里写一个FOR循环循环次数几千次里面还做了浮点运算看起来就几行代码但对小型PLC来说一个扫描周期可能直接飙到几十毫秒甚至更多。设备开机后动作还行一旦触发了这个循环所有输出都像慢镜头急停都得反应半天。碰巧我踩过这个坑。那是给一条包装线写“整箱计数统计”逻辑我用ST写了一个FOR循环遍历一百多组配方数据一开始没问题后来配方组数加到几百组扫描周期从3毫秒涨到60多毫秒整条线开始卡顿。排查了半天最后是查看扫描周期监控才发现的优化方式是只在数据变化时才做全量遍历别每个扫描周期都算一遍。民间做法还有个“土办法”把重计算放在“上升沿”或者“定时段”里执行别放在每个扫描周期无条件执行的地方。4.4 在线修改与监控的差异梯形图的在线监视非常直观程序里哪条线通了、哪个线圈亮了一目了然。但ST块的在线监控就没有那么直观了通常要靠变量监视表去盯内部变量。混编项目调试时建议养成同时开两个窗口的习惯一个窗口是梯形图在线监视看动作流程另一个窗口是ST块内部的变量表看算法中间量。在线修改也要小心。有些平台的ST块在线修改以后不能立刻生效或者需要重新下载程序段搞不好会短暂停机。现场生产节拍紧的时候这种“隐性停机”特别坑人。所以我在改ST块之前一定先确认当前设备状态尽量在非生产时段改改完马上下载并测试一遍空循环。5. 我现在的混编习惯5.1 分层IO层、算法层、执行层混编写到现在我形成了一个比较固定的结构就是三层分离第一层是IO映射层物理输入输出点统一在这里处理可以用梯形图写也可以用ST写我个人偏爱梯形图因为IO点表就是设备接线图一眼能看出哪个按钮去了哪个输入点。第二层是算法与流程层这里交给ST。状态迁移、配方管理、运动参数计算、报警条件判断都放这一层程序逻辑和具体物理点解耦改IO点位不用翻算法代码。第三层是执行与保护层用梯形图写。算法层给出“该干什么”的指令但真正驱动接触器、方向输出、互锁逻辑的还是这层梯形图这样即使ST内部有Bug物理执行也不会完全失控。这个分层不一定适合所有项目项目特别小的时候搞三层反而显得啰嗦但凡是超过两个轴或者超过四个气缸的设备这套结构收益就很大了。5.2 变量命名和注释的土办法混编项目最怕两件事一个是没有注释的ST一个是命名混乱的全局变量。梯形图变量名还能靠行列位置猜测ST代码如果没有注释三个月以后你再打开看只能靠上下文猜这个中间变量是干嘛的。我现在统一用前缀区分数据类型和用途物理输入用I前缀物理输出用Q前缀中间变量用M前缀数据块变量用DB前缀ST函数块内部变量用局部前缀还要在名称里带上含义比如M_PartReady、M_ForwardReq、DB_RecipeData、Axis1_CurrentPos。注释方面不要只在ST代码里写块头注释还要在梯形图功能块的引脚名称上写清楚毕竟梯形图是给“不想深究ST的人”看的引脚不写清楚别人只能干瞪眼。我的习惯是引脚名称直接带物理含义比如“脉冲数”、“方向正”、“当前位置”避免出现A1、B2这种纯编号式引脚。5.3 一个“先ST后梯形图”的折中方案前面说的三种写法我实际操作中最常用的是写法一但有时候也会反过来先写一个ST原型把整体流程和算法全部调试通过然后再把安全互锁和执行输出拆出来用梯形图重新搭一遍外围。这种方法看起来是重复劳动但对我这种有“先跑通再固化”习惯的人来说很稳。ST原型阶段可以快速验证算法和状态流不受梯形图那套触点线圈的束缚改起来比梯形图流畅得多。等流程跑通了再抽出需要现场维护和看得见的部分写成梯形图ST块就慢慢收缩成算法计算器。这样既保证了开发速度又留住了梯形图的现场友好性。当然如果你的项目按交付周期来算不允许你“做两遍”那就老老实实按写法三做工程级规划一步到位。别在前期省时间到后面返工更费时间。最后再啰嗦一句个人体会ST和梯形图混编没有标准答案一定以你所在场景里的“谁能看懂、谁要维护、出了事怎么查”为第一原则。语言只是工具程序是为了设备稳定跑起来顺便让调试的人少熬几个夜。