1. 程式人生 > >STM32F0 中 ADC 多通道轉換結果相同的問題

STM32F0 中 ADC 多通道轉換結果相同的問題

type 前段時間 isp external res lin version splay flag

前言

前段時間調試 STM32F030 的 ADC,在多通道轉換時遇到了奇怪的問題,使用官方的例程和庫函數連續轉換多個 ADC 通道,得到的幾個通道的結果是一樣的,解決辦法參考了 關於STM32F0系列多路ADC單獨采樣數據相同問題的處理,在此表示感謝。

記錄

在官方庫的例程 ADC_BasicExample 中的初始化和轉換方法如下

ADC_InitTypeDef     ADC_InitStructure;
GPIO_InitTypeDef    GPIO_InitStructure;

/* GPIOC Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

/* Configure ADC Channel11 as analog input */
#ifdef USE_STM320518_EVAL
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
#else
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
#endif /* USE_STM320518_EVAL */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
  
/* ADCs DeInit */  
ADC_DeInit(ADC1);

/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);

/* Configure the ADC1 in continuous mode with a resolution equal to 12 bits  */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure); 

/* Convert the ADC1 Channel 11 with 239.5 Cycles as sampling time */ 
#ifdef USE_STM320518_EVAL
ADC_ChannelConfig(ADC1, ADC_Channel_11 , ADC_SampleTime_239_5Cycles);
#else
ADC_ChannelConfig(ADC1, ADC_Channel_10 , ADC_SampleTime_239_5Cycles);
#endif /* USE_STM320518_EVAL */

/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);

/* Enable the ADC peripheral */
ADC_Cmd(ADC1, ENABLE);     

/* Wait the ADRDY flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 

/* ADC1 regular Software Start Conv */ 
ADC_StartOfConversion(ADC1);

while (1)
{
    /* Test EOC flag */
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    
    /* Get ADC1 converted data */
    ADC1ConvertedValue =ADC_GetConversionValue(ADC1);
    
    /* Compute the voltage */
    ADC1ConvertedVoltage = (ADC1ConvertedValue *3300)/0xFFF;
    
    /* Display converted data on the LCD */
    Display();
}

可見庫函數中切換通道是使用 ADC_ChannelConfig(ADC1, ADC_Channel_11, ADC_SampleTime_239_5Cycles),在庫函數中 ADC_ChannelConfig 函數源碼如下

void ADC_ChannelConfig(ADC_TypeDef* ADCx, uint32_t ADC_Channel, uint32_t ADC_SampleTime)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_ADC_ALL_PERIPH(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));
    assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime));

    /* Configure the ADC Channel */
    ADCx->CHSELR |= (uint32_t)ADC_Channel;

    /* Clear the Sampling time Selection bits */
    tmpreg &= ~ADC_SMPR1_SMPR;

    /* Set the ADC Sampling Time register */
    tmpreg |= (uint32_t)ADC_SampleTime;

    /* Configure the ADC Sample time register */
    ADCx->SMPR = tmpreg ;
}

其中 ADCx->CHSELR |= (uint32_t)ADC_Channel 對寄存器賦值使用了“|”,這會造成下一次循環轉換時仍然轉換最高位通道
解決辦法是,在每次調用 ADC_ChannelConfig 之後,再對寄存器寫入

uint16_t ADC_Get_Result(uint32_t ch)
{
    ADC_ChannelConfig(ADC1, ch, ADC_SampleTime_239_5Cycles);
    ADC1->CHSELR = ch;
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)){};
    ADC_StartOfConversion(ADC1);
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){};
    return ADC_GetConversionValue(ADC1)&0x00000fff;
}

STM32F0 中 ADC 多通道轉換結果相同的問題