ST计数器应用:CTU、CTD在ST中的逻辑实现与复位策略

发布于 2026-03-18 11:56:45 · 浏览 4 次 · 评论 0 条

ST(结构化文本)是IEC 61131-3标准中功能最强、表达最接近高级语言的编程语言,广泛用于PLC控制系统中实现复杂逻辑。计数器是自动化控制中最基础也最关键的元素之一,而CTU(Count Up)、CTD(Count Down)是ST中两种标准计数器功能块。它们看似简单,但在实际工程中,因复位时机错位、使能信号抖动、计数值越界、多条件交叉触发等原因,极易引发计数失准、设备误动作甚至停机事故。本文不讲概念定义,只讲怎么写才不出错——从底层逻辑、代码实现、典型陷阱到可复用的复位策略,全部以ST语法为唯一载体,所有内容均可直接粘贴进Codesys、TIA Portal、Unity Pro等主流平台验证。


一、CTU与CTD的本质:不是“黑盒”,而是“状态机”

CTU和CTD在ST中并非内置语句(如FORIF),而是预定义功能块(FB),必须通过实例化调用。其核心行为由三个输入引脚和两个输出引脚共同决定:

引脚名 类型 作用说明
CU / CD BOOL 上升沿触发计数动作。仅当该信号由FALSETRUE跳变时,计数器才响应一次。注意:持续TRUE不会重复计数。
R BOOL 异步复位。只要R=TRUE,无论CU/CD状态如何,立即清零PV并置Q=FALSE(CTU)或Q=FALSE(CTD)。复位优先级最高。
LD(仅CTD) BOOL 装载预设值。当LD=TRUECD无上升沿时,将PV强制设为PV:=PV(即保持当前值),但标准CTD不支持外部装载值;若需装载,应使用CTUD或自定义逻辑。此处以标准CTD为准。
PV INTDINT 当前计数值。初始值为0,范围取决于数据类型:INT为−32768~+32767,DINT为−2147483648~+2147483647。溢出不自动回绕,而是锁死在边界值(如INT计到32767后再+1,仍为32767)。
Q BOOL 计数完成标志。CTU中:Q := (PV >= PV_MAX);CTD中:Q := (PV <= 0)。注意:Q为纯组合逻辑输出,无延时。

关键认知:CTU/CTD本身不保存“是否已触发过”的历史,它只响应边沿、只依赖当前输入电平。 所谓“计数稳定”,完全取决于你如何组织CU/CD信号的边沿生成逻辑。


二、标准CTU的ST实现:从模板到防抖

以下是最小可行、零冗余的CTU实例化代码(以DINT型为例,兼顾大计数场景):

// 声明实例与变量
ctu_inst: CTU;
reset_flag: BOOL;
count_enable: BOOL;
pulse_input: BOOL; // 外部脉冲源,例如光电开关信号
preset_value: DINT := 5; // 计满5次触发动作

// 主逻辑段(放在主程序POU或循环任务中)
// 步骤1:生成干净的上升沿脉冲(抗抖动)
pulse_edge := pulse_input AND NOT pulse_input_prev;
pulse_input_prev := pulse_input;

// 步骤2:添加软件滤波(可选,但强烈推荐)
IF filter_timer.Q THEN
    filtered_pulse := pulse_edge;
ELSE
    filtered_pulse := FALSE;
END_IF;

// 步骤3:启动计时器滤波(10ms去抖)
filter_timer(IN := pulse_edge, PT := T#10ms);

// 步骤4:构造最终CU信号 —— 仅当使能有效且滤波后有边沿时才计数
ctu_inst(CU := count_enable AND filtered_pulse,
         R  := reset_flag,
         PV := preset_value);

// 步骤5:导出结果
count_value := ctu_inst.CV; // CV为当前值输出(标准CTU含CV、Q、QU等)
is_full     := ctu_inst.Q;  // Q为到达预设值标志

说明:

  • pulse_input_prev 必须声明为VAR RETAIN或位于FB内部,否则每次扫描都会丢失前一状态;
  • filter_timer 是标准TP(脉冲定时器)功能块,确保毛刺宽度<10ms时不触发;
  • count_enable 是工艺允许计数的使能条件(如“电机正在运行”AND“安全门关闭”),绝不能直接用硬件信号代替
  • reset_flag 的生成必须独立于计数逻辑,见第四节。

三、标准CTD的ST实现:避免“负计数陷阱”

CTD常被误用于“倒计时”场景(如物料剩余量提示),但其Q输出逻辑是PV <= 0,而非PV == 0。这意味着:一旦PV被意外减至−1,Q将保持TRUE直至复位——这是多数故障的根源。

正确做法:永远用CTD配合边界钳位,禁止单独使用其Q输出做关键动作。

// 声明
ctd_inst: CTD;
down_enable: BOOL;
pulse_down: BOOL;
min_limit: DINT := 0;

// 主逻辑
// 生成下降沿(用于CTD的CD输入,注意:CTD响应CD上升沿,所以需将“下降事件”转为上升脉冲)
pulse_down_edge := NOT pulse_down AND pulse_down_prev;
pulse_down_prev := pulse_down;

// 构造CD信号:仅当允许且有干净边沿时触发
ctd_inst(CD := down_enable AND pulse_down_edge,
         LD := FALSE, // 标准CTD中LD无装载功能,设FALSE即可
         R  := reset_flag);

// 关键:手动钳位PV,防止越界
pv_raw := ctd_inst.CV;
pv_clamped := MAX(min_limit, pv_raw); // 确保不低于0
count_down_value := pv_clamped;

// 安全Q输出:仅当PV恰好等于0时置位(非<=0)
is_zero := (pv_clamped = 0);

⚠️ 警告:不要写 is_zero := ctd_inst.Q。因为ctd_inst.QPV=−1−2…时恒为TRUE,失去“精确归零”意义。


四、复位策略:四种工业级可靠方案

复位不是“按个按钮清零”,而是与工艺周期强耦合的状态管理。以下是经产线验证的四大策略,按可靠性升序排列:

  1. 同步复位(最简,仅限调试)

    reset_flag := btn_manual_reset OR (is_full AND auto_reset_en);

    ✅ 适用:单次测试、手动模式。
    ❌ 风险:若auto_reset_en时序错配(如在计数中途使能),导致reset_flagCU同拍,计数器可能漏计1次。

  2. 周期复位(推荐用于批次控制)

    // 在每个工艺周期开始前复位
    IF cycle_start_edge THEN
        reset_flag := TRUE;
    ELSIF cycle_running THEN
        reset_flag := FALSE;
    END_IF;

    cycle_start_edge 必须是严格单脉冲(如伺服回原点完成信号的上升沿),确保每周期只复位1次。

  3. 条件锁定复位(高可靠性,防误触发)

    // 仅当满足全部条件时才允许复位
    can_reset := (is_full) 
                 AND (conveyor_stopped) 
                 AND (no_material_on_belt) 
                 AND (reset_permission = OK);
    reset_flag := can_reset AND reset_request; // reset_request为操作员确认信号
  4. 双沿复位(最高可靠,用于安全相关计数)

    // 复位需“按下+松开”两个事件,杜绝粘连误动作
    reset_press := btn_reset AND NOT btn_reset_prev;
    reset_release := NOT btn_reset AND btn_reset_prev;
    btn_reset_prev := btn_reset;
    
    reset_flag := (state = WAITING_FOR_RESET) 
                  AND reset_press;
    state := CASE state OF
        IDLE:        IF is_full THEN WAITING_FOR_RESET ELSE IDLE END_IF;
        WAITING_FOR_RESET: IF reset_release THEN IDLE ELSE WAITING_FOR_RESET END_IF;
    END_CASE;

✅ 实践结论:在包装线计瓶、灌装线计桶、装配线计工件等场景中,第3种(条件锁定)覆盖90%需求;第4种(双沿)用于SIL2及以上安全回路


五、CTU与CTD混合应用:CTUD的替代方案(不依赖CTUD FB)

部分老版本PLC(如早期Modicon M340)不支持CTUD功能块。此时可用CTU+CTD协同实现双向计数,并规避CTUD常见的“CU/CD同时为TRUE时行为未定义”的风险:

// 双向计数器逻辑(目标:PV ∈ [0, 100],CU加、CD减,越界钳位)
VAR
    cu_pulse, cd_pulse: BOOL;
    cu_active, cd_active: BOOL;
    pv_work: DINT := 0;
    upper_limit: DINT := 100;
    lower_limit: DINT := 0;
END_VAR

// 分别处理CU和CD(互斥触发)
IF cu_pulse AND cu_active THEN
    pv_work := MIN(upper_limit, pv_work + 1);
ELSIF cd_pulse AND cd_active THEN
    pv_work := MAX(lower_limit, pv_work - 1);
END_IF;

// 输出
bidir_cv := pv_work;
at_upper := (pv_work = upper_limit);
at_lower := (pv_work = lower_limit);

优势:

  • 完全可控,无隐式状态;
  • 可加入任意前置条件(如“仅当温度>80℃时才允许加计”);
  • 复位只需 pv_work := 0;,无时序依赖。

六、终极检查清单(部署前逐项核对)

检查项 合格标准 不合格示例
边沿生成 所有CU/CD信号均来自X AND NOT X_prev结构 直接写CU := sensor_signal;
数据类型 PVCVpreset_value三者类型严格一致(全DINT或全INT preset_value: INT;CV被赋给DINT变量
溢出防护 CV读取后立即CLAMP(0, max, CV)MAX/MIN处理 IF cv > 100 THEN start_alarm; END_IF;(未阻止cv继续增长)
复位隔离 R信号与CU/CD无共用中间变量,且R电平变化不依赖CU/CD输出 R := ctu_inst.Q;(Q刚置位就复位,导致计数器无法保持)
初始化 所有_prev变量声明含:= FALSE初值 sensor_prev: BOOL;(冷启动时值不确定)

最后强调:ST中没有“自动魔法”。每一个:=、每一个AND、每一个边沿,都必须是你亲手确认过的确定性动作。 把本文 checklist 打印出来,贴在编程电脑边框上——比任何教程都管用。


评论 (0)

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

扫一扫,手机查看

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