ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ST与梯形图混编的三种写法及选型指南

ST与梯形图混编的三种写法及选型指南

做设备改造这几年,我最大的感受是:PLC程序写到一定程度,梯形图就不够用了。去年我负责一条老化测试线的程序升级,原程序清一色梯形图,功能越加越多,模拟量换算、配方选择、报警排序这些逻辑密密麻麻铺了几十个网络,改一个量程要在三四个地方翻来翻去,光是理清触点关系就耗了一下午。后来我把一部分算法逻辑换成ST写,再用梯形图把ST块包起来,程序瞬间清爽了不少。这篇就聊聊ST与梯形图混编的三种写法,分别是什么、各自解决什么问题、什么时候用哪种,以及混编实测下来最容易踩的坑。内容偏西门子S7-1200/1500平台,三菱FX3U/FX5U的ST编程逻辑也通用,正在做设备改造、想把复杂算法从梯形图里拆出来,或者刚开始接触ST的工程师,应该都能用得上。

1. 三种混编写法的整体思路拆解

1.1 为什么要混编,而不是二选一

先明确一个基本事实:梯形图和ST不是竞争关系,而是互补关系。梯形图的核心优势是直观,继电器回路、互锁、急停,一眼就能看出逻辑关系,电气出身的人看着特别亲切;ST的核心优势是表达能力强,数学运算、循环处理、字符串、数组、嵌套条件分支,用梯形图写起来费劲的活,ST几行就完事。

但麻烦在于,设备程序通常既有安全性要求高的硬逻辑,又有运算量不小的算法逻辑。全用梯形图写,算法部分会变得又长又绕;全用ST写,硬件安全回路、手动操作逻辑可读性会明显下降,现场维修电工大概率会骂人。这时候就需要混编:让梯形图去管它擅长的“看得见的逻辑”,让ST去管它擅长的“算得动的逻辑”。

实际场景中我见过不少反面案例。有的工程师出于对ST的新鲜感,一个程序从上到下全用ST,结果急停回路也写在ST的IF里,现场设备急停按钮出了状况,排查时看半天才发现某个IF嵌套顺序错了。也有工程师死活不碰ST,2000步的程序能用梯形图硬扛,等程序涨到5000步,维护成本直接翻倍。混编的价值就在于,把两种语言的优点揉进一个工程,各管一段。

1.2 三种写法的核心特征与选型逻辑

根据我拆过和写过的程序,ST与梯形图混编基本就三种主流写法:

写法核心结构典型特征适合场景
写法A:梯形图主导,ST做内层算法梯形图搭程序骨架,FC/FB内部用ST写算法触点、线圈、安全回路全在梯形图里,复杂计算封装在ST块内程序整体逻辑不复杂,但夹杂模拟量处理、查表等算法
写法B:ST主导,梯形图做外壳和守护ST写业务逻辑主流程,梯形图只负责启停、急停、手自动切换主流程是ST的IF/CASE,硬件安全回路由梯形图独立保护工艺流程复杂、分支多,但安全要求同样高
写法C:按功能分层,模块间协同梯形图和ST各自负责不同功能模块,通过共享数据区交换信息安全相关逻辑和算法逻辑彻底分层,互不干扰设备功能多、程序量大,多人协作或后期维护频繁

选择标准不复杂。如果你的重点工作量在逻辑控制、顺控上,算法只是偶尔插一脚,用写法A;如果你的程序核心是配方、排序、数学建模这种流程密集型逻辑,又不想牺牲安全回路的可靠性,用写法B;如果设备分好几个工位、多个独立功能单元,建议直接上写法C,把整个工程按工艺段切块,梯形图和ST各写各的,反而最清晰。

1.3 影响选型的三个关键维度

除了功能边界,还有三个维度会影响最终选择。

第一是调试可观测性。梯形图在线监控时,每个触点的通断在屏幕上清清楚楚,ST块里则只能看变量值,看不到“执行到哪一行”。设备调试阶段,如果程序逻辑还没稳定、频繁要跟现场信号核对,优先用写法A,把ST的范围限制在算法块里,主逻辑在梯形图里可以随时盯触点。程序稳定后再考虑把低频改动的流程迁到ST里。

第二是团队维护能力。这是很多人容易忽略的点。设备卖出去以后,现场服务工程师大概率不懂ST,让他们改梯形图没问题,改ST里的一行判断就是灾难。如果你的售后团队结构没有变化,老实点,主逻辑留在梯形图里,ST只做封装好的“黑盒算法块”——外部接口固定,内部随便改,不影响梯形图侧调用。

第三是目标PLC平台的指令和资源限制。西门子S7-1200/1500对ST(实际叫SCL)的支持很成熟,三菱Works3里的ST程序、FX5U的ST功能也没问题。但老一点的FX3U在GX Works2里做ST混编,块里不允许某些操作,循环语句的指令周期也更长,混编前必须先确认目标PLC的ST指令集覆盖范围。别拿新平台的特性去套旧机型,会被打得措手不及。

2. 混编前必须理清的几个底层问题

2.1 扫描周期与程序执行顺序

ST和梯形图混编之后,第一件要搞明白的是程序执行顺序。PLC的运算本质是循环扫描:读取输入、执行用户程序、刷新输出,一个周期接一个周期。在同一个OB1里,先写的网络先执行,梯形图网络和ST块混在一起时,ST块作为一个整体被调用,调用位置决定了它在整个扫描周期里的执行时机。

这里有个常见误区:有人觉得ST块的代码是“独立线程”,和梯形图并行执行,这是不对的。ST块被OB1调用时,它就在这一扫描周期的这个时间点上跑完整个块,跑完才继续往下执行梯形图的后续网络。如果ST块里写了一个大循环,循环时间过长,整个OB1的扫描周期都会被拖长,PLC的看门狗直接报错停机。

我记得第一次在循环里跑数组处理,FOR循环上限设成了5000多,S7-1200的OB1默认扫描周期监控时间是150ms,一个循环直接超时。后来把数组长度改小,同时把循环拆成“每次扫描只算一小段”的分片处理,才把周期压下来。所以混编之前,先算清楚这个ST块的执行时间对整体扫描周期的影响,尤其是有循环和浮点运算的时候。

2.2 数据交换的三种常用通道

梯形图和ST块之间要传数据,不是像高级语言那样直接调函数传参那么简单,PLC里有三种主流通道。

第一种是全局数据块(Global DB)。这是最常用的方式,定义一个共享DB,梯形图往里面写“当前温度”“启动指令”,ST块一边读一边算,再把结果写回DB,梯形图再去读结果。优点是任何人都能看到数据流,在线监控很方便;缺点是DB里变量多了以后容易乱,必须做好命名规范,否则时间一长谁都不知道某个变量是什么意思。

第二种是函数块的背景数据块(Instance DB)。当ST逻辑写在FB里时,FB每次调用都会配一个背景DB,管脚上的输入输出参数都映射到这个背景DB里。梯形图调用FB时填参数,相当于给ST块传递输入、取回输出。优点是封装性好,同一份ST逻辑可以造出多个互不干扰的实例;缺点是背景DB数量多,管理起来要有点耐心。

第三种是M区或全局标签。用在比较简单的数据交换场景,比如三菱PLC里梯形图用M0做启动,ST程序块里直接IF M0 THEN,数据通过软元件直接互通。这种方式最直接,但M区地址重叠的风险需要格外注意,一个地址被两处写,排查起来挺头疼。我做三菱FX3U混编时就栽过跟头,ST块里用了M100做中间标志,结果梯形图网络里早就有M100自锁线圈,两边抢一个点,设备动作全乱了。

2.3 数据类型与接口匹配

混编时数据类型是最容易翻车的地方,而且往往是编译不出错的隐性错误。梯形图里触点、线圈都是BOOL,数据块里常见的是INT、DINT、REAL,ST块在函数里声明管脚时,类型接不上就会出问题。

举一个我实际遇到的:模拟量模块采上来的原始值是INT,0到27648,梯形图里直接把INT和设定值比较,看不出毛病。把这个逻辑搬进ST块以后,我声明了一个REAL类型的输入管脚,梯形图那边传INT进去,系统自动做了隐式转换,数值看着对,但精度和范围都有隐患。后来所有模拟量值统一在ST块入口手动转成REAL,再参与运算,才彻底稳定。

需要特别留意的还有TIME、DATE这类复合类型。ST里做延时要TIME,梯形图TON的PT端也是TIME,但有一点要记住:ST里直接写TIME常量要加前缀,比如T#5S代表5秒,直接写数字编译会报错。另外BOOL在ST里的写法是TRUE/FALSE,不是1/0,虽然有些平台兼容,但逻辑判断出错时很难查。

2.4 在线监控与调试方式的差异

梯形图在线监控的体验是ST无法替代的:每一个触点上都有一个“小绿灯”,通断状态一目了然。ST块内部则只能看到变量值,看不到执行流程,也无法在梯形图上看出ST块当前“卡”在哪一行。这不是缺陷,是语言本质决定的,但混编程序调试时就必须有对应的替代方法。

我常用的调试手段是“探针变量”。开工时在共享DB里定义几个DEBUG用的状态字,ST块在关键分支处把当前状态值写进去,梯形图里放一个监控表,或者直接把状态字映射到触摸屏的隐藏画面上,调试时看状态字就知道ST块走到哪个分支了。这个方法比反复离线修改再下载快得多。

另一个经验是断点调试。博途(TIA Portal)的SCL块支持设置断点,程序停在断点处可以看到块内的局部变量值,也能单步执行。但要注意,启用断点调试会占用PLC资源,在线调试完一定要禁用断点再恢复运行,否则影响程序执行时间,我还见过断点没清干净导致设备运行时程序一直停在某个位置的情况,现场急得满头汗。

3. 实操演示:S7-1200上同一需求三种写法各来一遍

3.1 案例需求:模拟量换算加正反转控制

纸上谈兵没意思,我拿一个实际设备上的典型需求来做演示:一个温控箱体,需要把4-20mA温度变送器的模拟量信号换算成实际温度,温度超限时报警,同时控制风机的正反转。换算公式很简单:实际温度 = (模拟量原始值 / 27648) × 量程 + 偏移量,但放在设备程序里,加上启动、停止、互锁、报警这些常规要求,就够体现三种写法的差异了。

换算逻辑我封装成FC,梯形图侧做启停和正反转互锁,这样一来同一个需求可以用三种不同方式组合,对比起来很直观。三菱的读者也可以对应理解:西门子的FC相当于三菱的ST程序块,全局DB相当于D区或全局标签,底层逻辑是相通的。

3.2 写法A:梯形图主导,ST做内层算法

写法A的核心思路是:程序骨架、启停、正反转互锁、报警输出全部留在梯形图里,ST只负责模拟量换算这一小块算法。

梯形图侧的逻辑很简单:启动按钮置位运行标志,停止按钮复位,运行状态下风机得电;正转和反转继电器之间做互锁,两个输出不可能同时通。换算部分则在某个常ON的网络上调用FC。

FUNCTION "FC_ConvertTemp" : Void VAR_INPUT RawValue : Int; // 模拟量原始值 0-27648 ScaleHigh : Real; // 量程上限 ScaleLow : Real; // 量程下限 END_VAR VAR_OUTPUT TempValue : Real; // 换算后的实际温度 OverTemp : Bool; // 超温报警标志 END_VAR VAR THigh : Real; END_VAR // 原始值转成REAL再做线性换算 #TempValue := (REAL(#RawValue) / 27648.0) * (#ScaleHigh - #ScaleLow) + #ScaleLow; // 超温判断,量程上限加5度做报警阈值 #THigh := #ScaleHigh + 5.0; IF #TempValue > #THigh THEN #OverTemp := TRUE; ELSE #OverTemp := FALSE; END_IF;

这里的关键点:梯形图网络调用FC时,RawValue引脚要填模拟量输入地址(比如IW64),ScaleHigh和ScaleLow填4.0和100.0这类实际量程值,TempValue和OverTemp则填到DB里的变量地址。这样做的优势是梯形图里逻辑完整,懂电气的人可以全程看得懂,ST不过是“一个黑盒小算法”,参数给进去,结果拿出来,内部写的什么不用关心。

注意事项是FC不要在这个写法里越权。我以前见过有人把正反转互锁也写进ST块里,梯形图那边输出直接接接触器,看似省事,实际上梯形图侧完全失去了对安全回路的可见性,等于把安全性最大的保障给丢了。写法A的边界应该是:梯形图管逻辑,ST管计算。

3.3 写法B:ST主导,梯形图只做启停和守护

写法B适合工艺流程复杂、分支多的情况,比如多种运行模式、多段温控曲线,用CASE分支来处理比几十个梯形图网络清楚得多。

这个写法下,梯形图只做三件事:急停回路(硬接线或梯形图软回路)、启动停止按钮输入、调用ST主逻辑块。所有业务逻辑都在ST块里,手自动切换、正反转互锁、超温报警、连锁条件,全部用ST实现。

FUNCTION "FB_MainLogic" : Void VAR_INPUT StartCmd : Bool; // 启动命令 StopCmd : Bool; // 停止命令 ManualMode : Bool; // 手动模式 RawValue : Int; // 模拟量原始值 END_VAR VAR_OUTPUT FanForward : Bool; // 风机正转 FanReverse : Bool; // 风机反转 AlarmLamp : Bool; // 报警灯 END_VAR VAR TempValue : Real; RunFlag : Bool; END_VAR // 模拟量换算 #TempValue := (REAL(#RawValue) / 27648.0) * 96.0 + 4.0; // 运行标志控制 IF #StartCmd THEN #RunFlag := TRUE; END_IF; IF #StopCmd THEN #RunFlag := FALSE; END_IF; // 温度保护,超温只允许反转运行(排风逻辑) IF #TempValue > 100.0 THEN #AlarmLamp := TRUE; #RunFlag := FALSE; END_IF; // 手动模式直接输出,自动模式带连锁 IF #ManualMode THEN #FanForward := FALSE; #FanReverse := TRUE; ELSE #FanForward := #RunFlag; #FanReverse := FALSE; END_IF;

梯形图那边只留下急停回路:急停按钮的常闭触点串在输出线圈前面,任何时候急停按下,风机输出立刻切断。这是写法B的关键设计思维:把“安全的逻辑”和“逻辑的安全”分开,业务流程怎么复杂都行,硬件安全回路由梯形图守住最后一关。

写法B的优点很明显,业务逻辑修改方便,不用再翻几十个梯形图网络找触点;缺点也很直接,ST块里的状态机对不熟ST的人来说就是个黑箱子,调试时必须配好状态字或探针变量。

3.4 写法C:按功能分层,ST块与梯形图模块协同

写法C适用于真正的多模块设备,比如加热、输送、分拣各一个工位,每个工位既有独立逻辑,又要跟总控联动。这时候不推荐把所有逻辑塞进一个ST块,也不推荐梯形图里几百个网络堆在一起,而是按功能区切块,各写各的,通过共享DB对接。

在我的温控箱例子里,可以这样分:梯形图负责安全回路和手动操作,ST块1负责温度采集换算和超温报警,ST块2负责风机自动运行策略(比如按温度自动切换正反转),总控条件放到共享DB里,梯形图和各ST块都往这个DB里读写。

模块实现语言职责数据接口
安全回路梯形图急停、接触器互锁、硬件保护直接接输出
手动操作梯形图手动按钮、点动、单步测试写入共享DB
温度换算梯形图调用FC(内含ST)模拟量预处理、超温判断读取共享DB
自动策略ST自动运行状态机、模式切换读写共享DB

这种写法下,模块之间的耦合被压到最低。自动运行的ST块根本不关心风机接触器具体是哪个输出点,它只管往共享DB里写“FanForwardDemand := TRUE”,梯形图侧读到这个请求后,再结合急停状态和互锁条件,最终决定是否真的输出。好处是每个模块都能相对独立地测试,改自动策略不影响安全回路,改互锁逻辑也不用碰ST。

模块开发时有个经验:共享DB相当于各模块间的“协议”,变量命名一定要带前缀,比如Temp_Current、Fan_Cmd_Forward、Mode_Manual,避免时间一长自己都分不清谁在写谁在读。我在一个改造项目里,共享DB里的BOOL变量有三四十个,写模块时图省事随便命名,后来排查问题只能一个个点开看,效率特别低。

3.5 三种写法对比后的选择建议

从这几个代码示例能看出来,同一个小需求,三种写法都能实现,但代码分布、调试方式、维护难度完全不同。

如果项目就是一台单机设备,程序量一两千步,逻辑主要集中在顺序控制上,只有零星几个计算,写A最稳,梯形图占大头,ST只在算法块里露脸。如果是流程类设备,配方多、模式多、温度曲线复杂,写B能让主流程清晰得多,但要配好状态字方便调试。如果是整线设备,多个工位协同动作,写C是最终归宿,不然后期加功能必然牵一发而动全身。

我自己的原则是:单模块内优先保证可读性,多模块间优先保证解耦。这三者不是互斥关系,一个大程序里经常会同时出现写法A和写法C,比如某个工位的算法用A,整个产线的协作逻辑用C。B用得少一些,因为完全ST主导对售后团队不友好,除非是研发型项目且维护人员有ST基础。

4. 常见问题与排查技巧实录

4.1 ST块内部变量在线监控不到

混编后第一个常见问题是工程师习惯性想去“看梯形图触点”,却发现ST块里全是代码行,根本没法像梯形图那样观察逻辑通断。这是语言差异,不是说代码有问题,但现场调试效率会明显下降。

我的解决方法是“状态镜像”。在ST块里专门设一个输出变量,叫DiagState(诊断状态),每个关键分支处把一个常量写进去。比如换算正常写1,超温写2,手动模式写3,通信故障写4。然后这个变量在梯形图里接一个比较指令,等于把ST内部的“走到哪了”映射成梯形图能看懂的信号。现场人员不用打开ST块,看一眼触摸屏或监控表就知道设备卡在哪个逻辑分支。

这个方法我很早就开始用,实测下来对调试效率的提升是决定性的。尤其是程序客户现场出问题的时候,售后工程师可能完全不懂ST,打来电话说“设备不动了”,我让他看触摸屏上诊断状态码是几,一秒就能定位问题区间,比自己翻代码高效得多。

4.2 数据类型的隐式转换和精度坑

ST和梯形图接口处的数据类型问题,编译时多半不报错,但运行结果千奇百怪。最常见的几个坑:一是INT和REAL混用做除法,有的平台直接截断成整数,结果完全不对;二是BOOL赋值用了1而不是TRUE,逻辑判断时行为怪异;三是比较运算里REAL值明明等于目标值,却一直不触发,这是浮点精度问题。

REAL比较的问题值得单独说一下。比如ST里写了IF TempValue = 50.0,TempValue经过一系列浮点运算,实际值可能是49.99999,条件永远不满足。正确做法是区间判断,IF TempValue > 49.5 AND TempValue < 50.5,或者在换算时就加一个“归一化”处理:先把数值四舍五入到一位小数,再参与比较。

我做温控程序时,所有温度比较统一用“大于设定值+0.1度”作为动作条件,表面看多了0.1度容差,实际大幅降低了误触发的概率,而且对工艺完全没有影响。

4.3 FB的背景DB分配混乱

FB和FC是有区别的。FC没有背景数据块,参数直接映射到调用方的实参;FB每次调用都要一个背景DB,不同实例之间数据完全隔离,梯形图调用FB时要手动指定或自动分配背景DB。混编时常见的错误是多个FB调用用了同一个背景DB,导致一个设备的运行状态把另一个设备“顶掉”。

一个典型事故:我在一个双工位设备上复用同一个FB做温度控制,梯形图里两个工位都调用这个FB,第一次下载时没仔细看,两个调用的背景DB自动分配成了同一个,结果一个工位设定温度变了,另一个工位也跟着变。排查了两个小时才想起来去翻调用的“背景DB”参数。教训是:FB共享逻辑是好事,但每个调用点一定要确认背景DB是独立的,最好在命名时带上工位号,比如DB_TempCtl_Sta1、DB_TempCtl_Sta2。

4.4 ST块循环语句导致扫描超时

ST的FOR循环、WHILE循环使用不当是PLC停机的常见原因。PLC不是PC,循环指令要占据真实的CPU时间,循环体里再放浮点运算,一次循环几微秒,几千次叠加起来很可能直接扫溢出。

我在处理一段数组求和时写过FOR i := 0 TO 9999,在仿真器里能跑,下载到实体PLC上一运行CPU直接STOP。排查后发现不是代码问题,是循环体太大,OB1的扫描周期监控时间内跑不完。最后把数组拆成多段,每次扫描只处理一段,再配合移位指针,才把扫描周期恢复到正常水平。

这里给个经验值参考:S7-1200的OB1默认周期监控是150ms,虽然可以改大,但不建议长期靠这个方案扛,那相当于用“允许更慢的响应”换程序跑通,风险太大。三菱FX5U的ST循环同样要注意,老款FX3U的ST指令集循环效率相对低,能用梯形图分步实现的循环逻辑就尽量别硬上ST。

4.5 常见问题速查表

症状可能原因排查思路
ST块计算结果与梯形图监控值对不上数据类型隐式转换、浮点精度统一显式转换,用区间比较替代等值比较
调用ST块时设备动作全乱了FB背景DB串用检查每个调用的背景DB是否独立分配
PLC上电后ST块不执行ST块没有被OB1调用检查OB1里是否有该块的调用网络,注意调用位置
ST块里FOR循环执行完PLC停机扫描周期超时减小循环上限,分片处理,或调整扫描监控时间
梯形图上修改变量但ST块里看不到变化数据区地址重叠用交叉引用查该变量的所有读写位置
在线监控ST块提示“无法访问”块被加密或当前在线模式不支持检查块属性,编译下载时选择“下载但不初始化”

这些坑几乎都是我在实际项目中踩过的,不是教科书式理论。混编程序出问题时,先不要怀疑ST或梯形图本身,先怀疑数据交互这一层。数据通道干净了,90%的诡异问题都会消失。

5. 关于混编边界划分的个人经验

要说我最大的体会,就是混编的本质不是语言之争,而是“分层”之争。梯形图和ST各有主场:梯形图的主场是安全逻辑、手动逻辑、看得见的控制回路;ST的主场是算法、流程、数据处理、复杂分支。一个人总想把所有代码写成同一种语言,通常是因为心里没有清晰的层次感。

我后来写设备程序,都会先画一张“程序结构图”再动手。这不需要什么工具,纸笔就行:哪些模块属于安全级,哪些是工艺级,哪些是算法级,每一级用什么语言写、相互之间怎么传数据,先写清楚再开编。三个工程阶段下来,混编程序的维护成本比纯梯形图时代低了一个量级,现场报修的频率也明显下降。

最后再分享一个小技巧:每台设备程序的第一个版本,尽量先把梯形图和ST的模块边界白纸黑字定下来,哪怕是拿胶带贴在控制柜里也行。边界清晰以后,后来加功能的人才知道往哪里加。没有边界的混编,过半年再回来看自己的代码,你都想不起来当初为什么要把这个逻辑放在这里。先理清边界,再谈写法,这才是ST与梯形图混编最值得花时间的部分。

返回列表