尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

PLC信号抖动怎么解决?消抖功能块ST代码与工程经验详解

发布时间:2026/9/29 21:16:08

资讯中心
01
ARTICLE

PLC信号抖动怎么解决?消抖功能块ST代码与工程经验详解

PLC信号抖动怎么解决?消抖功能块ST代码与工程经验详解
做现场调试这些年我最怕的不是复杂的轴联动也不是PID参数乱飞而是那种“看起来很简单”的信号问题。按钮按下去指示灯偶尔不亮接近开关碰到工件有时候响应、有时候不响应光电传感器对着运行中的产线信号像抽风一样来回跳。多数新手第一反应是换硬件、换线、换传感器结果折腾半天问题还在。其实幕后黑手基本都是同一个——信号抖动。这周的“每周一个编程小例子”我想把PLC里最常用的消抖功能块拆开讲透从原理到ST代码再到我踩过的一些坑一次性交代清楚。马上就是中秋了很多工控同行还守在项目现场、调试车间里先把祝福送给大家愿各位工控人阖家团圆中秋快乐。调试设备再忙也记得给家人打个电话。下面进入正题。1. 现场信号的“抖动”从哪里来为什么必须做软消抖1.1 抖动不是玄学三个最常见的来源信号抖动这个问题谁做现场谁遇到区别只是你有没有意识到它。我归纳下来工业现场信号的抖动主要有三个来源。第一个是机械触点的弹跳。按钮、继电器、接触器这类元件触点闭合瞬间并不是“啪”一下就稳定导通而是会像乒乓球掉到桌面上一样弹几下才落稳。这个弹跳过程通常持续几毫秒到几十毫秒期间信号会反复通断。如果你把PLC的输入点直接接到一个按钮上用示波器看波形你会看到在电平从0翻到1的过程中中间夹着一串窄脉冲。PLC扫描周期如果足够快这些窄脉冲就会被当成一次次真实的开关动作采进去。第二个是传感器在临界位置的输出抖动。接近开关、光电传感器、编码器当被测物体刚好处于检测临界区时传感器会处于“似触非触”的状态输出信号就会在0和1之间来回跳。这种情况在振动比较大的设备上尤其明显比如输送线上的光电对射工件边缘刚好卡在光斑边缘时信号能抖出几十赫兹的脉冲串。第三个是电气干扰带来的毛刺。变频器、伺服驱动器、大功率接触器通断时会在动力电缆周围产生较强的电磁干扰。如果信号线屏蔽没做好、布线又和动力线走在同一个线槽里PLC输入端就会时不时捕获到莫名其妙的窄脉冲。这种干扰脉冲宽度可能只有零点几毫秒但足以让计数器多计一个数、让报警误触发一次。用个生活化的类比你半夜听到敲门声如果敲一下就开门大概率会被恶作剧耍一次如果连续敲了几秒才去开门十有八九是真有人找。消抖就是这个道理——在时间维度上确认信号“稳住了”再让它生效。1.2 不消抖的直接后果误动作、计数错乱、联锁失效有人可能会说不就抖一下嘛PLC扫描周期是毫秒级的忍一忍就过去了。真不是这样。我见过一个计数工位光电传感器检测工件通过由于产线振动导致信号在临界点反复跳变一个工件实际只应该计1次结果计数器的数值哗哗往上跑一个小时多计了几百件。操作工都懵了以为设备坏了停机排查了半天最后发现是信号没做消抖。误动作更常见。比如设备启动按钮因为触点弹跳PLC可能把一次按下当成多次操作导致程序里的启动指令被重复执行。还有一种更危险的情况是安全联锁信号被毛刺旁路本应保持关闭的阀门因为输入信号瞬间抖到错误电平联锁逻辑被突破哪怕只放行了半个扫描周期也可能酿成事故。所以我一直跟团队里的人说凡是接真实物理信号的输入点尤其是按钮、限位、急停、传感器都应该默认考虑消抖。不是每次都会抖但只要出一次事代价就不是换一个传感器能弥补的。1.3 硬件消抖和软消抖的取舍消抖不是PLC时代才有的问题以前的继电器电路、分立元件控制柜也有处理手段最常见的是硬件消抖在输入回路中并联RC滤波电路利用电容充电延时吸收窄脉冲或者使用施密特触发器做电平整形。硬件消抖的优点是响应快、不占用PLC扫描周期但它有个让我很头疼的缺点——参数改起来太麻烦。你设计时按10ms去抖做到了现场发现这个按钮的触点弹跳有30ms就得换电阻电容、重新焊板子。要是设备已经装进柜子、线都接好了这活儿想想都头大。软消抖则完全相反只需要在程序里用一个功能块去抖时间做成参数现场发现不够就改一个数下装、搞定。它的代价是占用几十毫秒的响应时间以及增加一点扫描周期负担但在绝大多数工业场景下这点代价完全值得。我现在的项目基本上统一采用软消抖只有极少数对响应速度要求苛刻的场合才会额外加硬件滤波。2. 消抖功能块的设计权衡时间窗、采样计数与边沿输出2.1 消抖的核心逻辑在时间上确认状态消抖功能块的核心思想并不复杂不让输入信号的边沿立即生效而是要求信号在某个电平上稳定持续超过设定的时间才认为这次状态变化是“真的”。举个例子去抖时间设为50ms。信号从0变成1之后PLC并不会立刻把内部输出也置1而是启动一个计时器。如果在这50ms内信号一直保持1计时结束输出才翻转为1如果中途又跳回0计时器清零重来。反过来信号从1变成0也同理。这种方法叫“延时确认”它的本质是拿时间换确定性用牺牲几十毫秒响应速度的方式换来可靠的信号状态。这里有个容易混淆的概念消抖不等同于滤波。低通滤波是处理连续变化的模拟量消抖处理的是开关量的状态确认。虽然两者都涉及时间常数但在PLC里开关量消抖的实现方式是完全不同的。2.2 两种主流实现定时器确认法 vs 采样计数法在PLC里做消抖主流上有两种实现思路我分别说一下。第一种是定时器确认法利用TON延时接通定时器来做。信号变为高电平后TON开始计时计时达到设定值且输入一直保持高电平输出跟随为高。信号在计时中途掉回低电平TON复位输出保持低。这种方法实现简洁代码量少去抖时间直接用TIME类型设置直观清楚。它最适用于信号变化不频繁、但要求去抖时间精确可控的场合比如按钮、急停、限位开关。第二种是采样计数法在PLC的循环扫描中每次扫描读取一次输入信号用一个计数器记录“连续读到相同电平的次数”。连续N次读到高电平才把输出置高连续N次读到低电平才把输出置低。这种方法不依赖定时器逻辑上更接近数字滤波特别适合扫描周期固定、信号频率较高的场合。缺点也很明显去抖时间取决于扫描周期和N的乘积扫描周期不稳的话去抖时间就漂。两种方法的对比如下维度定时器确认法采样计数法实现复杂度低代码简洁中需要计数器逻辑去抖时间设置直接设置TIME值直观由扫描周期×N间接决定适用信号频率低频信号为主中高频信号更稳受扫描周期影响小TON计时独立大扫描周期波动会改变实际去抖时间典型场景按钮、急停、限位、保护联锁编码器、快速计数、振动环境传感器我在实际项目中90%的情况用定时器确认法稳、直观、好维护。采样计数法更多是在运动控制或者高速计数场景里遇到那时候我会把它做成独立功能块参数单独调。2.3 消抖和边沿检测怎么组合消抖解决了信号稳定性的问题但程序里经常还需要边沿信号——比如按钮按一下只想要一个上升沿脉冲去触发置位而不是持续的高电平。这里有个常见坑直接在原始输入信号上做上升沿检测原始信号一抖边沿脉冲也会跟着抖出好几个。正确做法是先消抖再在消抖后的信号上取边沿。也就是在功能块内部把上一扫描周期的消抖输出保存下来用“当前消抖输出为TRUE且上一周期为FALSE”来判断上升沿。这样就能保证一个真实的按钮动作只产生一个上升沿脉冲。有些工程师会在OB1里单独写一段沿检测逻辑来处理消抖后的信号这也能跑但可复用性差。我更推荐把边沿捕获封装进消抖功能块内部输入给消抖块输出直接拿消抖后的电平和上升沿、下降沿到哪儿都能直接用。3. 一个可直接抄走的ST消抖功能块及移植要点3.1 功能块接口定义与内部变量设计先定义一个标准的FB功能块接口。之所以用FB不用FC是因为消抖逻辑需要“记忆”——要记住上一次的输出状态用来做边沿检测。FB实例有自己的背景数据块状态会安全地保存在里面不会像FC那样每次调用都要手动传递静态变量。接口定义如下FUNCTION_BLOCK FB_Debounce VAR_INPUT bRawSignal : BOOL; // 原始输入信号接物理输入点 tDebounceTime : TIME : T#50MS; // 去抖时间默认50ms bEnable : BOOL : TRUE; // 功能块使能FALSE时输出直接跟随输入 END_VAR VAR_OUTPUT bFilteredSignal : BOOL; // 消抖后的稳定信号 bRisingEdge : BOOL; // 消抖后信号的上升沿单周期脉冲 bFallingEdge : BOOL; // 消抖后信号的下降沿单周期脉冲 END_VAR VAR tonTimer : TON; // 内部定时器 bFilteredOld : BOOL; // 上一周期的消抖输出用于边沿检测 END_VAR这个接口设计基本是“通用脸”三个输入、三个输出、一个内部定时器和一个保持变量。bEnable端口是我后加上的一开始觉得多余后来发现现场总有人想在维修时强制旁路消抖直接观察原始信号有这个端口就方便多了。3.2 核心ST实现定时器确认法的完整代码定时器确认法的ST实现如下我直接把完整功能块代码贴出来// 消抖处理使能状态下去抖非使能状态直通 IF NOT bEnable THEN tonTimer(IN : FALSE, PT : tDebounceTime); bFilteredSignal : bRawSignal; ELSE // 原始信号为TRUE时启动/保持定时器 tonTimer(IN : bRawSignal, PT : tDebounceTime); // 定时器完成且原始信号仍为TRUE输出TRUE // 原始信号为FALSE时输出FALSE这里用Q输出配合直接赋值 IF tonTimer.Q THEN bFilteredSignal : TRUE; ELSE // 没有计时完成时维持当前滤波状态 // 若原始信号掉回FALSE则立即复位输出 IF NOT bRawSignal THEN bFilteredSignal : FALSE; END_IF; END_IF; END_IF; // 边沿检测基于消抖后的信号做上升沿和下降沿 bRisingEdge : bFilteredSignal AND NOT bFilteredOld; bFallingEdge : NOT bFilteredSignal AND bFilteredOld; bFilteredOld : bFilteredSignal;这里最关键的一行是tonTimer(IN : bRawSignal, PT : tDebounceTime)。TON的输入直接接原始信号意味着原始信号一旦变为FALSETON立即复位计时清零。这样逻辑就变得很干净只要原始信号没有在设定的时间窗内稳定保持计时器就永远到不了Q输出就不会翻转。有些初学者会犯一个错误把TON的IN接成消抖后的输出而不是原始输入。这样逻辑就完全乱掉了——输出反馈给定时器形成自锁去抖功能形同虚设。记住TON的IN永远接原始信号。3.3 采样计数法的ST实现和适用说明如果你遇到的场景扫描周期固定、信号频率偏高可以试试采样计数法。实现如下VAR_INPUT bRawSignal : BOOL; nConfirmCount : INT : 5; // 连续N次采样一致才确认 END_VAR VAR nHighCount : INT : 0; nLowCount : INT : 0; bOut : BOOL : FALSE; END_VAR // 采样计数逻辑 IF bRawSignal THEN nHighCount : nHighCount 1; nLowCount : 0; IF nHighCount nConfirmCount THEN bOut : TRUE; END_IF; ELSE nLowCount : nLowCount 1; nHighCount : 0; IF nLowCount nConfirmCount THEN bOut : FALSE; END_IF; END_IF;这个版本的缺点是正反转去抖需要分别计数代码会稍微长一点但它不依赖TON定时器在扫描周期极小且稳定的PLC上表现很好。实际的去抖时间就是nConfirmCount × 扫描周期调试时按这个公式估算就行。3.4 移植到西门子、汇川、Codesys等平台的注意事项这个功能块我在西门子博途TIA Portal、汇川、Codesys系的PLC上都跑过基本逻辑通用但有几个移植坑值得提醒。第一数据类型。博途和Codesys都支持TIME类型但汇川部分型号的ST实现里TIME常量写法略有差异比如T#50MS在个别版本里要求写成TIME#50MS。保险做法是先在程序里定义一个CONSTANT再赋给去抖时间参数。第二定时器资源。在西门子S7-1200/1500里直接用TON功能块就好CPU会自动分配定时器资源不用手动指定定时器号。但旧式的S7-300/400如果使用IEC定时器要注意TON也是FB需要在背景数据块里管理实例。第三FB实例命名。一个项目里可能用到几十个消抖功能块每个都必须有唯一的实例名。建议按信号用途命名比如FB_Debounce_StartButton、FB_Debounce_PhotoEye_3千万别叫什么Instance_1、Instance_2否则三个月后你自己都不想看这个程序。4. 上线前最容易翻车的三个细节扫描周期、初始状态和掉电保持4.1 扫描周期会吃掉你的去抖时间这个坑我是被现场狠狠教育过一次才长记性的。当时给一台设备做按钮消抖去抖时间设了50ms心想着够用了结果现场测试时按钮按得快一点偶发失灵。排查半天发现问题出在OB1的扫描周期上——那个项目里OB1里塞了太多逻辑加上HMI通信扫描周期已经飘到30ms上下。TON虽然计时准确但它的启动滞后于实际信号变化输出刷新又要等下一个扫描周期实际等效去抖时间被“吃”掉了一个扫描周期还要多。所以我的建议是去抖时间不要卡着信号抖动时间定至少要留出两倍以上的余量。现场实测触点弹跳10ms你设50ms是安全的如果触点弹跳有30ms就果断设80~100ms。消抖时间设长一点代价最多是响应慢几十毫秒设备该干嘛还是干嘛设短了去抖等于没去。另外在调试阶段可以用HMI或者上位机把“原始信号状态”和“消抖信号状态”同时显示出来按钮按一下看两个灯是不是同步翻转。如果不同步说明去抖时间有效如果明显感觉到延迟比设定的50ms长不少那就该查扫描周期了。4.2 上电瞬间的第一个状态默认输出可能让设备直接动作功能块内部变量在PLC上电时会被初始化TON的输出Q默认FALSEbFilteredSignal默认FALSE。这在大多数情况下是合理的——设备上电按钮没按输出当然应该是FALSE。但如果现场是失电安全型负载比如常闭型急停回路、常闭型安全门开关信号在未触发时本身就是TRUE你一做消抖上电瞬间输出被强制成FALSE设备反而可能被认为“急停按下”而无法启动。解决思路有两个。一是在功能块里增加一个“初始化跟踪”逻辑PLC从STOP转到RUN后的第一个扫描周期直接把消抖输出赋值为当前原始信号不做延时确认。二是把bFilteredSignal的初始值设计成可配置不同安全等级的回路用不同的初始值。我实际用的比较多的是方案一只需要在功能块内部加一个初始化标志位VAR bInitDone : BOOL : FALSE; END_VAR // 在消抖逻辑之前执行 IF NOT bInitDone THEN bFilteredSignal : bRawSignal; bInitDone : TRUE; // 跳过本周期的正常消抖逻辑 ELSE // 正常消抖处理 END_IF;这样上电瞬间输出会跟随原始信号的真实状态不会因为默认值导致设备误动作。4.3 掉电保持与多实例化停电后再上电状态还记得吗消抖功能块内部的状态变量比如bFilteredOld、中间计数器的值默认都是非保持型PLC断电重启后会清零。这在大多数场景没问题按钮按下后断个电再上电按钮状态重新检测用户不会觉得奇怪。但有一种情况必须考虑掉电保持设备状态联锁。比如两个工位之间的互锁信号A工位到位后允许B工位动作这个信号做了消抖处理。如果PLC断电期间设备机械部分因为惯性仍在移动重新上电后消抖块丢失了上次的联锁状态设备就可能在不安全的状态下自动恢复运行。解决方案是给关键联锁信号使用保持型变量或者在FB内部把bFilteredSignal声明为RETAIN。这里要提醒一句RETAIN变量会占用保持性存储区而且写入次数有限制不能把高频变化的信号随便设为保持型。我通常只对“设备安全状态”类信号启用RETAIN普通的按钮消抖完全不需要。还有多实例管理的问题。一个车间几十个按钮、几十个传感器如果你手动创建几十个几乎一模一样的功能块调用程序会非常臃肿。正确做法是利用FB的可复用性在同一段逻辑里多次调用同一个FB每个调用对应一个实例数据块。博途里可以直接把同一个FB拖到梯形图里多次使用或者在ST里多次声明实例。这样改去抖时间只改FB内部默认值重新下装全部生效维护成本低得多。5. 从按钮防抖到整机联锁消抖功能块的工程扩展5.1 把计数防抖改进为“速度防抖”解决慢速信号误判前面介绍的采样计数法有一个隐含问题对于变化很慢的合法信号比如温度开关在临界点缓慢翻转连续几个扫描周期读到相同电平是正常的但它不一定意味着信号稳定。如果把计数阈值设大了合法信号会被延迟设小了抖动又滤不干净。我在一些项目里用过一种“速度防抖”的思路不只统计连续相同电平的周期数还估算信号变化的速率。具体做法是记录最近一段时间内信号翻转的次数如果翻转频率超过设定值就认为是抖动如果翻转频率低但单个高电平持续时间很短则可能是真实的短脉冲信号。这种思路比较适合编码器方向判断、快速计数等场景。但在常规的工业按钮和传感器场景里我劝你别把消抖做太复杂。固定延时确认已经能覆盖绝大多数情况速度防抖适合对信号特征有明确了解、且普通消抖无法满足的特定工位。5.2 双通道互锁加消抖安全联锁的可靠做法在安全要求比较高的设备上单通道信号做消抖还是不够的。原因很简单消抖滤掉了抖动和大部分干扰但无法防止传感器本体故障。比如一个安全门开关坏了输出信号永远是对的你消抖也发现不了。规范的联锁设计会做双通道互锁两个独立的传感器检测同一个安全状态两个信号分别做消抖处理后再把两个消抖结果做“与”运算作为最终联锁条件。只有两个通道都确认到位设备才允许动作任何一个通道被消抖后确认未到位立即联锁停机。这样设计的价值在于它把消抖从“信号整形”提升到了“故障安全”的层次。即使某个通道因为干扰、老化、接线松动产生了错误电平另一个通道还能兜底。这个思路我用在好几台设备的安全门、急停、光栅互锁回路里故障率明显下降。5.3 把消抖时间做成HMI可调参数最后分享一个我个人很推荐的做法把消抖时间做成HMI上的可调参数而不是写死在程序里。原因很实际设备在客户现场运行一段时间后传感器老化、机械磨损触点弹跳时间会变化。如果去抖时间写死现场出问题就要找电气工程师改程序、重新下装用户等不起。把参数开放到HMI上现场操作工通过触摸屏就能把去抖时间从50ms调到100ms立竿见影。具体实现上不要在FB内部声明固定的默认值而是把tDebounceTime接到一个全局变量上再在HMI里绑定该变量。要注意设置上下限比如10ms到500ms防止误操作设成一个离谱的值把响应拖死。还要在HMI上同时显示“原始信号状态”和“消抖后状态”方便现场人员直接判断当前去抖时间是否合适。我最近调试的一套设备就用了这个方案。客户反映有个光电传感器在高速运行时偶尔误触发我在HMI上把去抖时间从50ms调到120ms问题当场解决客户自己动手改的连电话都没给我打。5.4 消抖功能块之外老生常谈的工程习惯说实话消抖功能块本身不是什么高深技术它的价值在于能帮你把现场那些“说不清、道不明”的偶发问题挡在程序之外。但技术之外有些工程习惯比功能块本身更重要接线尽量远离动力线屏蔽层单端可靠接地传感器的供电不要和电机驱动共用一个开关电源程序里每个输入信号都做注释标明来自哪个设备、用途是什么。这些东西看起来琐碎但现场故障排查时它们的作用比功能块还大。等你半夜三点被电话叫醒去处理一台停机的设备就会发现当初多写一行注释、多留一个HMI参数都是省命的操作。这个消抖功能块我用了很多年从最简单的按钮消抖一路用到安全联锁中间踩过扫描周期的坑、吃过上电初始状态的亏也踩过掉电保持的雷。把这些经验写出来也是希望刚开始接触PLC的朋友少走几步弯路。中秋月圆愿各位工控人手里的项目都稳稳当当家里的灯都亮亮堂堂阖家团圆节日快乐。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。