学习应用笔记—STM32之ADC+DMA多通道模数转换

在以往学习中,使用ADC采集都是规则单通道软件启动采集的那种方式,这种方式也仅限于学习。在真正的项目中会采集很多路ADC,显示上面方式不合理,这时候就可以使用ADC+DMA进行多路采集,Nice!!!

STM32 ADC 简介

学习应用笔记—STM32之ADC+DMA多通道模数转换_第1张图片


ADC通道与GPIO管脚对应表

学习应用笔记—STM32之ADC+DMA多通道模数转换_第2张图片


DMA简介

在这里插入图片描述

学习应用笔记—STM32之ADC+DMA多通道模数转换_第3张图片
学习应用笔记—STM32之ADC+DMA多通道模数转换_第4张图片

更多理论内容可以查看中文参考数据手册

知道以上东西可以撸代码了。
使用固件库配置还是挺"容易"的。看配置代码就理解了。


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;
}

你可能感兴趣的:(STM32)