ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PLC输入信号消抖功能块详解:从原理到ST与梯形图实现

PLC输入信号消抖功能块详解:从原理到ST与梯形图实现 做PLC调试这么多年最让我有成就感的不是项目一次通过而是手里攒下来一张张能反复用的功能块。今天这个“每周一个编程小例子”想聊一个几乎所有工控人都绕不过去的坑——输入信号抖动。无论是按钮、继电器触点还是接近开关现场信号就没几个是干干净净的稍微有点毛刺就能让程序误动作计数器凭空多跳几位电机该停不停报警乱闪。折腾一圈下来说不准又是哪个触点接触不良。在这个例子里我会把消抖功能块从原理到实现完整拆一遍给出结构化文本和梯形图两种写法再结合实际调试中容易踩的坑一起聊。不管你是刚入门看PLC编程基础知识还是在非标项目里被现场干扰折磨得头大这篇都能直接用得上。中秋在即先祝各位工控同仁阖家团圆吃口热乎的月饼看完这篇回工位上做“每周一个编程小例子”也更有底气。1. 消抖到底消的是什么从现场噪声到信号毛刺1.1 常见的抖动来源与现场表现先说说我见过比较典型的几类抖动。最普遍的是机械触点类。常规继电器、接触器、按钮在动作瞬间金属触点会弹跳电压波形上会出现一连串几十微秒到十几毫秒的通断这在示波器上叫“弹跳毛刺”。第二个大户是传感器尤其是电感式和电容式接近开关在检测到铁板边缘、齿轮齿牙的时候输出会反复跳变有时候位置没完全到位信号就贴着阈值来回翻。还有一个隐蔽的来源是变频器、伺服驱动器、接触器线圈通断产生的电磁干扰会耦合到信号线里让输入点出现瞬时的尖峰或电平翻转这种尤其难查因为它可能只在电机起停瞬间出现。现场表现也很直观。用监控软件在线看CPU扫描周期一般是几毫秒到几十毫秒你肉眼在监控表里常看到某个BOOL量闪烁或者某个计数器的数值连续加了好几下本质上就是同一个物理动作触发了多次有效边沿。我见过最夸张的一次是某设备上一个行程开关按一次按钮计数器从0跳到57根本没法用。1.2 软硬件消抖的取舍对付抖动现场常用的手段分两层。硬件层给输入点并联RC滤波器或者用带滤波器的输入端子模块。像西门子SMATIC一些数字量输入模块本身就有一个几个毫秒级的数字滤波参数可配可以滤掉一部分毛刺。硬件滤波的好处是不过多占程序逻辑缺点是需要改接线、换模块而且RC参数固定之后不灵活。尤其点位数多、改造量大的时候回来改电路板非常痛苦。软件层在PLC程序里写一个延迟判断逻辑用一个定时器或计数器只有信号持续维持一个设定时间后才认为它是有效状态。这就是我们常说的消抖功能块。它的好处是灵活性极高同一个功能块可以给不同点位配置不同的消抖时间不用动一根线直接改参数就行。而且不太受硬件型号限制三菱、西门子、Codesys、汇川这些主流平台都能用同一种思路实现。从我个人的经验看硬件滤波适合做“第一道粗筛”软件消抖负责“精确认定”。真正核心的快逻辑、安全逻辑还是得靠程序里的功能块兜底。硬件能滤掉一部分高频干扰但低速弹跳、阈值反复穿越这类情况软件定时器更可靠。1.3 消抖时间参数的选择逻辑功能块能不能用关键看参数设多少。消抖时间太短滤不干净太长会丢掉真实信号尤其是高频计数、快速取反的场景还会让响应滞后变得明显。一般可以参考这些经验值普通按钮、旋钮、继电器触点20ms到50ms比较合适。人在按按钮时触点弹跳一般不超过10ms留两到三倍余量已经足够同时不会让人觉得响应“肉”。接近开关、光电开关常规检测点位10ms到30ms。看现场干扰情况如果线缆长、旁边有变频器可以提到50ms。计数和位置检测类尽量设置在2ms到5ms或者干脆不用软件消抖靠高速计数器模块处理。因为计数信号一旦滤波时间太长轮盘转快了脉冲就直接被吞掉误差很感人。要注意这儿说的“时间”最终是几倍扫描周期。如果扫描周期是10ms你设了20ms消抖实际判断一次最快也要两个扫描周期也就是20ms以上。这点在做时间敏感逻辑时要想清楚。2. 功能块设计把消抖做成一个标准封装2.1 输入输出接口定义要写功能块第一步不是码代码而是想清楚接口。消抖功能块对外至少需要这些端口输入信号bIn原始、未经过滤的信号。消抖时间tTime单位用毫秒TIME或TON类型。输出信号bOut经过消抖后判定的稳定信号。上升沿输出bRising检测到消抖后信号的上升沿。下降沿输出bFalling检测到下降沿。此外内部需要一个定时器以及一个标记“当前暂态”的中间变量。有人会问为什么输出信号之外还要上升沿/下降沿因为在实际项目里很多动作并不需要持续电平而是用一个瞬时脉冲去触发。比如按钮启动按下一次只需要一个上升沿脉冲如果直接用稳定信号去置位线圈按钮一直按住时线圈就不会复位有时候正是我们想要的自锁效果但有时候又会引起误触发。所以把沿信号一起留出来调用端按需取用更方便。端口命名建议统一比如inSignalfilterTimeoutSignaloutRisingoutFalling这套接口可以跨平台映射到任意PLC环境里换平台时只改内部实现。2.2 结构化文本实现用TON把它自然写出来我一般用结构化文本ST写逻辑思路最清晰。下面的代码以Codesys风格的ST为基础三菱、博途、汇川改改类型声明就能用。FUNCTION_BLOCK FB_Debounce VAR bTimerStart : BOOL : FALSE; tonDebounce : TON; END_VAR VAR_INPUT bIn : BOOL; tFilterTime : TIME : T#20MS; END_VAR VAR_OUTPUT bOut : BOOL : FALSE; bRising : BOOL : FALSE; bFalling : BOOL : FALSE; END_VAR // 核心逻辑只有输入信号持续达到设定时间才更新输出 IF bIn bOut THEN bTimerStart : TRUE; // 启动定时器持续检测直到时间到达 tonDebounce(IN : bTimerStart AND bIn, PT : tFilterTime); IF tonDebounce.Q THEN bOut : bIn; bRising : bOut AND NOT bPrevOut; bFalling : NOT bOut AND bPrevOut; bPrevOut : bOut; END_IF ELSE bTimerStart : FALSE; tonDebounce(IN : FALSE); bRising : FALSE; bFalling : FALSE; bPrevOut : bOut; END_IF这里用到了TON定时器输入bIn发生变化时开始计时若在计时期间bIn又变回去了定时器会自动清零不会误判。只有当bIn持续保持新状态超过tFilterTime后才把bOut更新为新值。而bRising/bFalling通过比较上一次稳定输出bPrevOut来生成。初次接触这个逻辑的PLC编程入门学习者容易陷入“为什么不直接用TON定时器非要把bTimerStart变量接进来”的疑问。原因很简单不带使能端的TON在输入掉回旧状态时Q输出保持一段时间不严格。这里用“与上bIn”来确保如果输入已经反转定时器立刻被禁止复位避免在半途定格。说句实在话像三菱的定时器OUT指令在功能块里做循环调用容易出各种肚子的坑用ST写TON是更稳妥的方案。如果只能用梯形图请参考下一节。2.3 梯形图版本与扫描周期原理很多老师傅还是习惯用梯形图写逻辑。梯形图版本的消抖功能块在思路上通常有两种做法。一种是“定时器保持”法输入信号x0先把它和定时器线圈串联定时器设定值设为消抖时间。输入有高电平后定时器开始计时计时到达后定时器触点接通再把一个内部中间继电器M50置位。同时M50的常开触点并联在定时器线圈两端起到保持作用除非输入重新变为OFF定时器线圈断开M50复位。这个逻辑把“信号持续为ON超过设定时间”转化成“定时器计时完成后M50一直保持”。另一种是“计数器窗口”法利用PLC的扫描周期计数每扫描一次做一次累加当输入为OFF时清零累计达到设定的“次”数后输出为ON。这种适合没有定时器指令的老PLC但分辨率不稳定因为扫描周期会随程序长短变化。所以我还是偏向于TON。无论哪种都要理解扫描周期的影响。PLC从输入采集到程序扫描再到刷新的周期本身不是绝对固定功能块里的定时器依靠PLC内部定时器中断或系统时钟计时时间基准是准的但判断边沿、刷新输出都发生在扫描周期的末尾。所以整个消抖链路的实际延时大约是消抖时间加上一个到两个扫描周期。这在涉及安全回路的场合必须留足余量不能一套参数全世界通吃。3. 典型场景实战按钮启动停止与传感器计数3.1 场景一普通按钮的启动停止最经典的“启动停止”按钮直接用消抖后的信号和沿信号就非常舒服。按钮X0接启动X1接停止分别接两个功能块实例。启动按钮的bRising沿用来置位电机线圈M0停止按钮的bRising沿用来复位M0。这样做的好处显而易见不用担心按钮触点抖出的多次变化不会出现按一下起两个操作。利用沿而不是电平即使操作员按住按钮不松手也只会触发一次置位不会反复启动。停止按钮如果误按一下不小心抖出一下也会被认为是一次有效停止但这本来就是操作员动作物理弹跳造成的问题已经滤掉了。有人会问停止按钮要不要用常闭触点接线我的建议是需要急停的回路用常闭普通启停用常开。功能块只管软件抖动硬件安全仍要遵循对应标准不要混在一起。3.2 场景二接近开关与高速计数接近开关检测齿轮齿数或者输送带上工件计数这种场景最考验消抖块的参数取舍。我之前有个项目检测旋转轴上六个齿形凸台转速最高3600转/分齿轮每转产生6个脉冲算下来最高频率约360Hz脉冲周期约2.8ms。如果我把消抖时间设成20ms那一个信号周期都撑不过去输出来不及翻转就被判定成无效计数值会少得可怜。这时候必须放弃通用消抖逻辑改用高速计数模块或者把消抖时间压到1ms以内。但1ms在普通PLC扫描周期内又几乎不可实现。另一个常见问题是接近开关在临界位置时反复ON/OFF但因为运动速度慢持续时间长消抖时间设成50ms也不影响采样率反而能滤掉抖动。所以做现场应用时要先估算信号额定频率再反推消抖时间上限。规律很简单最高信号频率下信号ON最短时间或OFF最短时间应大于消抖时间否则该状态永远不会被认定。对于计数信号消抖时间尽量不超过信号周期的三分之一否则边沿会严重滞后。表格里我给个参考应用类型典型信号频率推荐消抖时间普通按钮1Hz20ms~50ms输送带光电计数10Hz~50Hz5ms~10ms齿轮凸台检测200Hz~500Hz不用普通功能块改用高速计数电机正反转反馈几Hz30ms~100ms防误动这表是我拍脑袋定的吗不是是从项目调试记录里归纳的。你只要记住参数没有万能值只有现场调出来的值。3.3 场景三在博途/Codesys/三菱中的调用方式写好的功能块在不同平台里调用的方式大同小异。在西门子博途TIA Portal里把功能块放到程序库的“函数块”文件夹下然后在OB1里拖出来为每个输入点建一个背景数据块。比如按钮A对应DB_A接近开关B对应DB_B。这样每个实例都能单独设置过滤时间互不干扰。在Codesys系列平台里更简单直接把功能块当成一个类型在程序区声明局部变量比如VAR db1 : FB_Debounce; db2 : FB_Debounce; END_VAR然后赋值调用db1(bIn : X1, tFilterTime : T#30MS); Q1 : db1.bOut;三菱GX Works里不支持POU复用同一个ST功能块那么自由一般是用子程序或FB块实现三菱的FB也有类似结构。如果你习惯用梯形图就把功能块整体复制到主程序里然后用不同的M点代替内部变量。调用次数多了以后我建议做一个“素材库”文件夹专门存放这类基础功能块旁边加上注释说明版本和更换日期这样后面维护起来会比翻旧程序舒服得多。4. 调试排障实录消抖功能块不工作的几个坑4.1 信号一直被过滤时间参数过大问题踩过最多的坑是把消抖时间设得过大尤其从别处复制来的程序没看参数就直接用。原本按钮只要20ms结果功能块里留着200ms按下去半天才反应。你在线看输出信号一直是0监控原始输入已经变成1了但输出还在0上往往就是过滤时间太长。还有更隐蔽的信号是脉宽本身只有100ms的短信号消抖时间也设了100ms这样哪怕信号没有抖动也几乎无法被识别因为“有效”条件要求100ms内必须持续为ON但实际上只ON了99ms定时器刚要到点就断电复位了。这种问题在自动化计数、气缸到位检测里很常见。排查思路把过滤时间临时改成0或1ms看输出是否能正常变化。如果能就说明是时间参数过大或者是信号本身脉宽不足然后根据实际脉宽重新设值。4.2 信号仍然抖动时间参数太小与硬件残留设置10ms消抖时间但用在线监控看输出偶尔还是会跳一下。这里头有两个可能。一个是物理弹跳持续时间超过10ms尤其在老旧接触器上触点弹跳最长可以到几十ms。这种不仅要把参数调大最好在硬件侧也处理一下比如在端子排上并联RC吸收回路。另一个是信号线上叠加了干扰在输入模块内部形成了几十毫秒的低电平毛刺。这种毛刺是不是“抖动”严格说不是触点弹跳而是电气噪声但软件功能块一样可以滤掉一部分。问题是如果噪声持续时间长、反复出现消抖时间要设到几百毫秒才压得住但这样正常工作也会受影响。我后来学到的办法是先用示波器挂到PLC输入端子处看波形确认毛刺形态和持续时长。如果是尖峰干扰优先查线缆屏蔽层、接地、走线路径如果单纯是触点弹跳加消抖时间就行。不要一上来就只改功能块参数否则治标不治本。4.3 定时器复位与扫描周期不一致常见逻辑错误自己手写消抖逻辑时最容易出现“输出沿疯狂重复触发”的问题。原因多出在沿信号生成的地方。比如用TON定时器当输入保持稳定很长一段时间后你希望比较器只在状态变化那一刻输出一个扫描周期的脉冲。但有人会把沿输出这么写bRising : bIn AND NOT bPrevIn;这里bPrevIn是原始输入原始输入抖动导致bPrevIn和bIn在你更新前又相等了会出现沿丢失或重复。正确的做法是把bRising放在消抖后的输出与上一个消抖输出比较也就是我代码里用bPrevOut的那个位置。还有在一个扫描周期里如果你在功能块内部既改变了bOut又在最后一行比较bOut有可能因为扫描顺序问题导致bRising在同一个周期里连续触发。解决办法是把bRising、bFalling的赋值放在功能块末尾的同一段并且保证每次扫描只按一次逻辑计算实在不行就在主程序里用上升沿指令对bOut再做一次边沿提取。碰到这种疑难杂症最好的排查方法不是看代码段想而是把在线监控里所有相关变量都拉在一起加个趋势图按时间轴看bIn、bTimerStart、tonDebounce.Q、bOut、bRising一眼就能看出定时器状态和输出是否匹配。5. 从消抖块到更通用的数字量处理组件5.1 上升沿/下降沿分离扩展一个消抖功能块并不只是用来“过滤”它完全可以扩展成边缘检测功能块。在上面代码里输出已经包含bRising和bFalling这就是一个带消抖的沿检测器。实际应用中我们可以基于它再封装一个“延时断开”功能块或者在输出后并联一个TOF定时器做“掉线保持”。比如设备紧急信号来了虽然现场环境干扰很大但只要检测到上升沿就要锁定报警这样就需要在功能块里加一个锁存输出。这种模块化思路我用得很顺手。基础的功能块只负责最基本的功能上面再一层一层包逻辑类似盖房子时先做好地基框架再填墙出问题时分开排查比较快。5.2 与触摸屏、PID调节等场景联动别以为消抖功能块只跟数字量输入有关。现场很多PID回路比如温度PID波动温差大的问题有一部分就是从PV侧的测温信号引入干扰引起的。热电偶信号在PLC中经过模拟量转换后变成数字量如果这组数字量变化频繁FB的反向计算就会一直抖。虽然模拟量不能用BOOL消抖但可以把算法思路迁移过来设一个小的变化死区只有变化量超过死区时才更新PV值等于是“模拟量消抖”。这个思路跟PLC数字量消抖一样都需要做“时间窗口幅度窗口”判断。以前我调试一条生产线上的恒温炉就是因为在程序里加了个死区功能块PV波动幅度小了一半以上温控曲线才真正稳下来。触摸屏上也可以在画面里加一个滚动显示当前消抖时间的功能让现场调试人员可以临时微调不用每次连电脑编译下载。做非标设备时这种“参数可调”的体验特别好客户会觉得自己项目是“可配置”的而不是写死的。5.3 我的经验分享功能块库维护与复用最后分享一点我个人的习惯。我电脑里有个文件夹叫“功能块库”按年份分类文件名带上项目编号。每写一个新功能块我会在同一文件里放三部分功能说明、代码或梯形图、测试数据记录。测试数据记录里写清楚在哪个PLC型号上跑过、扫描周期大致多少、设了多少消抖时间、实际效果如何。这样做的好处是以后再遇到类似项目直接调出来复制改参数就能用不用重新推导演算。而且遇到稀奇古怪的故障时翻旧记录往往会发现原来两年前就碰到过一模一样的现象当时怎么解决的直接找出来就少走弯路。像消抖功能块这种基础组件确实不显眼但它决定了整套程序的上限。有一次我在活动项目头天晚上把所有输入信号都加了消抖第二天调试人员说很奇怪现场电机动作变得非常有条理以前那些莫名奇妙的报警全没了。我笑了笑心想这大概就是消抖功能块的隐形价值吧。我自己的体会是写程序最怕的不是功能有多复杂而是忽略了那些最基础的工程细节。每次把这个小功能块加到自己的“每周一例”清单里其实是在提醒自己处理现场问题先让信号干净了后面的逻辑才谈得上准确。
返回列表