尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ST语言定时器全解析:TON/TOF原理、应用与排错技巧

ST语言定时器全解析:TON/TOF原理、应用与排错技巧 做PLC项目的人应该都有同感梯形图里最常用的指令除了常开常闭触点就是定时器。我刚从梯形图转ST语言那会儿最别扭的就是定时器——梯形图里拖一个TON框出来填个时间就完事换成ST之后不少人第一反应是“这玩意儿还能不能用”。答案是当然能而且用熟了比梯形图灵活得多。这篇实战笔记就专门聊ST语言里的TON、TOF从工作原理、标准写法到三个高频应用场景最后把定时器不动作、不复位、时序竞争这些坑一次说清楚。适合刚接触ST语言、或者一直在梯形图里写定时逻辑想换换思路的朋友。1. 定时器在PLC控制里的位置别把时间逻辑写死1.1 为什么项目里到处是定时器在任何一条产线控制程序里你几乎找不到一个完全不用定时器的项目。电机启动前先开风机要延时星三角启动的星角切换要延时传送带停机后警示灯要延时熄灭气缸动作之间要避免同时得电连报警信号都需要延时确认防止现场抖动误报。这些东西如果用梯形图的传统写法每加一路延时逻辑就要拖一个定时器框、引一条复位线程序一大看着就累。ST语言里处理这些时间是另一种思路。它把“时间”当成数据来处理定时器输入接BOOL信号设定时间是一个TIME类型的变量而不是梯形图里那个藏在框里的固定数值。这意味着你可以把延时时间做成HMI变量操作工在触摸屏上直接改程序一行不用动。还有一个很多人没意识到的好处ST语言里的TON、TOF都是IEC 61131-3标准定义的功能块。你在西门子博途的SCL里怎么用在Codesys里基本还是那么用汇川、信捷、台达这些支持IEC标准的PLC也大同小异。换句话说学会这一套换个品牌PLC你的定时器知识不用重学。1.2 TON、TOF、TP、TONR到底怎么选初学者最容易卡住的就是“我该用哪个定时器”。先看一张对照表类型名称动作特点典型场景TON通电延时输入ON持续到设定时间后输出才变ON延时启动、时序联锁TOF断电延时输入OFF后输出继续ON保持设定时间再OFF延时停止、滑行警示TP脉冲输入一触发输出ON固定时长与输入ON多久无关单次脉冲输出TONR累计延时输入ON的时间累计到点输出ON可复位累计运行时间、维护提醒选型的时候其实只需要问自己一个问题我要延长的是信号的上升沿还是下降沿如果条件是“启动信号来了等5秒再动作”那是上升沿要延后用TON。如果条件是“停止信号到了设备还要再转10秒才真正停”那是下降沿要延后用TOF。两个方向搞清楚了选型就完成了一大半。TP和TONR属于进阶用法本文先不展开但上面这张表可以留着以后查。2. 把TON和TOF的内部机制吃透2.1 TON的工作时序TON全称On-Delay Timer中文叫通电延时定时器。它的输入端是IN输出端是Q设定时间是PT还有当前计时值ET。工作过程分三段理解就够了。第一段IN为FALSE时ET等于0Q等于FALSE定时器就是静止的。第二段IN从FALSE变成TRUEET开始从0往上计时。当ET计到大于等于PT时Q变成TRUE然后ET会停在PT不再往上走直到IN断开。第三段如果IN在ET还没到PT的时候变回了FALSE那么ET立刻清零Q始终为FALSE。这里有个关键点很多人忽略TON只对上升沿做延时它不管下降沿。输入一断输出立刻跟着变FALSE中间没有任何保持。如果你需要“输入断了输出再保持一会儿”那应该选TOF而不是在TON后面硬凑逻辑。2.2 TOF的工作时序TOF全称Off-Delay Timer断电延时定时器。它的引脚和TON一样但动作逻辑正好相反。当IN变为TRUE时Q立刻变为TRUE没有延时同时ET清零。当IN从TRUE变成FALSE时Q不会马上变FALSE而是保持TRUEET从0开始计时。当ET计到大于等于PT后Q才变为FALSEET停在PT。如果在计时过程中IN又变回了TRUE那么ET立即清零Q继续保持TRUE。理解TOF的关键词是“滞后”它让信号的关断变得平缓。产线上很多设备都有惯性比如传送带停了滚筒还在转、风机停了叶片还在转这时候用TOF给警示灯留出延时熄灭的时间比在程序里写一堆“停止计数”逻辑干净得多。2.3 定时精度和扫描周期到底是什么关系聊到这里必须澄清一个问题PLC里的TON/TOF定时器精度受扫描周期影响。它不是一个独立的硬件计时器而是每个扫描周期由CPU执行一次功能块逻辑。ET的累加本质上是“这个功能块被执行了多少次、每次间隔多少时间”的累计。所以实际延时误差大概在一个扫描周期左右。做普通产线逻辑扫描周期一般10毫秒到几十毫秒延时精度完全够用。但如果你要做的是高频脉冲测量、精确到毫秒以下的时序控制那靠TON/TOF是不够的得用带中断的任务或者硬件高速定时器那是另一个赛道。顺带说一句社交平台上经常看到的“STM32定时器”讲的也是硬件定时器和PLC里的TON/TOF功能块不是一回事别混在一起学。3. 实操5分钟写完三个高频场景3.1 场景一电机启动前先开风机TON延时启动先看一个最常见的需求按下启动按钮风机立即启动5秒后电机才合闸让风机先把风道吹起来。PROGRAM MotorStart VAR xStartBtn : BOOL; // 启动按钮 xFanRun : BOOL; // 风机运行 xMotorRun : BOOL; // 电机运行 fbFanDelay : TON; // 延时合闸定时器 tPreFanTime : TIME : T#5S; // 提前5秒 END_VAR // 风机直接跟随启动信号 xFanRun : xStartBtn; // 启动信号保持5秒后电机才允许合闸 fbFanDelay(IN : xStartBtn, PT : tPreFanTime); xMotorRun : fbFanDelay.Q;这段代码的逻辑很简单xFanRun直接等于启动按钮没有延时fbFanDelay这个TON的IN接的也是同一个启动按钮设定时间5秒。启动按钮一按风机先动定时器开始计时5秒后Q变TRUE电机接触器才得电。这里有两件事值得说。第一IN不一定要接一个按钮信号它可以是任意BOOL表达式比如“启动按钮 AND 没有急停 AND 门关到位”这就把联锁条件直接揉进了定时器的使能信号里。梯形图里得串好几级触点ST里一行写完。第二PT用的是TIME类型写T#5S表示5秒注意格式T#2S是2秒T#100MS是100毫秒T#3M30S是3分30秒。千万别写成数字5类型不匹配编译都过不了。3.2 场景二传送带停止后的警示灯延时熄灭TOF第二个场景传送带正常运行时它的状态信号是TRUE这时候警示灯常亮。传送带停止后由于滚筒和物料还有惯性禁止后方操作员靠近警示灯要继续亮10秒再熄灭。PROGRAM ConveyorStop VAR xConveyorRun : BOOL; // 传送带运行反馈 xWarnLamp : BOOL; // 警示灯 fbStopDelay : TOF; // 停机延时定时器 END_VAR fbStopDelay(IN : xConveyorRun, PT : T#10S); xWarnLamp : fbStopDelay.Q;注意这里用的是TOF。传送带运行信号从TRUE变成FALSE的那一刻TOF的Q并不会立即变FALSE而是保持TRUE继续计时10秒计时结束后Q才变FALSE警示灯熄灭。整个过程只需要两行代码没有额外的计数器没有置位复位干净利落。如果这个逻辑用TON来写会怎样你需要在停止信号出现时去启动另一个定时器还要处理重复启动的问题。虽然也能实现但代码量和踩坑概率都会增加。这就是选对定时器类型的价值。3.3 场景三用两个TON搭一个自复位脉冲驱动间歇喷吹第三个场景很典型除尘器的脉冲喷吹阀要求喷2秒、停5秒循环往复。这个逻辑用两个TON互相控制是最稳妥的写法。PROGRAM PulseGen VAR fbOnTimer : TON; // 控制输出ON的持续时间 fbOffTimer : TON; // 控制输出OFF的持续时间 xBlowValve : BOOL; // 喷吹阀输出 END_VAR fbOffTimer(IN : NOT xBlowValve, PT : T#5S); fbOnTimer(IN : xBlowValve, PT : T#2S); IF fbOffTimer.Q THEN xBlowValve : TRUE; ELSIF fbOnTimer.Q THEN xBlowValve : FALSE; END_IF;从头推一遍流程。程序刚启动时xBlowValve是FALSEfbOffTimer的IN是TRUE开始计5秒。5秒到fbOffTimer.Q变TRUExBlowValve被置TRUE。阀门打开同时fbOffTimer的IN变成FALSE自己复位而fbOnTimer的IN变成TRUE开始计2秒。2秒到fbOnTimer.Q变TRUExBlowValve被置FALSE。阀门关闭fbOnTimer复位fbOffTimer又开始计5秒如此循环。实际项目里阀门的打开还需要结合压差信号、手动自动切换等条件。做法很简单把IF条件改成“压差信号有效 AND fbOffTimer.Q”就行结构完全不用改。3.4 时间参数别写死把延时做成常量或HMI变量前面三个例子都是直接把时间写成T#5S这样的字面量。个人建议稍微复杂一点的项目把时间参数提取出来放到一个统一定义的变量区或者直接绑定HMI输入。VAR_GLOBAL T_MOTOR_PREFAN : TIME : T#5S; // 风机提前量 T_CONVEYOR_LAMP : TIME : T#10S; // 警示灯延时 T_BLOW_ON : TIME : T#2S; // 喷吹ON T_BLOW_OFF : TIME : T#5S; // 喷吹OFF END_VAR这样做的好处非常明显调试的时候操作工在触摸屏上把T_CONVEYOR_LAMP从10秒改成8秒程序不需要重新下载维护工程师看代码的时候见名知意不用去猜某个定时器里的T#12345MS是多少秒。现场设备的时间参数几乎都是要反复调的写死等于给自己挖坑。4. 常见问题与排查技巧实录4.1 定时器不动作Q一直为FALSE这是ST语言新手问得最多的问题。总结下来原因就那么几类。第一IN信号太短。如果输入信号持续的时间小于一个扫描周期定时器可能根本没扫描到这个跳变ET一直保持0。这种情况在按钮、接近开关这类瞬态信号上很常见。解决办法是把输入信号先做一次保持或锁存再送给定时器。第二同一个功能块实例被重复调用。TON是一个功能块它需要自己的实例来保存内部状态。如果你在程序里写了两处fbTimer(IN:..., PT:...)两处共用了同一个实例运行时两个地方的调用会互相干扰ET和Q的状态完全乱掉。记住一条铁律一个定时器实例只能在一个地方调用多用几个就声明几个实例。第三设定时间类型不对。有人把PT写成5而不是T#5S编译会直接报类型错误也有人写成T#5000这种可读性很差的格式。建议统一写成T#5S、T#100MS这种带单位的形式清晰又不容易错。4.2 定时器动作了但Q死活不复位Q不复位多半是IN一直保持TRUE。TON的特点是IN断开后ET清零、Q变FALSE如果你的IN是一个始终为TRUE的变量那Q当然不会复位。排查办法很简单在线监控里看IN的值。还有一种情况是把TOF的时序搞反了。TOF在IN变FALSE后才开始计时如果IN始终保持TRUETOF的Q会一直ON看起来就像“卡住了”。这时候要检查的依然是IN而不是定时器本身。再有一种隐蔽情况你在ST里对同一个变量在多个地方赋值后执行的赋值把前面定时器的结果覆盖掉了。比如代码前面写了xMotorRun : fbFanDelay.Q后面又一个IF分支里写了xMotorRun : FALSE那定时器就算到时间输出也可能被覆盖。遇到这种问题用在线监控逐行看执行结果比瞎猜快得多。4.3 定时器的调用位置和扫描顺序ST语言是从上到下顺序执行的定时器功能块在程序里放的位置会影响逻辑结果。典型错误是把使用定时器输出的判断写在了定时器调用之前。// 错误写法先用Q再调用定时器 IF fbFanDelay.Q THEN xMotorRun : TRUE; END_IF; fbFanDelay(IN : xStartBtn, PT : tPreFanTime);这样写的问题在于本次扫描执行到IF时fbFanDelay还是上一次扫描结束时的状态等于你的逻辑晚了一个扫描周期。如果只是延时输出晚一个周期可能无所谓但如果是自复位、互锁这种对时序敏感的场合一个周期的偏差就可能造成输出抖动。// 正确写法先调用定时器再读取Q fbFanDelay(IN : xStartBtn, PT : tPreFanTime); IF fbFanDelay.Q THEN xMotorRun : TRUE; END_IF;4.4 排查定时器问题的三步法遇到定时器相关故障别急着改代码先按下面三步走。第一步看输入。在线监控IN到底是TRUE还是FALSE是不是一直在抖动是不是存在保持时间太短的问题。输入信号没问题再看下一步。第二步看ET和PT。ET有没有在涨涨到哪里停了和PT的差距是多少。ET不涨说明定时器没被激活或没被执行ET涨到PT但Q没出来说明问题在调用顺序或输出被覆盖。第三步看任务周期。在组态里确认程序所在任务的循环周期如果任务周期是50毫秒而你的延时精度要求是10毫秒以内那这个定时器天生就不合格得换用更快的任务或中断。顺手整理了一张速查表排查时对照着看现象可能原因排查动作Q一直FALSEET为0IN没有持续超过扫描周期检查输入信号宽度必要时做锁存Q一直FALSEET在涨但不到PTPT过大或IN中途断开在线看ET、PT、IN三者的变化Q一直是TRUE复位不了IN始终为TRUE或TOF时序理解错检查IN的在线值输出不定期抖动定时器实例被多处调用检查是否有重复调用同一实例结果比预期晚或早一个周期调用顺序不正确把定时器调用放在读取Q之前5. 从梯形图迁到ST的几条实战建议5.1 定时器实例化管理别吝啬变量梯形图时代很多人习惯一个定时器框改改时间就到处复制。到了ST语言复制粘贴定时器代码却不改实例名是最容易埋雷的。建议养成习惯每个功能性延时都单独声明一个实例名字起得直白一点比如fbFanDelay、fbConveyorLampDelay、fbBlowOnTimer。代码一多这种命名的优势会非常明显。5.2 时间参数集中管理上一节提到的全局常量做法建议推广到整个项目。所有延时时间集中放在一个全局变量列表里HMI能改的标成对应映射变量不能改的用常量。这样现场改动需求来了你不需要翻遍整个程序找定时器。维护老项目的时候这一条能帮你省下大量时间。5.3 软定时器解决不了的场景大胆换方案TON/TOF不是万能的。需要精确到毫秒以下的高频控制用支持中断的任务或硬件定时器需要累计设备运行时间做保养提醒用TONR加重置需要定时触发一个固定宽度的脉冲可以考虑TP。选型选错了再怎么写也是给自己添堵。我在实际项目里踩过的最深的一个坑就是刚开始用ST时把同一个定时器实例在FB和主程序里各调用了一次结果设备启动时间忽长忽短查了整整一个下午。从那以后我给自己立了一条规矩定时器实例是谁的就在谁的代码段里调用绝不在其他地方碰它。这个习惯帮我省下的排查时间远比刚开始多写几个实例声明要值。ST语言的定时器其实不难把TON、TOF的时序吃透多写几个场景你很快就会发现原来梯形图里那些绕来绕去的延时逻辑在ST里几行就写完了。
返回列表