☰
三台电机顺起逆停的ST实现:CoDeSys顺序控制核心案例
2026/10/17 9:59:59 网站建设 项目流程

“三台电机顺起逆停”,在CoDeSys里用ST怎么写?这是我经常被问到的问题,尤其是一些刚接触PLC编程、之前一直画梯形图的朋友。顺起、逆停、定时器、按钮边沿、故障联锁,这些元素单独拿出来都不难,但组合在一起,很多人就容易写乱。这篇是系列第28篇,我打算从工艺需求开始,到变量设计,再到ST代码逐段拆解,最后补充仿真和现场调试的经验,完整走一遍三台电机顺起逆停的控制逻辑。适合有一定ST基础、想通过完整案例把语法点串起来的朋友参考。

1. 顺起逆停的工艺逻辑,先于代码说清楚

1.1 我为什么要专门写这个三台电机案例

前阵子有朋友在做一条输送线项目,三段皮带分别由三台电机驱动,甲方要求很明确:开机时按1号、2号、3号的顺序启动,中间间隔几秒;停机时反过来,先停3号,隔几秒再停2号,最后停1号。朋友说他在梯形图里画了几十个触点线圈,眼睛都快看花了,问我ST要怎么写才清晰。

这件事给我触动挺大。很多教材讲ST都是讲语法,什么IF、CASE、FOR,但真正到了现场需求,大家第一反应还是“梯形图能不能画出来”。其实ST的价值恰恰在这种带顺序、带延时、带联锁的逻辑上。三台电机顺起逆停,就是ST入门中一个非常典型、又能完全练到核心功底的案例,所以我专门把它单独拿出来写。

这个案例的应用场景不止输送线。水处理泵站、空压机站、物料提升设备、风机群控,都会遇到类似的顺起逆停需求。控制对象都是电机,逻辑骨架却是通用的,理解了一组,就能套到N组上。

1.2 启动要顺序,停止为什么要逆序

很多人能理解“顺起”的道理,却想不通“逆停”意义在哪。这里必须把工艺逻辑讲透,否则代码写得再漂亮,现场也是白搭。

拿三段皮带输送线举例。启动时如果先启动2号皮带,后端皮带马上开始跑,但1号皮带还没动,物料从料斗落到1号皮带上堆积,积到一定量就会堵料、压死电机。正确顺序是,1号先跑,物料到了1号和2号的交接点,2号才开始接,然后3号再接,这样整条线是“前面送、后面接”的顺畅状态。

停机时如果还按1、2、3的顺序来,就出问题了:1号皮带还在往前送料,2号皮带已经停住,料全部堆在1号尾部,下次启动就是重载启动,电机的启动电流会非常大,还可能直接卡死。所以必须先停3号,让皮带上的料全部走完或卸完,再停2号,最后才停1号,保证每一段皮带上不留料、不堆料。

再讲一个电网侧的原因。如果三台电机同时启动,整个配电回路会瞬间出现极大的启动电流,几十千瓦以上的电机还会造成母线电压明显跌落。错峰启动,把三台电机的启动瞬间岔开,对变压器和断路器都非常友好。这也是很多项目要求“顺起”的最大动机之一。

1.3 为什么这个案例特别适合ST语言

同一个控制需求,梯形图当然也能实现,但有个典型的头疼问题:三台电机要画三套启保停回路,再加上时间继电器延时的触点串联,图纸会越来越庞大。尤其到了调试阶段,想改某个延时值,还要在图纸里翻半天找对应的定时器触点。

ST的优势是,控制逻辑以纵向文本呈现,每个条件、每个定时器都是独立的行,想改哪一个,定位极其方便。而且ST里可以自由写注释,别人接手程序时,读代码就是在读你的设计思路,亲和力远胜于迷宫一样的触点网络。

还有一个现实原因,很多项目发展到后来都不是单纯启停控制,还要加故障计数、运行计时、能耗统计、参数配方。这些计算类的逻辑,如果混在梯形图里会非常笨拙,但在ST里就是几行赋值语句的事。从三台电机顺起逆停开始接触ST,正好把“顺序控制”和“结构化表达”打通。

2. 先设计信号和定时链,再动手写ST

2.1 数清楚输入输出:先把I/O表列出来

写程序之前必须先想清楚信号,尤其是真实项目的硬件信号。这个案例里,我做如下假设:启动、停止、复位按钮各一个;急停按钮一路;三台电机各自有一路故障信号(热继电器、变频器故障等);输出三路,分别控制三台电机的接触器或变频器启动端子。

变量含义类型
xStartBtn启动按钮BOOL输入
xStopBtn正常停止按钮BOOL输入
xResetBtn故障/停止链复位按钮BOOL输入
xEStop急停信号BOOL输入
xFault1 / xFault2 / xFault3三台电机故障反馈BOOL输入
xRunCmd1 / xRunCmd2 / xRunCmd3三台电机运行输出BOOL输出

注意,这里故障信号我假设是长信号。如果硬件上故障是瞬时的,比如几秒后自动消失,那程序里要想办法锁存故障状态,否则一眨眼PLC就继续往下启动了,安全隐患很大。这一点我在后面会进一步提。

另外,真实项目里我会强烈建议增加三路“运行反馈”信号,就是接触器辅助触点或者变频器运行中触点,接到PLC输入端。它们的作用是告诉你电机是否真的转了,而不是只看输出命令。这个反馈在顺起逻辑里也有用,我放到扩展那一节分享。

2.2 TON定时器是这个案例的主角

顺起逆停的核心就是时间控制,CoDeSys的TON定时器是绕不开的功能块。它的行为可以用一句话概括:当IN输入为TRUE时开始计时,计时到达PT设定时间后,输出Q变为TRUE;只要IN变回FALSE,Q会立刻变成FALSE,时间也清零。

在ST里调用TON实例,写法是:

tonStart2(IN := xRunCmd1, PT := T#5S);

调用之后,使用tonStart2.Q读取输出。这里的T#5S是TIME类型,表示5秒。要注意,不是写数字5。CoDeSys的时间字面量,秒用T#5S,毫秒用T#500MS,两者可以混着写,比如T#5S500MS。

这个案例里我一共用了5个TON定时器。启动方向2个,负责2号、3号的延时启动;停止方向3个,负责3号、2号、1号的延时停止。很多初学者觉得定时器一多就容易乱,我的经验是,给它们的命名直接体现用途:tonStart2就是“启动2号电机的定时器”,tonStop3就是“停止3号电机的定时器”。名字取清楚,程序就不容易看岔。

2.3 启动链和停止链分开写,别搅在一起

这是我给所有初学者的建议。一个程序如果能把“启动链”和“停止链”看成两套独立的逻辑,分别写成两个段落,调试的时候就会非常舒服。

启动链的逻辑是“向前推进”:按下启动按钮之后,运行记忆置位,1号电机的输出直接满足条件;1号运行信号作为2号延时启动的输入条件,2号延时到达后运行;2号运行后再触达3号的延时,实现3号的最后启动。

停止链的逻辑是“往回拉”:按下停止按钮之后,停止记忆置位,3号电机的输出先被切断(可以理解为“让它走完最后一段物料”),延时结束后再切2号,最后切1号。

为什么要拆开?因为两条链的触发源、方向、复位方式完全不一样。如果把“启动停止”揉在一个复杂的IF条件里,很容易出现“3号既要满足启动条件又要满足停止条件”的混乱局面。ST本身就是线性执行的,分段落写,条理自然就出来了。

2.4 一个扫描周期带来的滞后,怎么看待

PLC程序是按扫描周期顺序执行的,同一周期内,后面的语句能读到前面的更新值,但读不到后面还没执行到的更新值。所以ST代码的行顺序是有讲究的。

我习惯的做法是:把定时器的调用放在“读取它的Q之前”执行。就比如tonStart2要在读取tonStart2.Q之前调用,这是保证同一周期内读取到的是“本次扫描更新后的Q”。至于xRunCmd1作为tonStart2的输入,在代码里写在tonStart2调用之后才赋值,那这一个扫描周期里tonStart2读到的就是上一周期的xRunCmd1,这属于“一个扫描周期的滞后”,对秒级的延时控制毫无实际影响。

如果你是个强迫症,希望启动条件在同一个扫描周期内绝对一致,可以把输入条件展开,不引用xRunCmd1这个后赋值的输出,而是直接写成一串条件组合。不过对于咱们这个入门案例,我建议先接受这个微小的滞后,把精力放在理解逻辑链上。

3. ST程序逐段拆解:一台一台被点亮和熄灭

3.1 变量声明:哪些类型、为什么

打开CoDeSys,新建一个POU,语言选ST。程序名我就叫PLC_PRG,实际项目中你可以叫MotorSeq。首先要写变量声明。我完整贴出来:

PROGRAM PLC_PRG VAR // 输入信号 xStartBtn : BOOL; // 启动按钮 xStopBtn : BOOL; // 正常停止按钮 xResetBtn : BOOL; // 复位按钮 xEStop : BOOL; // 急停信号 xFault1 : BOOL; // 1号电机故障 xFault2 : BOOL; // 2号电机故障 xFault3 : BOOL; // 3号电机故障 // 输出信号 xRunCmd1 : BOOL; // 1号电机运行命令 xRunCmd2 : BOOL; // 2号电机运行命令 xRunCmd3 : BOOL; // 3号电机运行命令 // 按钮边沿检测 fbStartR : R_TRIG; // 启动按钮上升沿 fbStopR : R_TRIG; // 停止按钮上升沿 bStartP : BOOL; // 启动脉冲 bStopP : BOOL; // 停止脉冲 // 模式记忆 bRunMem : BOOL; // 运行模式记忆 bStopMem : BOOL; // 停止模式记忆 // 定时器实例 tonStart2 : TON; // 2号启动延时 tonStart3 : TON; // 3号启动延时 tonStop3 : TON; // 3号停止延时 tonStop2 : TON; // 2号停止延时 tonStop1 : TON; // 1号停止延时 END_VAR

这里有个细节:为什么用R_TRIG而不直接判断按钮值?因为如果按钮持续按着不松开,直接判断IF xStartBtn THEN的话,运行记忆可能在一个扫描周期内反复被置位,甚至如果不加互锁还会导致停止逻辑和启动逻辑打架。R_TRIG的输出Q只在一个扫描周期内为TRUE,相当于把“按下按钮”变成了“按下按钮的瞬间”。

3.2 按钮边沿和模式记忆:先处理启动停止的“总开关”

逻辑体第一部分,处理按钮边沿,并记忆运行和停止的模式。我写:

// 1. 按钮边沿:只响应按下瞬间 fbStartR(CLK := xStartBtn); bStartP := fbStartR.Q; fbStopR(CLK := xStopBtn); bStopP := fbStopR.Q; // 2. 运行/停止模式记忆 bRunMem := (bRunMem OR bStartP) AND NOT bStopP AND NOT xEStop; bStopMem := (bStopMem OR bStopP) AND NOT xEStop AND NOT xResetBtn;

解释一下bRunMem。刚按下启动的瞬间,bStartP为TRUE,所以bRunMem变成TRUE。此后bStartP消失,但bRunMem OR bStartP维持住自锁,所以bRunMem会一直保持。只有在停止脉冲来了、或者急停动作时,AND NOT...把bRunMem拉成FALSE,运行模式才结束。

bStopMem的逻辑同理。按下停止按钮后,bStopMem被置位并保持,它负责驱动整个逆停链完整执行。只有按下复位按钮xResetBtn,或者急停时,bStopMem才会被清零。为什么要这样?因为逆停必须是一个完整的“3停→2停→1停”过程,不能让中间任何一个环节被打断。如果停止按钮是边沿信号,那么等逆停链走到一半,启动条件又开始生效,系统就乱了。所以必须有一个停止模式记忆罩住整个逆停过程。

有个细节我要提醒:真实项目中,xResetBtn可能同时也要清除故障锁存。我这里为了保持代码简洁,只让它清除bStopMem,项目里你可以扩展。

3.3 顺启链代码:前面的亮了,后面的才跟着启动

接下来就是本次案例的核心了——怎么把1号、2号、3号按顺序点亮。启动链的定时器我这样写:

// 3. 顺启链定时器 tonStart2(IN := xRunCmd1 AND NOT xFault2, PT := T#5S); tonStart3(IN := xRunCmd2 AND NOT xFault3, PT := T#5S);

然后是三台电机输出的赋值:

// 5. 输出赋值 xRunCmd1 := bRunMem AND NOT xFault1 AND NOT tonStop1.Q; xRunCmd2 := tonStart2.Q AND NOT xFault2 AND NOT tonStop2.Q; xRunCmd3 := tonStart3.Q AND NOT xFault3 AND NOT tonStop3.Q;

一行行读。

xRunCmd1的条件:运行模式为真,1号没有故障,并且逆停链还没把1号停掉(tonStop1.Q为FALSE)。这三个条件同时满足,1号立即得电。因为它的启动条件里没有延时,所以只要bRunMem置TRUE,1号就是这个扫描周期里第一个启动的。

xRunCmd2的条件:tonStart2.Q已经变TRUE,说明“延时5秒”已经走完。另外要求2号没有故障、逆停链还没停到2号。tonStart2的IN是什么?是xRunCmd1。也就是说,只有1号已经在运行,tonStart2才开始计时。这保证了严格的顺启顺序:1号必须亮,2号的5秒才算数。

xRunCmd3同理,只有2号在运行了,tonStart3才开始计时,5秒之后3号才得电。

这里我可以提一个现场升级点:如果你硬件上有接触器运行反馈,强烈建议把tonStart2的IN从xRunCmd1改为xRunFb1。因为xRunCmd1只是“你给了输出命令”,但万一接触器没吸合,或者电机因为堵转没真正转起来,你觉得它启动了,实际上它只是在命令上亮了。换成反馈信号后,只有电机真的转起来,下一台的延时才开始计时,更可靠。

3.4 逆停链代码:从末端开始延时断开发令

逆停链的代码放在顺启链之后,但它的作用是“往后覆盖”启动状态。我把代码写成这样:

// 4. 逆停链定时器 tonStop3(IN := bStopMem, PT := T#5S); tonStop2(IN := tonStop3.Q, PT := T#5S); tonStop1(IN := tonStop2.Q, PT := T#5S);

我们来推演时间轴。

按下停止按钮后,bStopMem变TRUE。tonStop3的IN变TRUE,开始计时5秒。5秒后tonStop3.Q变TRUE。回到输出赋值那一段,xRunCmd3的条件里带了一个NOT tonStop3.Q,此时变成FALSE,于是3号输出被切断。

tonStop2的IN是tonStop3.Q。换句话说,只有当“3号停车的定时器”已经完成,tonStop2才开始计时。再等5秒,tonStop2.Q变TRUE,2号输出被切断。再往后,tonStop1才开始计时,5秒后,1号输出被切断。

所以停止时间轴是: 按下停止按钮后的第0秒:三台照常运行; 第5秒:3号断开; 第10秒:2号断开; 第15秒:1号断开。

这就是标准的“逆停”而非“同时停”或“顺序停”。

为什么停止链不用“启动链的反向条件”去控制,而是专门开三个定时器?因为要保证停机的节奏一定是从3到2到1,不能出现“按下停止后,因为启动链还在活跃,某台又意外重新启动”的情况。停止定时器的IN是独立的bStopMem,不依赖启动链状态,所以停止链一旦开始,就会稳定地按顺序往下执行。

3.5 急停、故障和复位:最高优先级的保护

故障的处理其实已经在输出条件里体现了。比如xRunCmd2包含AND NOT xFault2,如果2号电机的热继电器跳了,它的输出立即断开。更关键的是连锁反应:2号停止后,xRunCmd2变成FALSE,tonStart3的IN即xRunCmd2变成FALSE,tonStart3.Q立即清零,所以3号也立刻失去输出条件,会在同一时间断开。也就是说,中间某台电机故障,会导致它后面的电机跟随停车,而前面的电机因为不受这个故障条件限制,会继续运行。这个逻辑符合一般工艺要求:口诀是“故障机后面全停,前面能扛就扛”。

当然,如果工艺要求“任何一台故障,全线都停”,那你需要把故障信号做一个全局汇总,把它加进三台输出里,我这里不做展开。

急停是另一件事。我把它放在程序最末尾,用最高优先级的方式单独处理:

// 6. 急停最高优先级,直接切断所有输出 IF xEStop THEN xRunCmd1 := FALSE; xRunCmd2 := FALSE; xRunCmd3 := FALSE; END_IF;

之所以放在最后,是因为ST程序按行顺序执行,最后赋值的语句等于覆盖前面所有赋值结果。这样无论前面的逻辑怎么把输出置成TRUE,只要xEStop为TRUE,执行到结尾时输出都会被强制拉成FALSE。这比前面的条件里到处挂“AND NOT xEStop”更干净,也更不容易漏掉。

急停同时也要清空bRunMem和bStopMem,这个在前面的记忆逻辑里已经做了:bRunMem的赋值带AND NOT xEStop,bStopMem也带AND NOT xEStop。紧急情况下,不给你走5秒逆停,马上全切,这才是急停该有的样子。现场硬接线安全回路也一定要有,不能只依赖PLC软逻辑,那是保命的东西。

4. 仿真验证与现场调试的几个坑

4.1 在CoDeSys仿真里怎么把时序跑通

代码写完后,不要急着直接灌到PLC里,先在CoDeSys自带的仿真环境里跑一遍。仿真模式切换很简单,工具栏里选“仿真启动”,然后在登录模式下启动程序。我建议直接把按钮变量当作软变量,用变量强制功能来模拟按钮动作。

操作顺序我可以给你复现一遍:

  1. 将xStartBtn强制为TRUE,然后立刻再强制回FALSE。这一步就是模拟“按一下启动按钮”,触发R_TRIG的上升沿。
  2. 观察bRunMem变为TRUE,随后xRunCmd1变为TRUE。
  3. 不再做任何操作,等5秒,观察xRunCmd2变为TRUE;再等5秒,xRunCmd3变为TRUE。至此,顺启完成。
  4. 将xStopBtn强制为TRUE再变回FALSE,模拟按下停止按钮。
  5. 观察xRunCmd3在5秒后断开,再过5秒xRunCmd2断开,再过5秒xRunCmd1断开。逆停完成。

在仿真里,CoDeSys还有一个非常好用的功能,就是“跟踪”视图,可以像示波器一样把xRunCmd1、xRunCmd2、xRunCmd3的变化曲线画出来。这样你就能直观地看到三台电机输出在时间轴上“阶梯式上升、阶梯式下降”的样子,排查问题比肉眼盯变量快得多。

有一点要注意,仿真环境里的定时器精度依赖于任务周期。如果任务周期设置成10毫秒,TON的精度也就是10毫秒的倍数。这种秒级延时的程序,任务周期设置到10ms或者50ms都没问题,但如果你改了任务周期,定时器的实际延时可能和你设定值有偏差,调试时心里要有数。

4.2 定时时间不是拍脑袋,要按工艺来整定

我见过太多新手,把5秒、10秒这些时间当成“大概差不多”就写进程序,结果到了现场发现皮带上的物料跑不完或者管道压力还没建起来。延时时间必须有依据。

以一个典型的三段皮带线为例: 启动间隔要参考前一段皮带从启动到把料送到下一段接料点的时间,一般观察正常给料下物料到达交接点的时间,再留1到2秒的裕量。停止间隔要参考物料在本段皮带上完全卸完的时间,也要留裕量。

对于水泵组,启动间隔可能取决于出口阀从全关到全开的动作时间;对于空压机群控,停止间隔可能取决于系统压力稳定时间。这些参数必须和工艺沟通,从现场实测或设备资料中获取,不能我在这里给你一个“默认5秒”就当万能答案。程序里我把所有PT都用T#5S,只是为了演示,真实项目你会看到启动和停止两套延时参数很可能不一样。

这里有一张参考表,是我在不同场景下的整定经验,仅供参考:

应用场景启动间隔参考停止间隔参考
皮带输送线5-10s,视皮带速度与长度3-8s,视物料卸空时间
水泵组3-8s,视出口阀动作时间1-5s,注意水锤
空压机群控5-15s,视压力建立速度3-10s,逐台卸载
风机群控5-10s5-10s,视风道压力

4.3 现场最容易翻车的五个细节

第一个坑:停止按钮用常闭触点。有些安全电路里停止按钮是常闭串在回路里的,接到PLC普通输入后,按钮没按时输入是TRUE,按下去反而是FALSE。如果你的程序里没有取反,那按下停止时看到的就是“信号消失”而不是“信号到来”,R_TRIG永远检不到上升沿,系统根本不会进入逆停流程。解决方法是,要么硬件改成常开输入,要么程序里xStopBtn := NOT xStopBtnA;做一次取反,然后再接R_TRIG。

第二个坑:双线圈输出。我见过有人在程序前半部分写xRunCmd1 := ...,后半部分为了急停又写一次xRunCmd1 := FALSE;。这在ST里其实是允许的,但后面的赋值会覆盖前面的,容易造成代码里同一个输出有多处逻辑,稍不留神就出现“明明条件满足了输出却还是断的”之类的怪问题。我的建议是,一个物理输出在一个程序里最好只出现一次赋值,急停这种例外,也要放在最末尾并加注释说明。

第三个坑:启动前没有检查“停止链是否走完”。如果按下停止后,在逆停链还没走到最后时,有人又按了启动,会发生什么?bStopMem还在TRUE,它的优先级高于bRunMem,所以系统不会立刻启动,必须等逆停链全部完成、bStopMem被xResetBtn清掉,才能再启动。这是一个安全特性,但如果你没有做任何状态提示,操作员可能以为设备坏了。要么在HMI上做一个“正在停机,请等待”的提示,要么在启动条件里用bStopMem做明确互锁并告诉操作员原因。

第四个坑:急停只做软件处理,没有硬接线安全回路。PLC程序再怎么可靠,也扛不住CPU死机、通讯中断、接触器卡死。急停回路必须用硬接线直接切断接触器线圈或者变频器使能,PLC程序里的急停逻辑只是第二道防线。这一点我在现场反复强调,安全无小事。

第五个坑:把HMI的“保持型”按钮当成了“脉冲型”按钮。HMI里很多按钮控件有“置位”、“复位”、“切换”三种操作模式。如果你把启动按钮做成了切换模式,按下后它一直为TRUE,那R_TRIG只能检测到第一次的上升沿,第二次再用可能就要先把按钮置FALSE再置TRUE才能触发。这个容易让操作员觉得“按钮不灵”,其实是你变量属性选错了。

5. 从三台到N台:这套逻辑还能怎么扩张

5.1 用数组和FOR循环批量管理

三台电机手写还吃得消,如果项目里是八台、十台、二十台风机,再一行行复制就太蠢了。工程上处理批量设备的惯用手法是用数组加循环。

声明一组定时器数组和BOOL数组:

VAR aRunCmd : ARRAY[1..10] OF BOOL; aRunMem : ARRAY[1..10] OF BOOL; aFault : ARRAY[1..10] OF BOOL; aTonStart : ARRAY[1..10] OF TON; aTonStop : ARRAY[1..10] OF TON; iMotor : INT; END_VAR

启动逻辑就可以写成:

FOR iMotor := 2 TO 10 DO aTonStart[iMotor](IN := aRunCmd[iMotor - 1] AND NOT aFault[iMotor], PT := T#5S); aRunCmd[iMotor] := aTonStart[iMotor].Q AND NOT aFault[iMotor] AND NOT aTonStop[iMotor].Q; END_FOR;

这里我还是要提醒:CoDeSys里ARRAY[1..10] OF TON是允许的,循环内使用数组下标访问不同实例也合法。不过FOR循环里的iMotor - 1要小心,如果iMotor从1开始,会发生下标0越界,所以我从2开始。这种写法适合需要统一延时的批量设备。如果每台设备的延时时间不一样,你还要再准备一个时间参数数组。

5.2 用运行反馈替代输出命令,可靠性差一个量级

我再强调一次,现场真实项目里,如果条件允许,优先用“运行反馈”去做下一级的启动条件。改造方法很简单,加三个反馈输入变量xRunFb1、xRunFb2、xRunFb3,然后把上一级输出条件换成反馈:

tonStart2(IN := xRunFb1 AND NOT xFault2, PT := T#5S); tonStart3(IN := xRunFb2 AND NOT xFault3, PT := T#5S);

这样做的意义在于:就算PLC已经输出xRunCmd1,但接触器实际没吸合、或电机卡住没转,下一台电机也不会盲目启动。尤其是那种“启动后必须确认上一台电机建立了流量或压力”的工艺,比如泵组,用一个压力开关或流量开关反馈,比用接触器辅助触点还要更贴近工艺。

5.3 和SFC顺序功能图的对比

这里顺带聊一句SFC。三台电机顺起逆停也可以拆成SFC步进方式:第一步启动1号,切换条件为定时到,进入第二步启动2号,再切第三步启动3号;停机时进入停止步,逐级退出。SFC的好处是图形化,状态切换一目了然,适合纯顺序控制。

我的个人倾向是:步数少、状态切换明了的用SFC没问题,但一旦控制对象是成组、成批的设备,或者需要和大量数据运算、配方逻辑混编,ST加数组的方式会更灵活。这套三台电机的ST案例练下来,你就把变量声明、边沿检测、自锁记忆、TON定时器、联锁、急停、复位这些ST最核心的东西全串了一遍。后面再遇到更复杂的控制需求,至少不会怵了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询