4. 软件保护方案:ADC采样策略、数字滤波算法、软件阈值判断、故障标志位管理

硬件保护像是个急性子的保安,一看到电流超标就立刻拉闸。但很多时候,电流尖峰只是电机换相时的正常现象,或者只是外部干扰。如果每次都触发硬件保护,电机根本没法正常转。

软件保护就是那个沉稳的工程师。它不急着下结论,而是先看看数据,分析一下,再决定要不要保护。说白了,硬件负责「快」,软件负责「准」。

核心思路:硬件保护做最后一道防线,软件保护做智能判断。两者配合,才能既保护硬件,又不误动作。

4.1 ADC采样策略:什么时候采?采几次?

ADC采样是软件保护的「眼睛」。眼睛不好使,后面算法再牛也没用。我见过不少项目,保护误触发,最后查出来是采样时机不对。

4.1.1 采样窗口的选择

BLDC 的相电流不是平滑的直流,而是 PWM 调制出来的脉冲波形。你想想看,如果在 PWM 开关管导通和关断的瞬间去采样,那数据肯定乱跳。

我个人习惯的做法是:

  • 单电阻采样:在 PWM 中心对齐的时刻采样。这时候电流最稳定,噪声最小。
  • 双/三电阻采样:在下桥臂导通期间采样。避开开关动作的尖峰。

小技巧:采样窗口要避开 PWM 边沿至少 1-2μs。我一般会在定时器里设置一个采样触发延迟,确保电流已经稳定了再启动 ADC。

4.1.2 采样频率与过采样

采样频率不是越高越好。太高了,CPU 忙不过来;太低了,又抓不住故障电流。

我一般这样配置:

应用场景 采样频率 说明
低速/轻载 10-20 kHz 电流变化慢,不需要高频采样
高速/重载 20-50 kHz 电流变化快,需要更密集的采样
过流保护专用 50-100 kHz 专门用于快速检测异常,可独立于控制环路

另外,我建议用过采样技术。比如,对同一个电流值连续采 4 次,然后取平均。这样能有效降低量化噪声。代价就是多占一点 CPU 时间,但换来的是更稳定的数据。

4.2 数字滤波算法:把噪声「洗」干净

ADC 采回来的数据,直接拿去判断阈值?别急,先过一遍滤波器。我在项目中遇到过,电机启动瞬间的电流尖峰,如果不滤波,软件保护会频繁误触发。

4.2.1 滑动平均滤波

这是最简单也最常用的方法。维护一个长度为 N 的缓冲区,每次采样都更新,然后取平均值。

// 滑动平均滤波示例
#define FILTER_LEN 8
uint16_t filter_buf[FILTER_LEN];
uint8_t filter_index = 0;

uint16_t moving_average(uint16_t new_sample) {
    uint32_t sum = 0;
    filter_buf[filter_index] = new_sample;
    filter_index = (filter_index + 1) % FILTER_LEN;
    
    for (int i = 0; i < FILTER_LEN; i++) {
        sum += filter_buf[i];
    }
    return (uint16_t)(sum / FILTER_LEN);
}

N 值越大,滤波效果越好,但响应也越慢。我一般取 4 到 8 之间。对于过流保护,响应速度很重要,所以 N 不能太大。

4.2.2 中值滤波

对付脉冲噪声(比如偶尔的尖峰干扰),中值滤波效果很好。把最近几次采样排序,取中间值。

嗯,这里要注意:中值滤波计算量大一些,不适合高频采样。我一般只在关键通道(比如相电流)上用,或者只在故障判断前用一次。

4.2.3 一阶低通滤波

如果你不想用缓冲区,可以用一阶低通滤波。它本质上是一个加权平均:

// 一阶低通滤波
#define ALPHA 0.8  // 滤波系数,0-1之间
uint16_t filtered_value = 0;

uint16_t low_pass_filter(uint16_t new_sample) {
    filtered_value = (uint16_t)(ALPHA * filtered_value + (1 - ALPHA) * new_sample);
    return filtered_value;
}

ALPHA 越大,滤波越平滑,但响应越慢。我习惯在调试时先设成 0.7,然后根据实际波形调整。

注意:数字滤波会引入延迟。对于过流保护,延迟不能超过 100μs,否则硬件可能已经烧了。所以,滤波算法要轻量,不能太复杂。

4.3 软件阈值判断:多级保护,层层递进

阈值判断不是简单的「超过就保护」。那样太粗暴了。我习惯设计多级阈值,不同级别对应不同的处理方式。

4.3.1 三级阈值设计

级别 阈值范围 动作 恢复方式
警告级 额定电流 × 1.2 记录日志,降低 PWM 占空比 电流回落后自动恢复
保护级 额定电流 × 1.5 立即关断 PWM,置位故障标志 需手动复位或延时重试
硬件级 硬件比较器设定值 硬件直接关断,不经过软件 需断电重启

为什么要分三级?因为有些过流是暂时的(比如负载突变),降功率就能扛过去。有些是严重的(比如相间短路),必须立刻停机。

4.3.2 滞回比较

直接比较阈值有个问题:电流在阈值附近抖动时,保护会频繁开启和关闭。这就像空调在设定温度附近频繁启停一样,很烦人。

解决办法是加滞回:

  • 保护触发阈值:1.5 倍额定电流
  • 恢复阈值:1.2 倍额定电流

也就是说,电流超过 1.5 倍才保护,但必须降到 1.2 倍以下才恢复。中间有个 0.3 倍的死区,避免频繁切换。

我的经验:滞回区间不要太小,否则等于没加。我一般设 20%-30% 的滞回量。具体数值可以在调试时用示波器观察电流波形来调整。

4.4 故障标志位管理:状态机思维

故障标志位不是简单的 0 或 1。我建议用状态机来管理。这样逻辑清晰,也方便扩展。

4.4.1 故障状态定义

typedef enum {
    FAULT_NONE       = 0x00,  // 无故障
    FAULT_WARNING    = 0x01,  // 警告级
    FAULT_OVER_CURRENT = 0x02, // 过流保护
    FAULT_HARDWARE   = 0x04,  // 硬件保护触发
    FAULT_LOCKED     = 0x80   // 锁定状态,需复位
} fault_status_t;

用位域的方式定义,可以同时记录多个故障。比如,同时有警告和过流,状态就是 0x03。

4.4.2 状态转移逻辑

我习惯用一个简单的状态机来处理:

  1. 正常状态:电流正常,无标志位。
  2. 警告状态:电流超过警告阈值,置位 FAULT_WARNING,降低功率。
  3. 保护状态:电流超过保护阈值,置位 FAULT_OVER_CURRENT,关断 PWM。
  4. 锁定状态:如果保护后电流仍然异常,或者硬件保护触发,进入锁定状态。必须断电或手动复位才能退出。

避坑指南:我曾经在项目里忘了清除故障标志位,导致电机保护后再也启动不了。后来我加了一个「自动恢复计数器」:保护后延时 1 秒,如果电流恢复正常,自动清除标志位。这样既安全又智能。

4.5 整体流程图

下面这张图展示了软件保护的完整流程。从 ADC 采样开始,到最终决定是否保护,每一步都很关键。

软件过流保护流程图 ADC 采样触发 PWM 中心对齐采样 滑动平均 / 低通滤波 超过 保护阈值? 否 是 清除故障标志 关断 PWM,置位故障 返回主循环 说明:整个流程从采样到判断,必须在 100μs 内完成,否则硬件保护会抢先动作。

4.6 调试建议

软件保护写好了,怎么验证?我分享几个实战经验:

  • 先用仿真器看数据:把 ADC 原始值和滤波后的值通过串口或 DAC 输出,用示波器观察。看看滤波效果是否满意。
  • 故意制造过流:堵转电机,或者短路一相(注意安全!),看软件保护是否及时响应。
  • 调整阈值:不要一次设死。先设一个宽松的值,然后逐步收紧,找到最佳平衡点。

安全提醒:调试过流保护时,一定要在电源回路中串联一个限流电阻或保险丝。我曾经因为疏忽,短路测试时直接把 MOS 管炸了。嗯,那味道,终身难忘。

软件保护方案的核心就这些。采样要准,滤波要稳,阈值要分级,标志位要管理好。把这几点做到位,你的 BLDC 驱动就能在「安全」和「性能」之间找到最佳平衡。