夜雨聆风学习资料网

ARTICLE · 1295300

IO 口偶尔出现毛刺误触发?分享一套实用软件滤波算法

IO 口偶尔出现毛刺误触发?分享一套实用软件滤波算法

前言

在PCBA上有一些过大电流的地方,如果有I/O电平操作,这时就容易受干扰,可能会偶发出现一个毛刺,影响功能。为了设备稳定运行,通常会采用I/O口滤波处理,把偶发的毛刺给过滤掉。

一、简介

在PCBA设计过程中,大电流走线附近往往伴随着较强的电磁干扰。如果此时旁边有I/O信号线在进行电平操作,就极易受到耦合干扰,导致MCU读取到偶发的毛刺信号。

这种毛刺如果被程序误判为有效电平,轻则导致LED闪烁异常,重则引发误触发、状态机错乱,影响设备稳定运行。

为了解决这个问题,通常我们会采用I/O口滤波处理,通过软件算法把偶发的毛刺给过滤掉。

二、I/O电平滤波算法

下面是一个经典的计数式滤波算法,核心思想是:连续检测到N次相同电平后,才确认该电平有效。

1. 数据类型定义

//数据类型定义typedefenum IoLevel_e{    PS_IO_LEVEL_HIGH,    PS_IO_LEVEL_LOW,    PS_IO_LEVEL_NUM}g_emIoLevel;g_emIoLevel g_emLedLevel = PS_IO_LEVEL_NUM;

2. I/O电平滤波处理函数

//I/O电平滤波处理g_emIoLevel PS_GetIoElecLevel(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint16_t u16FiltNum){static g_emIoLevel semRetVal = PS_IO_LEVEL_NUM;staticuint16_t s_u16HighLevelCnt = 0;staticuint16_t s_u16LowLevelCnt = 0;if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == GPIO_PIN_SET)    {        s_u16HighLevelCnt++;if(s_u16HighLevelCnt > u16FiltNum)        {            s_u16HighLevelCnt = 0;            semRetVal = PS_IO_LEVEL_HIGH;        }        s_u16LowLevelCnt = 0;    }else    {        s_u16LowLevelCnt++;if(s_u16LowLevelCnt > u16FiltNum)        {            semRetVal = PS_IO_LEVEL_LOW;        }        s_u16HighLevelCnt = 0;    }return semRetVal;}

3. 函数调用示例

/***********************函数调用****************************/g_emLedLevel = PS_GetIoElecLevel(GPIOA, GPIO_PIN_0, 500);if(g_emLedLevel == PS_IO_LEVEL_HIGH){    HAL_GPIO_WritePin(LED4_GPIO_PORT, LED4_PIN, GPIO_PIN_SET);}elseif(g_emLedLevel == PS_IO_LEVEL_LOW){    HAL_GPIO_WritePin(LED4_GPIO_PORT, LED4_PIN, GPIO_PIN_RESET);}

三、算法原理解析

这个算法的逻辑非常清晰,核心在于两个计数器和一个阈值:

变量
作用
s_u16HighLevelCnt
高电平连续计数
s_u16LowLevelCnt
低电平连续计数
u16FiltNum
滤波阈值(调用时传入,示例为500)

工作流程:

  1. 每次调用读取一次GPIO引脚状态。
  2. 如果是高电平,高电平计数器+1;如果此时低电平计数器不为0,则清零(说明之前不是连续低电平)。
  3. 当高电平计数器超过阈值u16FiltNum 时,才正式确认输出为高电平,并将计数器清零。
  4. 低电平逻辑同理。

为什么能滤除毛刺?

假设 u16FiltNum = 500,意味着需要连续500次调用都读到高电平,才会确认输出高电平。如果中间出现一次低电平毛刺,低电平计数器会+1,同时高电平计数器被清零,之前的计数全部作废。这样,单个或短时间的毛刺脉冲根本无法通过滤波。

四、使用注意事项

  1. 调用周期要稳定:该算法依赖调用频率,建议放在固定的定时器中断或主循环中周期性调用,保证滤波时间常数一致。
  2. 滤波阈值选择:u16FiltNum 越大,抗干扰能力越强,但响应速度越慢。需要根据实际信号频率和干扰程度权衡。
  3. 静态变量问题:函数内使用了 static 变量,意味着该函数不可重入。如果多个IO口需要滤波,建议将状态变量封装成结构体,或者为每个IO口单独写一个函数。
  4. 初始状态:semRetVal 初始为 PS_IO_LEVEL_NUM,调用方需要处理这个无效状态,避免上电瞬间误动作。

五、总结

I/O口滤波是嵌入式软件中非常实用的小技巧,成本低、效果好。对于PCBA上大电流干扰导致的偶发毛刺,这种计数式滤波算法能够有效提升系统的稳定性。

如果你也有类似的抗干扰经验,欢迎在评论区分享交流!

—— END ——

如果觉得有用,欢迎点赞、在看、转发三连支持一下~


【往期推荐】

充电宝新国标来了!GB 47372-2026全面解读

嵌入式C语言函数设计规范:一个健壮、可读性强的函数模板

环形队列(FIFO)的 C 语言实现:串口收发、ADC 采集都好用

低功耗 BLE 玄学 bug!杰理AW313A2 静置越久越容易死机

CBM8580 BMS 芯片量产完整开发流程:烧录、电芯建模、电压电流校准、充放电学习全步骤

英集芯IP5385偶发充不进电!从现象追踪到 SMBus 通信底层 bug 排查实录

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料