天天看點

STM32ADC多通道采集(基于DMA)

首先簡單介紹DMA,DMA(Direct Memory Access,直接記憶體存取) ,用來提供在外設和存儲器之間或者存儲器和存儲器之間的高速資料傳輸。無需CPU幹預,節省CPU資源;ADC轉換出來的值直接指派給定義好的變量中。配置好的DMA可以不停地将ADC轉換值寫到該變量中,在主函數直接判斷該變量就知道此時的AD值,也就是說在主函數中不需要調用ADC_GetConversionValue()函數來擷取轉換值。

DMA跟其他外設一樣需要進行配置通道,使能時鐘等參數

下面直接看代碼:

volatile vu16 ADCConvertedValue[10][3] ;//開辟的一段記憶體,用來存放ADC轉換結果,也是DMA的目标位址,3通道,每通道采集10次後面取平均數

void Adc_Init (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef  ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1  , ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//要注意,ADC的時鐘最大為14M,是以這裡6分頻,72/6=12<14
	
	/************ADC_Init****************/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//ADC位址,該參數用以定義DMA外設基位址
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCConvertedValue; //該參數用以定義DMA記憶體基位址(轉換結果儲存的位址)
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向(從外設到記憶體)
	DMA_InitStructure.DMA_BufferSize = sizeof(ADCConvertedValue)/sizeof(vu16); //定義指定DMA通道的DMA緩存的大小,機關為資料機關。這裡也就是Adc_Data的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //設定外設位址寄存器遞增與否,此處設為不變 Disable
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //用來設定記憶體位址寄存器遞增與否,此處設為遞增,Enable
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //外設資料機關
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;    //記憶體資料機關
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; //DMA模式:循環傳輸
	DMA_InitStructure.DMA_Priority = DMA_Priority_High ; //優先級:高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   //禁止記憶體到記憶體的傳輸
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //配置DMA1的1通道
	DMA_Cmd(DMA1_Channel1,ENABLE);
		
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 3;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_13Cycles5);//通道一轉換結果儲存到ADCConvertedValue[0~10][0]
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_13Cycles5);//通道二轉換結果儲存到ADCConvertedValue[0~10][1]
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_13Cycles5);通道三轉換結果儲存到ADCConvertedValue[0~10][2]
	//ADC_ITConfig(ADC1, ADC_IT_AWD, ENABLE);
	
	ADC_DMACmd(ADC1,ENABLE);
	ADC_Cmd(ADC1, ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	
}

           

做完這兩步,ADCConvertedValue數組的值就會随輸入的模拟電壓改變而改變,在主函數中最好取多幾次的平均值,再通過公式換算成電壓機關。下面是采集函數:

void Adc_Read(void)
{
	int sum;
	u8 i,j;	
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//開始采集
	for(i=0;i<3;i++)
	{
		sum=0;
		for(j=0;j<10;j++)
		{
			sum+=ADCConvertedValue[j][i];
		}
		ADC_Value[i]=(float)sum/(10*4096)*3.3;//求平均值并轉換成電壓值
		//ADC_Value[i]=(float)sum/10;
		printf("ADC_Value[%d] = %.3f\n",i,ADC_Value[i]);
	}
	Delay_ms(300);
}
           

采集結構如下:

STM32ADC多通道采集(基于DMA)

繼續閱讀