ST怎么写定时器延时:实例化 TON 并设置 .IN 条件和 .PT 时间

发布于 2026-03-14 22:56:39 · 浏览 3 次 · 评论 0 条

在结构化文本(ST)编程中,使用 TON(On-Delay Timer,接通延时定时器)实现精确延时是最基础也最频繁的操作。它不依赖硬件继电器,完全由 PLC 扫描周期和内部时基驱动,稳定、可复用、易调试。以下内容全程基于 IEC 61131-3 标准,适用于 Siemens TIA Portal(S7-1200/1500)、Codesys、B&R Automation Studio、Phoenix Contact PLC 等主流平台,所有代码均可直接复制粘贴运行。


一、TON 的本质:三个核心接口

TON 不是“函数”,也不是“指令块”,而是一个预定义功能块(FB)类型,必须先声明变量再实例化。它的行为由三个关键引脚控制:

引脚名 数据类型 作用说明
.IN BOOL 启动信号:上升沿触发计时FALSE 时自动复位 .Q 并清零 .ET
.PT TIME 预设时间值:必须为标准时间格式,如 T#5ST#100MST#2.5S
.Q BOOL(只读) 输出信号:.IN = TRUE.ET >= .PT 时变为 TRUE,否则为 FALSE
.ET TIME(只读) 已耗时间:从 .IN 上升沿开始累加,单位与 .PT 一致,最大值为 T#24D_20H_31M_23S_647MS

⚠️ 注意:.IN电平敏感而非边沿敏感——但 TON 内部自动检测上升沿启动计时,因此你只需保持 .INTRUE 即可持续计时;若 .IN 中途变 FALSE.ET 立即归零,.Q 立即变 FALSE


二、四步完成 TON 实例化(无错误写法)

1. 声明 TON 实例变量(全局或局部)

在程序组织单元(POU)的 VAR 区声明一个具名实例,不能直接调用 TON() 而不声明变量:

VAR
    myTimer: TON; // ✅ 正确:声明一个名为 myTimer 的 TON 实例
    // timer1: TON(); // ❌ 错误:语法非法,ST 不支持匿名实例化
END_VAR

💡 命名建议:用动词+功能命名,如 motorStartDelaysafetyGuardConfirmconveyorStopHold,避免 t1timer_01 等无意义名称。

2. 设置 .PT(预设时间)——必须使用标准 TIME 字面量

.PT 必须赋值为 TIME 类型常量,不可用整数、实数或字符串代替:

myTimer.PT := T#5S;        // ✅ 5 秒
myTimer.PT := T#100MS;     // ✅ 100 毫秒
myTimer.PT := T#2S_500MS;  // ✅ 2.5 秒(支持复合格式)
myTimer.PT := T#0.1S;      // ❌ 错误:ST 不支持小数点前缀写法,会编译失败
myTimer.PT := 5000;        // ❌ 错误:5000 是 INT,非 TIME 类型,类型不匹配
myTimer.PT := 'T#5S';      // ❌ 错误:字符串无法隐式转 TIME

🔍 时间单位缩写表:

  • MS:毫秒(1 ms = 0.001 s)
  • S:秒
  • M:分钟
  • H:小时
  • D:天
    全部区分大小写,msSec 均无效。

3. 连接 .IN(启动条件)——支持任意 BOOL 表达式

.IN 可接单个变量、逻辑运算结果或复杂判断,只要最终为 BOOL

// 场景1:按钮按下启动延时
myTimer.IN := startButton AND NOT motorRunning;

// 场景2:温度超限后延时报警(防抖)
myTimer.IN := temperature > 85.0;

// 场景3:多条件串联(所有满足才启动)
myTimer.IN := (doorClosed = TRUE) AND (emergencyStop = FALSE) AND (modeAuto = TRUE);

// 场景4:复位后重新允许启动(典型启保停逻辑)
myTimer.IN := startCommand AND NOT myTimer.Q AND NOT faultActive;

✅ 关键点:.IN 在每次扫描周期都被读取;TON 内部自动识别 第一个扫描周期内由 FALSE → TRUE 的跳变 作为计时起点。

4. 调用实例(执行计算)——必须显式调用

声明和赋值完成后,必须在代码体中调用该实例,否则 .Q.ET 不会更新:

// ✅ 正确:调用 myTimer 实例,触发内部逻辑
myTimer();

// ❌ 错误:仅赋值不调用 → 计时器永远静止
// myTimer.PT := T#3S;
// myTimer.IN := TRUE;
// (缺少 myTimer(); 这一行)

调用位置建议放在主程序循环末尾或独立定时器处理段,确保每周期执行一次。


三、完整可运行示例:电机启动延时保护

以下是一个工业现场真实可用的 ST 代码段,实现“按下启动按钮后延时 3 秒启动电机,期间任意松开按钮则取消”:

PROGRAM MotorControl
VAR
    startButton: BOOL;      // 硬件输入:启动按钮(常开)
    motorRunning: BOOL;      // 输出状态反馈(来自接触器辅助触点或驱动器反馈)
    motorCmd: BOOL;          // 电机控制输出(DO 点)

    startDelay: TON;         // 实例化延时定时器
END_VAR

// 步骤1:设置预设时间 → 3 秒
startDelay.PT := T#3S;

// 步骤2:设置启动条件 → 按钮按下 且 电机未运行
startDelay.IN := startButton AND NOT motorRunning;

// 步骤3:执行定时器逻辑(必须!)
startDelay();

// 步骤4:输出控制逻辑
// 当延时完成(.Q = TRUE)且无故障时,输出电机命令
motorCmd := startDelay.Q AND NOT overTemperature AND NOT driveFault;

// (可选)复位后清除延时状态:无需手动操作,TON 在 .IN = FALSE 时自动复位

🔍 执行时序详解(假设扫描周期 10 ms):

扫描周期 startButton startDelay.IN startDelay.Q startDelay.ET 说明
1 TRUE TRUE FALSE T#0MS 检测到上升沿,开始计时
2–299 TRUE TRUE FALSE T#10MST#2980MS 每周期累加 10 ms
300 TRUE TRUE TRUE T#3000MS .ET == .PT.QTRUE
301+ TRUE TRUE TRUE T#3000MS(锁存) .ET 停止增长,.Q 保持 TRUE
若第 150 周期 startButtonFALSE IN=FALSE .Q=FALSE, .ET=0 立即复位

✅ 验证技巧:在监控表(Watch Table)中添加 startDelay.QstartDelay.ET,手动切换 startButton,观察 .ET 是否从 0 开始线性增长,.Q 是否在目标时间点准确翻转。


四、常见错误及修正对照表

错误现象 错误代码片段 原因分析 正确写法
定时器不动作 TON().IN := TRUE; 未声明实例变量,试图匿名调用 delay1: TON;delay1.IN := TRUE; delay1();
编译报错 “type mismatch” timer.PT := 5000; 将整数赋给 TIME 类型 timer.PT := T#5000MS;T#5S
延时时间不准 timer.PT := T#0.5S; 小数点格式非法 timer.PT := T#500MS;
.Q 一闪即逝 timer.IN := buttonPulse; 使用脉冲信号(单周期 TRUE),.IN 下一周期即 FALSE,导致 .ET 归零 改用自锁逻辑:timer.IN := buttonPulse OR timer.Q; 或外接置位信号
多个定时器互相干扰 TON1(), TON2(); 但共用同一变量名 变量名重复或未分别声明 delayHeat: TON; delayCool: TON; 分开声明并分别调用

五、进阶技巧:动态修改延时、级联延时、防抖滤波

▪ 动态修改 .PT(运行时调整)

只要在调用 ton() 之前 修改 .PT,新值立即生效(下次计时起用):

// 根据模式选择延时
IF modeHighSpeed THEN
    conveyorDelay.PT := T#200MS;
ELSIF modeLowSpeed THEN
    conveyorDelay.PT := T#800MS;
END_IF;
conveyorDelay.IN := productDetected;
conveyorDelay(); // 调用后按新 .PT 计时

▪ 两级延时(先等 2 秒,再等 5 秒)

利用前一级 .Q 触发下一级 .IN

stage1: TON;
stage2: TON;

stage1.PT := T#2S;
stage1.IN := processStart;
stage1();

stage2.PT := T#5S;
stage2.IN := stage1.Q; // stage1 完成后启动 stage2
stage2();

▪ 按钮消抖(100 ms 硬件滤波)

debounceBtn: TON;
debounceBtn.PT := T#100MS;
debounceBtn.IN := rawButtonInput; // 直接接硬件信号
debounceBtn();
cleanButton := debounceBtn.Q; // 仅当稳定按下 ≥100ms 才输出

六、TON 与 TOF / TP 的关键区别(避免误用)

功能块 触发方式 复位方式 典型用途 .QTRUE 条件
TON .IN 上升沿启动 .IN = FALSE 启动延时、就绪确认 .ET >= .PT
TOF(Off-Delay) .IN 下降沿启动 .IN = TRUE 停机延时、缓冲关闭 .INFALSE.ET >= .PT
TP(Pulse Timer) .IN 上升沿启动 .ET >= .PT 后自动复位 生成固定宽度脉冲 .IN = TRUE.ET < .PT(即启动后整个时间段内为 TRUE

⚠️ 切勿用 TON 实现“断电延时”——应选 TOF;切勿用 TON 生成脉冲——应选 TP


七、性能与资源注意事项

  • 每个 TON 实例占用约 12–16 字节内存(取决于平台),无上限限制,但建议单个 POU 不超过 200 个以保障扫描周期。
  • .ET 为 64 位有符号整数(单位:毫秒),最大计时 T#24D_20H_31M_23S_647MS,超出将溢出归零(极罕见)。
  • 所有 TON 共享 PLC 系统时钟,不受扫描周期波动影响(即使扫描周期从 10 ms 波动到 50 ms,延时精度仍为 ±10 ms)。

八、调试黄金法则(3 分钟定位问题)

  1. .IN:用强制功能(Force)将 .IN 设为 TRUE,观察 .ET 是否从 0 开始增长;
  2. .PT:确认值为合法 TIME 类型,且数值合理(如 T#0S 会导致 .Q 瞬时置位);
  3. 验调用:检查是否遗漏 instance(); 行,这是 70% 的“不动作”问题根源;
  4. .Q.QTRUE 后,.INFALSE 会立刻使其变 FALSE —— 若需保持,需外加自锁逻辑。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文