STM32 HAL库ADC多通道DMA扫描模式:采样顺序与数据对齐的配置陷阱与实战

一、原理讲解:扫描模式与DMA的协作机制

在STM32中,ADC多通道采集通常采用扫描模式(Scan Mode)配合DMA传输,以避免CPU频繁中断。其核心机制如下:

  • 扫描模式:ADC按预设的规则组序列依次转换多个通道。序列顺序由ADC_RegularChannelConfig()中的Rank参数决定(Rank 1最先转换)。
  • DMA请求:每次转换完成后,ADC产生DMA请求,将转换结果从ADC_DR寄存器搬运到用户指定的内存数组。
  • 数据对齐:ADC结果可配置为左对齐或右对齐(12位分辨率下,右对齐时数据位于低12位,左对齐时位于高12位)。

关键陷阱:许多开发者误以为DMA搬运顺序与通道编号一致,或忽略数据对齐导致数值错误。实际上,DMA搬运顺序严格遵循规则组的Rank顺序,且数据对齐方式直接影响读取值的解析。

二、CubeMX配置步骤

  1. 使能ADC:选择ADC1,勾选Scan Conversion Mode,Continuous Conversion Mode根据需求选择(单次或连续)。
  2. 配置规则组:在Rank列表中按顺序添加通道,例如Rank1=Channel0,Rank2=Channel1,Rank3=Channel4。
  3. 使能DMA:在DMA Settings中添加ADC1的DMA请求,模式为Circular或Normal,数据宽度为Half Word(16位)。
  4. 数据对齐:在ADC参数设置中,Data Alignment选择Right alignment(推荐)或Left alignment。
  5. 生成代码:确保HAL_ADC_Start_DMA()在初始化后调用。

三、完整代码示例

以下代码实现3个通道(IN0、IN1、IN4)的连续扫描+DMA采集,结果存入数组adc_values[3]。

#include "main.h"

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

uint16_t adc_values[3]; // 存放3个通道的转换结果

void ADC_Init(void)
{
    // 1. ADC时钟与GPIO初始化(略,由CubeMX生成)
    // 2. ADC参数配置
    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 = 3;
    HAL_ADC_Init(&hadc1);

    // 3. 配置规则组通道顺序(Rank 1 -> 2 -> 3)
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);

    sConfig.Channel = ADC_CHANNEL_1;
    sConfig.Rank = 2;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);

    sConfig.Channel = ADC_CHANNEL_4;
    sConfig.Rank = 3;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);

    // 4. 启动DMA传输
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_values, 3);
}

// DMA转换完成回调(可选)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1) {
        // adc_values[0]对应Rank1(IN0),[1]对应Rank2(IN1),[2]对应Rank3(IN4)
        // 用户数据处理
    }
}

四、注意事项与陷阱规避

  • 采样顺序陷阱:DMA数组索引与Rank顺序一一对应,而非通道编号。例如Rank1=IN4时,adc_values[0]是IN4的结果。务必在代码注释中明确映射关系。
  • 数据对齐陷阱:若配置为左对齐,12位结果位于高12位,直接读取会得到错误值。建议统一使用右对齐,或读取后右移4位(左对齐时)。
  • DMA传输宽度:必须设置为Half Word(16位),否则可能因字节对齐问题导致数据错位。
  • 规则组长度:NbrOfConversion必须与Rank数量一致,否则DMA搬运长度错误。
  • 连续模式与DMA循环:若使用ContinuousConvMode+DMA Circular,数组会不断被覆盖,需确保数据处理速度跟得上采样率。
  • 过采样与校准:多通道扫描时,建议在初始化后执行HAL_ADCEx_Calibration_Start(),并注意采样时间足够长(尤其高阻抗信号源)。

通过理解扫描序列与DMA的映射关系,并正确配置数据对齐,可避免绝大多数多通道ADC采集的“数据错位”问题。实际项目中,建议用已知电压源验证每个通道的映射顺序,确保万无一失。