4、电流采样与ADC配置:电流检测电阻、运放电路、STM32 ADC多通道采样、DMA传输
电机控制里,电流采样是闭环控制的基础。说白了,你PID算得再准,电流采回来是错的,那一切都是白搭。我刚开始做FOC的时候,就吃过这个亏——电流波形看着挺好,电机一转起来就抖,查了半天,结果是ADC采样时序没配好。
这一章,咱们就把电流采样这条链路从头到尾捋一遍。从硬件上的检测电阻和运放,到STM32的ADC多通道配置,再到DMA传输,一步都不能省。
4.1 电流检测电阻与运放电路
先说说硬件端。电流采样最常用的方式就是串联一个毫欧级电阻,然后通过运放把电阻两端的微弱电压放大到ADC能采的范围。
4.1.1 检测电阻选型
检测电阻的选择有几个关键点:
- 阻值:一般在1mΩ~50mΩ之间。阻值越大,信号越强,但功耗也大。我一般控制在额定电流下压降不超过50mV。
- 功率:要留够余量。比如电机峰值电流10A,用10mΩ电阻,峰值功耗就是1W,选2W以上的比较稳妥。
- 温漂:尽量选低温度系数的,比如±50ppm/℃以下。温漂大了,电流采样会随温度飘,你想想看,PID参数调好了,跑一会儿电机热了,电流值就变了,那还怎么控?
4.1.2 运放电路设计
运放的作用是把差分小信号放大到ADC的输入范围(通常是0~3.3V)。常用的电路是差分放大或仪表放大。
这里有个坑——运放的共模输入范围。电机驱动是高压环境,母线电压可能几十伏,而采样电阻两端的共模电压就是电机相电压。如果运放的共模输入范围不够,输出就会失真。
运放电路的关键参数:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 增益 | 10~100倍 | 根据采样电阻和ADC范围计算 |
| 带宽 | >1MHz | PWM频率通常10~20kHz,带宽要够 |
| 失调电压 | <1mV | 失调大了,低电流时误差很大 |
| 共模抑制比 | >80dB | 抑制共模干扰,保证差分信号质量 |
4.2 STM32 ADC多通道采样
硬件搭好了,接下来就是STM32的ADC配置。电机控制通常需要同时采集两相或三相电流,所以要用到多通道采样。
4.2.1 ADC硬件资源
STM32的ADC有几种模式:
- 单次转换:每次触发只转一个通道,适合低速场景。
- 连续转换:自动循环转换,但CPU负担重。
- 扫描模式:一次触发转换多个通道,配合DMA使用最合适。
电机控制里,我一般用规则组扫描模式,把三相电流的ADC通道放在一个规则组里,一次触发就把所有电流都采完。
4.2.2 采样时序与触发源
这里有个关键点——采样时刻。PWM开关管导通和关断时,会有很大的开关噪声。如果ADC在噪声大的时候采样,数据肯定不准。
我的做法是:用PWM的定时器作为ADC触发源,把采样点放在PWM周期的中间时刻。这时候开关管已经稳定了,噪声最小。
配置示例(以STM32G4为例):
// 配置ADC1,规则组扫描模式,3个通道
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; // 扫描模式
hadc1.Init.ContinuousConvMode = DISABLE; // 不连续,由外部触发
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_TRGO; // TIM1触发
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 3; // 3个通道
HAL_ADC_Init(&hadc1);
4.3 DMA传输
ADC转换完的数据,如果不及时搬走,就会被下一次转换覆盖。用DMA是最优雅的方式——转换完成自动把数据搬到内存,CPU只管算PID就行。
4.3.1 DMA配置要点
DMA配置有几个地方要注意:
- 传输方向:外设到内存,ADC是源,内存数组是目标。
- 数据宽度:ADC是12位,但寄存器是16位或32位,对齐好就行。
- 循环模式:开启,这样每次触发都会自动传输,不用反复配置。
- 内存地址递增:开启,让数据依次存到数组的不同位置。
// DMA配置,把ADC数据搬到电流数组
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; // 内存地址递增
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_adc1);
// 连接DMA和ADC
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
4.3.2 数据对齐与处理
DMA搬过来的数据是原始ADC值(0~4095),要转换成实际电流值。转换公式很简单:
// 电流计算
float current = (adc_value - offset) * vref / 4096.0f / gain / Rshunt;
// adc_value: DMA搬来的原始值
// offset: 零电流时的ADC值(中点偏置)
// vref: ADC参考电压,通常3.3V
// gain: 运放增益
// Rshunt: 采样电阻阻值
4.4 整体架构与流程图
把上面这些串起来,整个电流采样链路就是:
电流 → 采样电阻 → 运放放大 → STM32 ADC多通道采样 → DMA传输 → 内存数组 → 电流计算 → 送给PID
下面这张图把整个流程和关键节点都画出来了,你可以对照着看:
4.5 常见问题与避坑指南
最后,分享几个我在实际项目中遇到的问题:
- 采样噪声大:检查采样时刻是否在PWM开关噪声区,调整触发点。
- 电流零点漂移:运放失调电压和温漂导致,用软件校准offset。
- DMA数据错位:检查内存地址递增是否开启,通道顺序是否和DMA数组对应。
- ADC转换时间不够:采样周期太短,适当降低ADC时钟或增加采样时间。
嗯,电流采样这块就讲到这里。硬件选型、运放设计、ADC配置、DMA传输,每一步都关系到最终的控制效果。你把这些吃透了,后面的PID整定才能建立在可靠的数据基础上。