STM32F0的多路ADC 无DMA

Posted Montauk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F0的多路ADC 无DMA相关的知识,希望对你有一定的参考价值。

前段时间几乎用了一下午的时间, 就为了调F0的两路ADC, 一开始想的办法是将采样的连续模式(ADC_ContinuousConvMode)使能, 然后连续拿两个值, 拿完分别返回.

坏处不用说, 看着就傻, 就算你只需要一个ADC通道的值, 也要拿足N个, 比如你一共要拿5个ADC引脚的电压, 那就要全拿, 然后取其中第若干个, 如果你要拿8个做平均, 就要把时间再乘8, 看着就蠢.

但是反复调试发现如果不连续采样, 第一次ok, 但是后面每次就只采后一个通道了, 很奇怪, 结果发现原来是居然没有一个方法去reset一个记录通道的寄存器, 看完规格书只能手动重置了.

ADC初始化:

void ADC1_DMA_Init(void)
{
    GPIO_InitTypeDef    GPIO_InitStructure;
    ADC_InitTypeDef     ADC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

    GPIO_Init(GPIOA, &GPIO_InitStructure);	
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_InitStructure);			
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);		
	
    ADC_DeInit(ADC1);	      
	
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  
    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); 
    
    ADC_ChannelConfig(ADC1, ADC_Channel_7 , ADC_SampleTime_239_5Cycles); /* Convert the ADC1 Channel 1 with 239.5 Cycles as sampling time */  
    ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); /* Convert the ADC1 Channel 1 with 239.5 Cycles as sampling time */     

    ADC_GetCalibrationFactor(ADC1);	 
    ADC_Cmd(ADC1, ENABLE);


}

 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

关掉连续模式.

接着是重点:

uint32_t getBatteryVol(void){
    __IO uint32_t i;
    __IO uint32_t result;
    __IO uint16_t tempADCResult=0,tempADCResultRef=0, tempADCBetween=0;
    __IO uint32_t average=0;   

    ADC1->CHSELR = 0;
    ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); /* Convert the ADC1 Channel 1 with 239.5 Cycles as sampling time */  
    ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
    
    ADC_StartOfConversion(ADC1);	

    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);  
       
    tempADCResultRef = ADC_GetConversionValue(ADC1);
    average = tempADCResultRef;
    
    for(i=1; i<8; i++){
        ADC_StartOfConversion(ADC1); 
    	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET){}
        
        tempADCResult = ADC_GetConversionValue(ADC1);  
        
        if( tempADCResult >= tempADCResultRef){
            tempADCBetween= tempADCResult - tempADCResultRef;
        }else{
            tempADCBetween = tempADCResultRef - tempADCResult; 
        }
        
        if(tempADCBetween <= ADC_Smoth){ 
            average += tempADCResult;
            tempADCResultRef = tempADCResult;  
        }else{
            average += tempADCResultRef;
        }

    }
    
    result = ((average >> 3 )* 2500 >> 12) * 2;

    return result;
}

ADC1->CHSELR = 0; 

先把这个记录通道的寄存器(ADC1->CHSELR)reset掉, 然后制定再指定通道, 然后取8次相加再除8, 还做了一个平滑处理, 其实没必要.最后按照2.5伏参考电压再结合50%的分压返回一个实际的mv为单位的值.

然后另一个取ADC的函数跟这个完全一样, 除了一行:

    ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); /* Convert the ADC1 Channel 1 with 239.5 Cycles as sampling time */  

换成:

    ADC_ChannelConfig(ADC1, ADC_Channel_7 , ADC_SampleTime_239_5Cycles); /* Convert the ADC1 Channel 7 with 239.5 Cycles as sampling time */  

其他一毛一样, 就能取A7引脚, ADC1_7通道的值了, 最后分压啥的,就不多说了.

以上是关于STM32F0的多路ADC 无DMA的主要内容,如果未能解决你的问题,请参考以下文章

STM32F0 DMA“输入溢出”

STM32 DMA问题

STM32F7:ADC DMA 传输只工作一次

带有 DMA 7 通道常规组的 STM32F4 ADC 不工作

STM32F4 ADC模块使用不同DMA模式的区别和对比

STM32F0库函数初始化系列:ADC