4. ADC多通道同步采样配置

任务目标

本案例完成三相电流采样所需的ADC多通道同步采样配置。以STM32G4系列(内置3个ADC,支持注入组同步模式)为例,配置ADC1/ADC2/ADC3的注入通道,分别采样U相、V相、W相电流,由定时器触发实现三通道同步转换,转换完成后通过DMA将结果搬运至内存。

硬件连接与前置条件

  • 三相电流经采样电阻+运放后,分别接入MCU的PA0(ADC1_IN1)、PA1(ADC2_IN1)、PA2(ADC3_IN1)
  • 使用TIM1的TRGO事件作为ADC同步触发源,频率与PWM载波一致(如20kHz)
  • 需在CubeMX中完成时钟配置(ADC时钟设为系统时钟的1/4,即42.5MHz@170MHz主频)

关键完整代码

/* main.c 中用户代码区 */

/* 注入通道转换结果存储(3相) */
volatile uint16_t adc_inj_result[3];

/* ADC注入通道配置结构体 */
static void ADC_Injection_Config(void)
{
    ADC_InjectionConfTypeDef sConfigInjected = {0};

    /* ADC1:注入通道1 = IN1(U相) */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_1;
    sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
    sConfigInjected.InjectedNbrOfConversion = 1;
    sConfigInjected.InjectedSamplingTime = ADC_SAMPLINGTIME_12CYCLES_5;
    sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNAL_TRIGINJECCONV_T1_TRGO;
    sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNAL_TRIGINJECCONVEDGE_RISING;
    sConfigInjected.AutoInjectedConv = DISABLE;
    sConfigInjected.InjectedOffsetNumber = ADC_INJECTED_SOFTWARE_OFFSET_NONE;
    sConfigInjected.InjectedOffset = 0;
    if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
    {
        Error_Handler();
    }

    /* ADC2:注入通道1 = IN1(V相) */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_1;
    if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
    {
        Error_Handler();
    }

    /* ADC3:注入通道1 = IN1(W相) */
    sConfigInjected.InjectedChannel = ADC_CHANNEL_1;
    if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
    {
        Error_Handler();
    }
}

/* 同步触发启动:使能3个ADC的注入组转换 */
static void ADC_SyncTrigger_Start(void)
{
    /* 使能注入转换完成中断(可选,用于调试) */
    HAL_ADCEx_InjectedStart_IT(&hadc1);
    HAL_ADCEx_InjectedStart_IT(&hadc2);
    HAL_ADCEx_InjectedStart_IT(&hadc3);
}

/* 注入转换完成回调:读取3个ADC的注入通道结果 */
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1)
    {
        adc_inj_result[0] = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
    }
    else if (hadc->Instance == ADC2)
    {
        adc_inj_result[1] = HAL_ADCEx_InjectedGetValue(&hadc2, ADC_INJECTED_RANK_1);
    }
    else if (hadc->Instance == ADC3)
    {
        adc_inj_result[2] = HAL_ADCEx_InjectedGetValue(&hadc3, ADC_INJECTED_RANK_1);
    }
}

/* 主函数中调用(在MX_ADC1_Init等初始化之后) */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_ADC2_Init();
    MX_ADC3_Init();
    MX_TIM1_Init();

    ADC_Injection_Config();
    ADC_SyncTrigger_Start();

    /* 启动TIM1产生TRGO触发信号 */
    HAL_TIM_Base_Start(&htim1);

    while (1)
    {
        /* 主循环:adc_inj_result[0..2] 即为同步采样的三相电流ADC值 */
    }
}

关键配置说明

  • 同步机制:3个ADC的注入组均配置为TIM1_TRGO上升沿触发,同一时刻启动转换,实现硬件级同步采样
  • 采样时刻:TIM1_TRGO由更新事件产生,对应PWM周期起始点,此时三相下桥臂导通,采样电流为真实相电流
  • 结果读取:每个ADC仅配置1个注入通道,转换完成后进入回调,分别读取对应ADC的结果寄存器

验证方法

  1. 编译烧录后,在回调函数中设置断点,观察三个ADC是否在同一个TIM1中断周期内依次进入回调
  2. 用信号发生器在PA0/PA1/PA2输入1.5V直流偏置+0.5Vpp正弦波,读取adc_inj_result数组,确认三通道波形一致且无相位差
  3. 预期输出:当输入为1.5V直流时,12位ADC(参考电压3.3V)的转换结果约为 1.5/3.3*4095 ≈ 1861,三个通道读数偏差应在±5 LSB以内

常见问题

  • 触发不生效:确认TIM1_TRGO已正确映射(通过TIM1的CR2寄存器设置MMS=更新事件),且ADC外部触发极性配置为上升沿
  • 结果始终为0:检查注入通道是否已使能,以及是否调用了HAL_ADCEx_InjectedStart_IT启动转换
  • 三通道不同步:确认3个ADC的触发源均为TIM1_TRGO,且未使用软件触发