You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32L073RZ ADC通道切换失效问题求助

STM32L073RZ ADC通道切换异常问题

我使用STM32L073RZ的ADC通道6、7、8分别读取100个样本数据,因无法采用连续序列模式,需读完一个通道的100个样本后切换至下一通道。为简化测试,将样本数改为1并编写了对应代码。按电路设计,通道6、7、8应分别读取到78、130、190的ADC值,但实际代码运行后三个通道均返回78;调整读取顺序为7、6、8后,结果变为130、78、78。请问切换至通道6后出现了什么问题?


测试代码

MX_ADC_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */

HAL_TIM_Base_Start(&htim2);

select_adc_channel(6);
HAL_ADC_Start_IT(&hadc);
HAL_Delay(250);
uint8_t adc=HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);

select_adc_channel(7);
HAL_ADC_Start_IT(&hadc);
HAL_Delay(250);
adc=HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);

select_adc_channel(8);
HAL_ADC_Start_IT(&hadc);
HAL_Delay(250);
adc=HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);

MX_ADC_Init()代码

static void MX_ADC_Init(void)
{

  /* USER CODE BEGIN ADC_Init 0 */

  /* USER CODE END ADC_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC_Init 1 */

  /* USER CODE END ADC_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc.Instance = ADC1;
  hadc.Init.OversamplingMode = DISABLE;
  hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_8B;
  hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ContinuousConvMode = DISABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerFrequencyMode = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
}

select_adc_channel()代码

void select_adc_channel(uint8_t channel)
{
    ADC_ChannelConfTypeDef sConfig = {0};

    switch(channel)
    {
        case 0: sConfig.Channel = ADC_CHANNEL_0;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 6: sConfig.Channel = ADC_CHANNEL_6;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 7: sConfig.Channel = ADC_CHANNEL_7;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 8: sConfig.Channel = ADC_CHANNEL_8;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 9: sConfig.Channel = ADC_CHANNEL_9;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;

    }
}

问题根源分析

  1. 转换完成判断不可靠:
    代码中用HAL_Delay(250)等待转换完成,但外部触发(TIM2_TRGO)的转换时机与延时没有绑定,可能出现新通道的转换未实际执行,HAL_ADC_GetValue()读取的是ADC数据寄存器中保留的旧值(因配置了ADC_OVR_DATA_PRESERVED)。

  2. 通道配置参数缺失:
    select_adc_channel()函数仅配置了通道编号和Rank,未显式设置采样时间。虽然初始化时全局配置了采样时间,但部分HAL库版本在重新配置通道时,需要显式指定采样时间参数才能生效,否则可能导致新通道采样异常。

  3. ADC状态未正确复位:
    切换通道前未清除ADC的EOC(转换完成)、OVR(溢出)标志,也未确保ADC完全停止,直接启动新通道可能导致触发逻辑混乱,无法正确触发新通道的转换。


修复方案

方案1:用硬件标志判断转换完成

替换HAL_Delay(),通过ADC的EOC标志确认转换完成:

MX_ADC_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start(&htim2);

// 读取通道6
select_adc_channel(6);
HAL_ADC_Start_IT(&hadc);
while(!__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOC)); // 等待转换完成
uint8_t adc = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC); // 清除标志

// 读取通道7
select_adc_channel(7);
HAL_ADC_Start_IT(&hadc);
while(!__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOC));
adc = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC);

// 读取通道8
select_adc_channel(8);
HAL_ADC_Start_IT(&hadc);
while(!__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOC));
adc = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop_IT(&hadc);
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC);

方案2:完善通道配置参数

在select_adc_channel()中添加采样时间配置,与初始化保持一致:

void select_adc_channel(uint8_t channel)
{
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; // 新增采样时间配置

    switch(channel)
    {
        case 0: sConfig.Channel = ADC_CHANNEL_0;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 6: sConfig.Channel = ADC_CHANNEL_6;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 7: sConfig.Channel = ADC_CHANNEL_7;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 8: sConfig.Channel = ADC_CHANNEL_8;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 9: sConfig.Channel = ADC_CHANNEL_9;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
    }
}

方案3:切换通道前复位ADC状态

在切换通道前停止ADC并清除所有标志,确保状态干净:

// 切换通道前执行通用复位逻辑
HAL_ADC_Stop_IT(&hadc);
__HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOC | ADC_FLAG_OVR);
select_adc_channel(channel);

内容的提问来源于stack exchange,提问作者vishnu m c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:52:24