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的区别:
| 特性 | CTU | CTD |
|---|---|---|
| 计数方向 | 向上计数(0→PV) | 向下计数(PV→0) |
| 触发条件 | CU上升沿 | CD上升沿 |
| 复位方式 | R输入复位为0 | LD输入加载PV值 |
| 输出条件 | CV ≥ PV | CV ≤ 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编程的基本功就算扎实了。下一章我们聊聊更高级的指令——数据处理和移位寄存器,那才是真正体现编程水平的地方。