一、引言
在嵌入式数据采集系统中,STM32的ADC多通道扫描+DMA模式是高效采集多路模拟量的标准方案。然而,许多开发者在使用HAL库时,常遇到采样数据与通道不对应、数值异常(如高位错位、符号错误)等问题。这往往源于对采样顺序和数据对齐机制理解不足。本文将系统分析这两个陷阱,并提供完整的排查与解决方案。
二、原理讲解
2.1 规则组序列与采样顺序
STM32的ADC规则组支持最多16个通道的序列转换。在扫描模式下,ADC按SQRx寄存器中配置的顺序依次转换。HAL库通过ADC_ChannelConfTypeDef的Rank参数指定顺序(1~16)。关键点:DMA传输的数据顺序严格遵循Rank顺序,而非通道号顺序。例如,若配置Rank1=Channel3、Rank2=Channel1,则DMA缓冲区第0个元素对应Channel3,第1个元素对应Channel1。
2.2 数据对齐与DMA传输宽度
ADC转换结果可配置为左对齐或右对齐(12位模式下)。HAL库默认右对齐,即结果存储在低12位。DMA传输时,若外设数据宽度(PeriphDataAlignment)与内存数据宽度(MemDataAlignment)不匹配,会导致数据错位。例如,ADC为12位右对齐,若DMA配置为半字(16位)传输,则每个结果占用2字节,内存中低12位有效;若误配为字节传输,则高4位丢失,数据严重错误。
2.3 多通道DMA的缓冲区映射
DMA循环模式下,每次ADC序列转换完成(EOC触发)后,DMA将结果搬运至内存。缓冲区大小应为通道数 × 数据宽度。若缓冲区定义过小或DMA传输长度错误,会导致数据覆盖或越界。
三、CubeMX配置步骤
- 在Analog中启用ADC1,选择通道(如IN1、IN4、IN5)。
- 参数设置:
- Scan Conversion Mode: Enabled
- Continuous Conversion Mode: Enabled(或根据需求)
- DMA Continuous Requests: Enabled
- Data Alignment: Right alignment
- Number Of Conversion: 3(与通道数一致)
- 在Rank列表中按需排列通道顺序(如Rank1=IN1, Rank2=IN4, Rank3=IN5)。
- 在DMA Settings中添加ADC1的DMA请求:
- Mode: Circular
- Data Width: Half Word(外设与内存均设为Half Word)
- 生成代码。
四、完整代码示例
/* 定义缓冲区,大小为通道数 */
#define ADC_CHANNELS 3
uint16_t adc_buffer[ADC_CHANNELS];
/* ADC初始化与校准 */
void ADC_Init(void)
{
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = ADC_CHANNELS;
HAL_ADC_Init(&hadc1);
/* 配置通道顺序 */
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/* 校准并启动DMA */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_CHANNELS);
}
/* 主循环中读取数据 */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_DMA_Init();
MX_ADC1_Init();
ADC_Init();
while (1)
{
/* adc_buffer[0]对应Rank1(IN1),[1]对应Rank2(IN4),[2]对应Rank3(IN5) */
uint16_t ch1 = adc_buffer[0];
uint16_t ch4 = adc_buffer[1];
uint16_t ch5 = adc_buffer[2];
HAL_Delay(100);
}
}
五、常见陷阱与排查
5.1 采样顺序错乱
- 现象:数据与预期通道不匹配。
- 原因:Rank配置与缓冲区索引未对应;或CubeMX中Rank顺序与代码不一致。
-
排查:检查
SQR1/SQR2/SQR3寄存器值,确认Rank顺序;在DMA完成回调中打印缓冲区内容,对比已知电压。
5.2 数据对齐错误
- 现象:数值偏大(左对齐未右移)或偏小(高位丢失)。
-
原因:
DataAlign配置为左对齐但未右移4位;或DMA数据宽度误配为字节。 -
排查:确认
ADC_CR2的ALIGN位;检查DMA初始化中PeriphDataAlignment和MemDataAlignment均为DMA_PDATAALIGN_HALFWORD。
5.3 DMA传输长度与缓冲区不匹配
- 现象:数据错位、覆盖或HardFault。
-
原因:
HAL_ADC_Start_DMA的Length参数不等于通道数;缓冲区数组大小不足。 -
排查:确保Length = NbrOfConversion;缓冲区定义为
uint16_t且大小≥通道数。
5.4 未校准或采样时间过短
- 现象:数据跳动大、精度低。
- 原因:未执行ADC校准;采样时间小于信号源内阻要求。
-
排查:上电后调用
HAL_ADCEx_Calibration_Start;根据信号源阻抗增加采样周期。
六、注意事项
- 多通道扫描时,必须启用DMA,否则EOC中断频繁且易丢失数据。
- 若使用连续转换模式,DMA必须配置为循环模式,否则传输完一次后停止。
- 缓冲区建议使用
__attribute__((aligned(4)))确保对齐,避免DMA访问异常。 - 调试时可用
__HAL_DMA_GET_COUNTER检查剩余传输次数,判断DMA是否正常运行。 - 对于高精度场景,可在DMA完成回调中做软件滤波,但注意回调执行时间。
七、总结
掌握ADC多通道DMA扫描模式的关键在于:明确Rank顺序决定数据排列、严格匹配DMA数据宽度与对齐方式、确保缓冲区与传输长度一致。通过本文的原理分析与代码示例,开发者可快速定位并解决采样顺序错乱与数据对齐陷阱,构建稳定可靠的多通道采集系统。
暂无评论,来抢沙发~