學習應用筆記—STM32之ADC+DMA多通道模數轉換

在以往學習中,使用ADC採集都是規則單通道軟件啓動採集的那種方式,這種方式也僅限於學習。在真正的項目中會採集很多路ADC,顯示上面方式不合理,這時候就可以使用ADC+DMA進行多路採集,Nice!!!

STM32 ADC 簡介

在這裏插入圖片描述


ADC通道與GPIO管腳對應表

在這裏插入圖片描述


DMA簡介

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

更多理論內容可以查看中文參考數據手冊

知道以上東西可以擼代碼了。
使用固件庫配置還是挺"容易"的。看配置代碼就理解了。


DMA初始化

static void ADC_DMA_Init(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  DMA_DeInit(DMA1_Channel1);

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  //ADC外設數據寄存器地址作爲基地址
  DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)g_stTempInfo.ADC_ValTab; //存儲數據內存地址
  DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC; //傳輸方向爲外設到內存
  DMA_InitStructure.DMA_BufferSize         = 4;		  //單位是下面的HalfWord 16bit
  DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;  //用到多通道ADC,                     所以使能自動增加,一個通道轉換完的數據放在g_stTempInfo.ADC_ValTab[0],
                                                                   //下一個通道數據就自動存放在g_stTempInfo.ADC_ValTab[1]
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外設數據大小爲半字
  DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;   //內存數據大小也爲半字
  DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;  //循環模式
  DMA_InitStructure.DMA_Priority           = DMA_Priority_High;   //優先級高
  DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;    //不使用內存到內存的傳輸
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  /* Enable DMA1 Channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);		      //使能DMA通道1 
}  

模擬輸入引腳初始化

static void GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
	                       
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;         //模擬輸入引腳
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);	

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	 //模擬輸入引腳	
	GPIO_Init(GPIOB, &GPIO_InitStructure);	
}

PA5對應ADC1的通道5,PB0對應ADC1的通道8
ADC初始化

static void ADC_Init(void)
{
	ADC_InitTypeDef ADC_InitStructure; 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );	  //使能ADC1通道時鐘
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);          //72M/6=12,ADC最大時間不能超過14M
	
	ADC_DeInit(ADC1);  
	ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;				  //ADC工作模式:ADC1工作在獨立模式
	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數據右對齊
	ADC_InitStructure.ADC_NbrOfChannel       = 2;							         //順序進行規則轉換的ADC通道的數目
	ADC_Init(ADC1, &ADC_InitStructure);	  
 
	ADC_RegularChannelConfig(ADC1,ADC_Channel_5, 1, ADC_SampleTime_239Cycles5);        //ADC1通道5配置->PA5   第3個參數爲轉換順序,轉換後的值存在g_stTempInfo.ADC_ValTab[0]中
	ADC_RegularChannelConfig(ADC1,ADC_Channel_8, 2, ADC_SampleTime_239Cycles5);	       //ADC1通道8配置->PB0   第3個參數爲轉換順序,轉換後的值存在g_stTempInfo.ADC_ValTab[1]中
    ADC_DMACmd(ADC1, ENABLE);                  //使能ADC1的DMA功能
				 
	ADC_Cmd(ADC1, ENABLE);	                     //使能ADC1
	
	ADC_ResetCalibration(ADC1);	                 //重置指定的ADC1的校準寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));	//獲取ADC1重置校準寄存器的狀態,設置狀態則等待
	ADC_StartCalibration(ADC1);		            //開始指定ADC1的校準狀態
	while(ADC_GetCalibrationStatus(ADC1));		//獲取指定ADC1的校準程序,設置狀態則等待
 
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的軟件轉換啓動功能	
}

初始化GPIO、DMA、ADC

void  MyADC_Init(void)
{ 	
	GPIO_Init();  
   
	ADC_DMA_Init();     //ADC DMA初始化
 
	ADC_Init();        //ADC初始化
}	

獲取多個通道的ADC值

void GetAverageAdcVal(stADCTempInfo *TempInfo,u8 n)
{
	u8 x = 0;
	u32  ledVal = 0;
	u32   machineVal = 0;
		
	if(TempInfo == NULL)
	{
		printf("指針爲空\r\n");
		return;
 	}
 	
	for(x = 0; x < n; x++)
	{	
		while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));        //等待DMA傳輸完成
		ledVal     += TempInfo->ADC_ValTab[0];
		machineVal += TempInfo->ADC_ValTab[1];
		delay_ms(1);
	}	
	ledVal = ledVal / n;
	TempInfo->averageLedAdcVal  = ledVal;
	machineVal = machineVal / n;
	TempInfo->averageMachineAdcVal = machineVal;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章