4、PLC编程基础(二):定时器指令(TON、TOF、TP)、计数器指令(CTU、CTD)、比较指令应用

好,咱们接着聊PLC编程基础的第二部分。上一章我们把位逻辑指令讲透了,这一章要上点硬货——定时器、计数器和比较指令。这三样东西,说白了就是PLC程序里的“时间管家”、“事件计数器”和“决策大脑”。我做了这么多年项目,可以说90%以上的逻辑控制都离不开它们。

4.1 定时器指令:TON、TOF、TP

定时器这东西,你想想看,就是让PLC学会“等一会儿”。但怎么等、等多久、什么时候开始计时,这里面门道可不少。IEC 61131-3标准里定义了三种基本定时器:TON、TOF和TP。我建议你先把这三种吃透,因为几乎所有品牌的PLC都支持它们。

4.1.1 TON(接通延时定时器)

TON是最常用的定时器。它的逻辑很简单:输入信号从0变1(上升沿)时开始计时,计时时间到,输出就置1。如果计时过程中输入变回0,定时器立即复位,输出保持0。

我在项目中遇到过这样一个场景:一个传送带启动后,需要等5秒让物料到位,才能启动下一个工位。用TON就特别合适。

// TON 定时器示例(结构化文本)
TON_1(IN := Start_Signal,
      PT := T#5s);
IF TON_1.Q THEN
    Next_Station := TRUE;
END_IF

关键参数:

  • IN:启动输入(BOOL)
  • PT:预设时间(TIME类型,如T#5s、T#100ms)
  • Q:定时器输出(BOOL)
  • ET:当前计时值(TIME类型,只读)

我的小技巧:PT时间建议用符号常量定义,比如T#CONVEYOR_DELAY。这样后期改时间不用翻遍整个程序,改一个地方就行。

4.1.2 TOF(断开延时定时器)

TOF和TON正好相反。输入信号从1变0(下降沿)时开始计时,计时时间到,输出才变0。如果计时过程中输入又变回1,定时器复位,输出保持1。

嗯,这里要注意:TOF的输入一开始必须是1,否则定时器不会启动。我曾经在调试一个冷却风扇控制时,就因为这个细节折腾了半天——风扇停止后需要继续吹30秒散热,结果TOF没触发,因为启动信号一开始就是0。

// TOF 定时器示例
TOF_1(IN := Fan_Running,
      PT := T#30s);
IF NOT TOF_1.Q THEN
    Cooling_Fan := FALSE;
END_IF

4.1.3 TP(脉冲定时器)

TP定时器,说白了就是产生一个固定宽度的脉冲。不管输入信号持续多久,输出只保持PT设定的时间。这个在需要“短按触发长动作”的场景下特别好用。

举个例子:一个按钮按一下,不管按多久,气缸只伸出2秒就缩回。用TP就完美解决。

// TP 定时器示例
TP_1(IN := Button_Pressed,
     PT := T#2s);
Cylinder_Extend := TP_1.Q;

我曾经踩过的坑:TP定时器在输入信号持续为1时,输出不会重复触发。也就是说,如果你一直按着按钮,TP只输出一个2秒的脉冲,然后保持0。要重新触发,必须让输入先变0再变1。这个和TON的行为不一样,千万别搞混。

4.2 计数器指令:CTU、CTD

计数器,顾名思义就是数数的。但PLC里的计数器不只是数数,它还能做很多有意思的事情。我习惯把计数器看作“事件累加器”——每来一个脉冲,它就记一笔。

4.2.1 CTU(加计数器)

CTU每检测到一次CU输入的上升沿,当前值CV就加1。当CV大于等于预设值PV时,输出Q置1。还有一个R输入,用来复位计数器。

// CTU 加计数器示例
CTU_1(CU := Sensor_Pulse,
      R := Reset_Button,
      PV := 10);
IF CTU_1.Q THEN
    Box_Full := TRUE;
END_IF

你看这个例子:传感器每检测到一个产品,计数器加1。数到10个,就认为箱子满了,输出一个信号。这个逻辑在包装线上太常见了。

4.2.2 CTD(减计数器)

CTD和CTU相反,每检测到一次CD输入的上升沿,当前值CV就减1。当CV小于等于0时,输出Q置1。还有一个LD输入,用来把预设值PV加载到当前值CV。

我个人习惯用CTD来做“库存管理”。比如仓库里有100个零件,每取走一个,计数器减1。减到0就报警补货。

// CTD 减计数器示例
CTD_1(CD := Part_Taken,
      LD := Restock_Signal,
      PV := 100);
IF CTD_1.Q THEN
    Low_Stock_Alarm := TRUE;
END_IF

CTU和CTD的区别:

特性CTUCTD
计数方向向上计数(0→PV)向下计数(PV→0)
触发条件CU上升沿CD上升沿
复位方式R输入复位为0LD输入加载PV值
输出条件CV ≥ PVCV ≤ 0

4.3 比较指令应用

比较指令,说白了就是让PLC学会“做判断”。它把两个数值比一比,然后输出一个布尔结果。别小看这个功能,它能把定时器和计数器的数据变成真正的控制逻辑。

4.3.1 常用比较操作符

IEC 61131-3支持这些比较操作符:GT(大于)、GE(大于等于)、EQ(等于)、NE(不等于)、LE(小于等于)、LT(小于)。

// 比较指令示例
IF TON_1.ET > T#3s THEN
    // 如果定时器当前值大于3秒
    Alarm := TRUE;
END_IF

IF CTU_1.CV >= 5 THEN
    // 如果计数器当前值大于等于5
    Half_Full := TRUE;
END_IF

4.3.2 实际应用场景

我做过一个混合罐的控制程序,需要根据液位和时间两个条件来决定是否开启搅拌器。你看,定时器和比较指令一结合,逻辑就活了。

// 混合罐控制逻辑
TON_Mixer(IN := Fill_Valve_Open,
          PT := T#30s);

// 液位传感器信号(0-100%)
IF (Level_Sensor > 50) AND (TON_Mixer.ET > T#10s) THEN
    Mixer_Start := TRUE;
END_IF

我的建议:比较指令的数值类型要一致。INT和REAL混着比,有时候会出意想不到的结果。我习惯在程序开头统一声明变量类型,避免这种低级错误。

4.3.3 组合应用:定时器+计数器+比较

最后,咱们把今天学的三个知识点串起来。假设你要做一个“3次报警后停机”的功能:每次报警持续超过5秒,就记一次。记满3次,直接停机。

// 组合应用示例
// 报警持续时间超过5秒,产生一个脉冲
TON_Alarm(IN := Alarm_Signal,
          PT := T#5s);

// 每次TON输出上升沿,计数器加1
CTU_Alarm(CU := TON_Alarm.Q,
          R := System_Reset,
          PV := 3);

// 计数器达到3次,触发停机
IF CTU_Alarm.Q THEN
    Machine_Stop := TRUE;
    // 同时记录故障代码
    Fault_Code := 1001;
END_IF

你看,这个逻辑用到了TON来过滤短时干扰,用CTU来累计次数,用比较指令(隐含在CTU的Q输出中)来判断是否达到阈值。三个指令配合得天衣无缝。

重要提醒:定时器和计数器的扫描周期问题。PLC是循环扫描的,定时器的精度受扫描周期影响。如果你需要毫秒级精度,建议用专用高速定时器或中断方式。我见过有人用普通TON做高速计数,结果丢脉冲丢得怀疑人生。

好了,这一章的内容就到这儿。定时器、计数器、比较指令,这三样东西你玩熟了,PLC编程的基本功就算扎实了。下一章我们聊聊更高级的指令——数据处理和移位寄存器,那才是真正体现编程水平的地方。