Skip to main content


 

图片

恭祝工控人中秋快乐
 


 

愿今晚的月色温柔,月饼香甜,无论您是刚下现场、还在盯着上位机,还是已经回到家陪在家人身边,剑指工控都祝您:

设备不报警,通讯不丢包,假期不加班,人月两团圆!

吃块月饼,赏赏月亮,好好歇一歇~ 🥮✨

图片

引言

在工业自动化项目的现场调试中,相信不少 PLC 工程师都遇到过这样的糟心场景:按下启动按钮后设备反复启停、光电传感器明明没检测到工件却频繁误报、限位开关到位后计数器多记了好几个数——这些问题的罪魁祸首,往往都是数字量输入信号的抖动。 机械触点的弹跳、光电传感器的信号干扰、电磁兼容性不佳导致的信号跳变,都会让原本应该稳定的高低电平在短时间内出现多次跳变,轻则导致逻辑误判,重则引发设备损坏、生产事故。今天给大家分享的FB_Debounce消抖功能块,就是专门解决这类问题的轻量、可复用的 PLC 程序单元,代码简洁逻辑清晰,几乎可以适配所有品牌的 PLC 编程环境。

1

   

程序代码与逻辑解析

FB_Debounce是结构化文本(ST)编写的功能块(FB),属于自定义的复用逻辑单元,每次调用时会独立存储内部变量,不会互相干扰,支持在一个项目中多次调用处理多个输入信号。

1.1

   

完整程序代码

下面是完整的 PLC 程序代码(代码基于 CodeSys 平台的 ST 语言): 

FUNCTION_BLOCK FB_Debounce
VAR_INPUT    
    input : BOOL;            // 原始数字量输入信号    
    debounceTime : TIME;     // 可配置的消抖时长    
    enable : BOOL;           // 功能块使能开关,TRUE启用消抖,FALSE直通
END_VAR
VAR_OUTPUT    
    output : BOOL;           // 消抖后的稳定输出信号    
    risingEdge : BOOL;       // 消抖后的上升沿(单周期脉冲)    
    fallingEdge : BOOL;      // 消抖后的下降沿(单周期脉冲)    
    stable : BOOL;           // 当前输入是否处于稳定状态
END_VAR
VAR    
    timer : TIME;            // 消抖计时器    
    lastInput : BOOL;        // 上一次采样的原始输入值    
    lastStable : BOOL;       // 上一次的稳定输出值    
    stableState : BOOL;      // 当前判定得到的稳定电平状态
END_VAR
// 失能模式下直通原始信号,方便调试无需修改逻辑
IF NOT enable THEN    
    output := input;    
    risingEdge := FALSE;    
    fallingEdge := FALSE;    
    stable := TRUE;    
    RETURN;
END_IF;
// 核心消抖逻辑:检测输入变化,计时稳定状态
IF input <> lastInput THEN    
    // 输入发生变化,重置计时器为设定消抖时间,标记信号不稳定    
    timer := debounceTime;    
    stable := FALSE;
ELSIF timer > T#0s THEN    
    // 输入无变化但计时未结束,每扫描周期递减计时(默认适配10ms扫描周期)    
    timer := timer - T#10ms;    
    // 计时归零说明信号连续保持超过消抖时间,判定为稳定    
    IF timer <= T#0s THEN       
        stable := TRUE;        
        stableState := input;    
    END_IF;
ELSE    
    // 计时已归零,信号保持稳定    
    stable := TRUE;
END_IF;
// 边沿检测:仅基于稳定后的信号生成边沿,避免抖动导致的虚假边沿
IF stable THEN    
    output := stableState;    
    // 对比本次稳定状态和上次稳定状态,生成单周期边沿脉冲    
    risingEdge := stableState AND NOT lastStable;    
    fallingEdge := NOT stableState AND lastStable;    
    // 更新上次稳定状态,为下次扫描做准备    
    lastStable := stableState;
END_IF;
// 更新上次原始输入值,用于下一次变化检测
lastInput := input;

 

1.2

   

逻辑核心解析

  1. 使能控制逻辑:失能模式下直接输出原始输入信号,不需要额外注释或修改程序就能快速切换消抖/直通模式,调试阶段查看原始信号非常方便,是代码的贴心设计。

  2. 消抖核心原理:本质是“时间滤波”——只要输入信号发生变化,就重新开始计时,只有信号连续保持当前状态超过设定的debounceTime时长,才判定为有效稳定信号,中间短时间的跳变全部作为干扰过滤。代码中默认每扫描周期减 10ms,对应 10ms 的 PLC 扫描周期,消抖时间设置范围建议为 5-200ms,覆盖绝大多数工业场景需求。

  3. 稳定边沿输出:边沿检测是基于消抖后的稳定信号生成的,不会出现原始输入抖动导致的虚假上升/下降沿,一次稳定动作只会输出一个单周期的边沿脉冲,非常适合用作触发信号(比如启动、计数触发等)。

2

   

典型应用场景

这个消抖 FB 适用范围极广,凡是低速数字量输入信号都可以用它做预处理,常见场景包括:

  1. 操作部件消抖:设备启动/停止/复位按钮、操作面板功能按键、急停按钮等机械按键,本身存在 5-20ms 的触点弹跳,没消抖时一次按下可能触发 3-5 次动作,轻则导致设备反复启停,重则烧毁接触器、撞坏模具。比如注塑机的合模按钮,加消抖 FB 后一次按下只触发一次合模,故障率直接下降 80%以上。

  2. 传感器信号滤波:接近开关、光电开关、限位开关、液位开关等工业传感器,受现场振动、电磁干扰影响,经常出现短时间的高频跳变。比如流水线光电检测工位,工件经过时因为反光、振动导致信号跳变,没消抖时会误判为“缺料”触发全线停机,设置 20-50ms 消抖时间后就能过滤干扰,只保留稳定的到位信号。

  3. 安全信号处理:急停按钮、安全门限位开关、安全光幕等安全类输入,需要兼顾响应速度和抗抖动能力,消抖时间一般设为 5-20ms,既过滤掉触点弹跳,又不会影响安全回路的响应及时性,避免误触发非计划停机。

  4. 脉冲信号预处理:流量计脉冲、电表脉冲、低速旋转编码器的单端脉冲等计量类信号,消抖后可以避免干扰导致的计数错误,提升计量精度,比如水表的脉冲输出加消抖后,统计误差可以从±5%降到±0.5%以内。

  5. 老旧设备改造适配:一些老旧现场设备输出信号质量差、抖动严重,硬件改造成本高,加这个消抖 FB 后不用换硬件就能提升信号稳定性,大幅降低改造成本。

3

   

拓展优化思考

这个 FB 的基础逻辑已经能满足大部分场景需求,针对特殊场景还可以做以下优化:

扫描周期适配优化:当前代码默认每周期减 10ms,仅适配 10ms 扫描周期的 PLC,如果 PLC 扫描周期是 5ms、20ms 或其他值,可以优化为用 TON 定时器实现消抖,不需要依赖扫描周期,消抖时间设置更准确,比如:

VAR   
   changeDetect : BOOL; // 输入变化检测标志   
   debounceTimer : TON; // 消抖定时器
END_VAR
changeDetect := input <> lastInput;
debounceTimer(IN:= changeDetect, PT:= debounceTime);
IF debounceTimer.Q THEN   
   stable := TRUE;   
   stableState := input;
END_IF

 

参数扩展:可以增加“失能默认输出”“消抖模式(高/低电平有效)”等输入参数,适配 NPN/PNP 传感器、特殊失能逻辑等需求;还可以增加“信号跳变次数统计”输出,如果短时间内跳变次数超过阈值,说明信号干扰严重或硬件故障,输出报警信号方便排查。

边沿输出扩展:当前输出的边沿是单扫描周期的窄脉冲,如果需要宽脉冲触发信号(比如驱动报警灯、电磁阀),可以增加“脉冲宽度”参数,内部用单稳态定时器输出固定时长的边沿脉冲。

批量处理优化:如果现场有几十上百个按钮/传感器需要消抖,可以把输入做成数组型变量,一次调用 FB 处理多个信号,减少 FB 调用次数,提升程序运行效率。

适用边界说明:当前消抖逻辑是基于扫描周期的,仅适合 1kHz 以下的低速数字量信号,如果是高速脉冲信号(比如编码器的高速 A/B 相脉冲、高频计数信号),需要用 PLC 高速输入模块的硬件滤波功能,这个消抖 FB 不适用。


 

总结

FB_Debounce虽然只有几十行代码,但精准解决了工业现场最常见的信号抖动痛点,逻辑清晰无复杂指令,西门子 TIA Portal、三菱 GX Works、汇川 AutoShop 等主流 PLC 编程软件都能直接移植,消抖时间可根据现场需求灵活配置。 平时做项目时将这类基础功能块封装到个人程序库中,既能减少重复开发的工作量,又能大幅提升程序的稳定性和可维护性,是 PLC 工程师必备的“轻量级工具”。哪怕是没有太多编程经验的新手,也能看懂代码逻辑,根据需求快速修改适配,非常实用。

图片

你来出题 我来答图片图片图片

欢迎大家在评论区提一些标准功能块的需求,如果合适,我们会在以后的文章中与大家分享。

图片

往期回顾


 

每周一个编程小例子 :Bit 到 Word 转换的两种实现方案对比

每周一个编程小例子:记录设备运行时间

每周一个编程小例子:基于长按检测的启动控制系统

每周一个编程小例子:探秘 PLC 数据记录功能块

每周一个编程小例子:心跳检测与 PLC 应用

每周一个编程小例子:斜坡发生器

每周一个编程小例子:旋转速度计算

每周一个编程小例子:计算 PLC 循环周期|例程需求征集!

每周一个编程小例子:如何优雅的分割字符串

每周一个编程小例子:带反馈的阀门控制程序

每周一个编程小例子:西门子 LGF 库中的脉冲继电器功能块

每周一个编程小例子:曲线加减速的控制应用

每周一个编程小例子:轻松去除字符串前导字符

每周一个编程小例子:根据阈值更新输入

每周一个编程小例子:官方模拟量输入处理模块

每周一个编程小例子:主从电机的时序控制

每周一个编程小例子:基于一阶滞后滤波的优化方案

每周一个编程小例子:16 进制到浮点数的神奇转换

每周一个编程小例子:PLC 长按控制程序

每周一个编程小例子:PLC 程序实现多位整数拆分

每周一个编程小例子:流量累积计算器

每周一个编程小例子:用于连锁的电机标准控制模块

每周一个编程小例子:PID 控制算法在 PLC 系统中的实现与应用

每周一个编程小例子:自定义种子生成随机数

每周一个编程小例子:可调时间的脉冲生成器

每周一个编程小例子:带滤波的标准模拟量输入功能块

每周一个编程小例子:使用 PLC 将字符串转换为日期格式

每周一个编程小例子:PLC 配方管理

每周一个编程小例子:比较两个 DB 块(STL)

每周一个编程小例子:如何使用 PLC 实现数组逆序

每周一个编程小例子:流量累计与批次控制

每周一个编程小例子:自定义循环执行控制程序

每周一个编程小例子:步进控制功能块

每周一个编程小例子:PLC 权重比例分配器

每周一个编程小例子:数字量输入组监控

每周一个编程小例子:实时数据分析

每周一个编程小例子:PLC 多轴同步控制的理解与应用

每周一个编程小例子:PLC 波形生成器 (正弦 方波 三角波)

每周一个编程小例子:模拟量信号报警

每周一个编程小例子:组合数概率的实现

每周一个编程小例子:多传感器信号融合与优化方案

每周一个编程小例子:监控模拟信号的健康状态

每周一个编程小例子:PLC 程序实现模拟信号的线性校准

每周一个编程小例子:智能报警过滤器:优化报警系统的 PLC 程序

每周一个编程小例子:使用 PLC 程序让灯光呼吸

每周一个编程小例子:自适应性滤波器:动态调整以平衡响应与稳定性

每周一个编程小例子:卡尔曼滤波器在自动化中的简单应用

每周一个编程小例子:多模式定时器

每周一个编程小例子:基于 PLC 的编码器速度计算器

每周一个编程小例子:电机顺序启动与停止程序

每周一个编程小例子:电梯控制程序

每周一个编程小例子:自动门控制系统

每周一个编程小例子:智能停车场计数系统

每周一个编程小例子:智能照明控制系统

每周一个编程小例子:变频器控制

每周一个编程小例子:比例阀控制

每周一个编程小例子:脉冲输出的灵活控制

每周一个编程小例子:计算移动平均值

每周一个编程小例子:速率限制器

每周一个编程小例子:线性插值法线性化传感器

每周一个编程小例子:数据转换的魔力

每周一个编程小例子:PLC 安全监控功能块

图片

2026年9月