参考链接:关于STM32F0系列多路ADC单独采样数据相同问题的处理
文中博主已经详细说明了采集ADC多通道数据的方法,但是代码有一处BUG,运行时容易造成死循环。
查看STM32F030参考手册
12.12.8章节ADC 通道选择寄存器 (ADC_CHSELR)
代码中涉及配置到CHSELR寄存器前,必须要确保ADC_CR寄存器的位2:ADSTART=0 时 ( 确定无进行中的转换 ) 才允许改写这些位。
12.12.3ADC 控制寄存器 (ADC_CR)
位 4 ADSTP: ADC 停止转换命令:该位写1停止ADC转换,使得ADSTART位为0,从而确保ADC通道能成功切换。
改正代码如下:
void adc_init(void){
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOC Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); //打开GPIO时钟
/* ADC1 Peripheral clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE); //打开ADC1时钟
/*Initialize GPIO 对应ADC_Channel_10到ADC_Channel_13*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //悬空
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化IO
/* ADCs DeInit */
ADC_DeInit(ADC1);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continuous mode withe a resolution equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位精度
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换 每次转换需要start
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右对齐
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward; //Backward
ADC_Init(ADC1, &ADC_InitStructure);
// ADC_OverrunModeCmd(ADC1, ENABLE); //使能数据覆盖模式
ADC_ChannelConfig(ADC1, ADC_Channel_11 , ADC_SampleTime_239_5Cycles); //通道选择
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1); //ADC校准
/* Enable the ADC peripheral */
ADC_Cmd(ADC1, ENABLE); //打开ADC
/* Wait the ADRDY flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); //等待ADC准备完成
/* ADC1 regular Software Start Conv */
// ADC_StartOfConversion(ADC1); //单次转换需要每次启动
}
/**
* @brief Returns the last ADCx conversion result voltage data for ADC channel.
* @param ADC_Channel_x:ADC通道号
* @retval The Data conversion average value(v).
*/
float get_ADC_AvrVoltageValue(uint32_t ADC_Channel_x,uint8_t times) {
float ADC1ConvertedValue = 0.0;
//停止转换 对应ADC_StopOfConversion(ADC_TypeDef* ADCx)
ADC1->CR |= (uint32_t)ADC_CR_ADSTP;
ADC_ChannelConfig(ADC1, ADC_Channel_x , ADC_SampleTime_239_5Cycles);
//只选择ADC_Channel_x这个通道有效
ADC1->CHSELR =ADC_Channel_x;
//等待准备完成
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET);
//ADC_StartOfConversion(ADC1);
for(int i=0;i<times;i++){
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);
/* Wait EOC flag */
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
/* Get ADC1 converted data */
ADC1ConvertedValue += ADC_GetConversionValue(ADC1);
}
return (float)(ADC1ConvertedValue *3.3)/0xFFF/times;
}