4. 电流检测法实战:采样电阻选型、运放电路设计、ADC采样配置、阈值设定策略
电流检测,说白了就是电机的“听诊器”。堵转时电流会飙升,你如果能准确捕捉到这个信号,保护就成功了一半。我这些年调试无感启动,踩过最多的坑就在电流检测这一块。不是采样电阻烧了,就是运放输出饱和了,再不然就是ADC采了一堆噪声。
今天咱们就把这条链路从头到尾捋一遍。从电阻选型,到运放设计,再到ADC配置和阈值策略,每一步我都会把实际项目里踩过的坑指出来。
核心链路: 采样电阻 → 差分运放 → ADC采样 → 软件阈值判断
任何一个环节出问题,堵转保护都会失效。
4.1 采样电阻选型:别只看阻值
很多人选采样电阻,上来就问“用多少毫欧”。其实这只是第一步。我见过一个项目,工程师选了5mΩ的电阻,结果电机启动瞬间电流一冲,电阻直接冒烟了。为什么?功率没算够。
选型时我习惯按三个维度来卡:
- 阻值: 一般1mΩ ~ 10mΩ。阻值太小,信号太弱,运放需要高增益,噪声也跟着放大。阻值太大,发热严重,效率下降。
- 功率: 按最大堵转电流的1.5倍来算。比如堵转电流30A,电阻5mΩ,功率P = I²R = 30² × 0.005 = 4.5W。选个5W以上的,留余量。
- 电感: 这个容易被忽略。普通绕线电阻有寄生电感,高频PWM电流通过时会产生尖峰电压,轻则干扰采样,重则击穿运放。我建议用金属膜电阻或锰铜电阻,电感极低。
我的习惯: 低压电机(12V~48V)用2mΩ~5mΩ,高压电机(220V以上)用1mΩ左右。功率留2倍余量,电感控制在10nH以下。
4.2 运放电路设计:差分放大是王道
采样电阻两端的电压是mV级的,而且共模电压很高(母线电压的一半)。你如果用单端放大,共模噪声会直接把信号淹掉。所以必须用差分运放。
我常用的电路结构是这样的:
采样电阻两端 → 差分输入 → 运放(如LMV358、AD8418) → 输出到ADC
设计时注意几个关键点:
- 放大倍数: 根据ADC参考电压来算。比如ADC是3.3V,采样电阻最大压降50mV,那放大倍数就是3.3 / 0.05 = 66倍。实际取60倍左右,留一点余量。
- 共模抑制比(CMRR): 选CMRR在80dB以上的运放。我踩过坑,用了一颗CMRR只有60dB的运放,电机一转,采样值跟着母线电压波动,根本没法用。
- 偏置电压: 如果电机电流是双向的(正转/反转),需要给运放加一个偏置电压,把信号抬到ADC量程中间。比如偏置到1.65V,这样正负电流都能采到。
我曾经踩过的坑: 运放输出直接连ADC,没加RC滤波。结果PWM开关噪声耦合进来,ADC采出来的值跳得像心电图。后来在运放输出和ADC之间加了一阶RC低通滤波(截止频率约10kHz),问题解决。
4.3 ADC采样配置:时机比频率更重要
ADC采样不是越快越好。你想想看,电机电流是正弦波,你如果随机采样,采到的可能是波峰、波谷或者过零点,算出来的有效值偏差很大。
我建议用同步采样的方式:
- 触发源: 用PWM定时器触发ADC。每个PWM周期在固定相位点(比如中心对齐的波谷)触发一次采样。
- 采样率: 一般每个PWM周期采一次就够了。PWM频率16kHz,采样率就是16kHz,完全够用。
- 分辨率: 12位ADC是底线。如果MCU支持16位,尽量用16位。我试过8位ADC,电流变化10%才能分辨出来,堵转保护根本来不及反应。
配置代码示例(基于STM32 HAL库):
// ADC配置:PWM触发,12位分辨率
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换,由PWM触发
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; // 定时器1通道1触发
HAL_ADC_Init(&hadc1);
小技巧: 如果MCU支持过采样,可以开16倍过采样,等效分辨率能提升到14位。代价是采样时间变长,但16kHz的PWM周期下完全够用。
4.4 阈值设定策略:动态 vs 静态
阈值设死了,电机在不同负载下容易误触发或者漏保护。我一般用动态阈值策略。
具体做法:
- 静态阈值: 作为底线保护。比如额定电流的2倍,超过就直接停机。这个阈值不能设得太低,否则启动瞬间的浪涌电流会误触发。
- 动态阈值: 根据当前运行电流实时调整。比如正常运行时电流是1A,动态阈值设为1.5A。如果电流突然跳到2A,说明堵转了。
我习惯用滑动窗口均值来做动态阈值:
// 动态阈值计算
#define WINDOW_SIZE 10
uint16_t current_buffer[WINDOW_SIZE];
uint8_t index = 0;
uint16_t get_dynamic_threshold(void) {
uint32_t sum = 0;
for (int i = 0; i < WINDOW_SIZE; i++) {
sum += current_buffer[i];
}
uint16_t avg = sum / WINDOW_SIZE;
return avg * 1.5; // 1.5倍作为动态阈值
}
这个策略的好处是:电机启动时电流大,动态阈值也跟着抬高,不会误触发。堵转时电流持续偏高,动态阈值跟不上,保护就会动作。
阈值设定总结:
| 阈值类型 | 设定值 | 触发条件 |
|---|---|---|
| 静态阈值(硬保护) | 额定电流 × 2.5 | 超过立即停机 |
| 动态阈值(软保护) | 滑动均值 × 1.5 | 持续超过100ms |
| 启动阈值(特殊处理) | 额定电流 × 3.0 | 启动后200ms内有效 |