STM32 ADC单/多通道采样及DMA传输详解

一、ADC介绍

ADC简介在这里插入图片描述
通过介绍我们可以了解到,ADC是12位的转换器,所以采样值范围是0~4095。18个通道可同时进行转换,也可以单独转换某个通道。

二、单通道单次ADC采样

使用ADC的流程应为:

  1. 初始化IO口。
    我这里使用的是PA1进行采样,也就是ADC1的通道1
void ADC_GPIO_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);//打开IO时钟
	
	//配置ADC对应的IO为模拟输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;
	GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化结构体
}
  1. 初始化ADC。
void ADC1_Init(void)
{	
	

	ADC_InitTypeDef ADC_InitStructure; 
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	ADC_DeInit(ADC1);
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;//单次转换
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发转换
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐

	ADC_InitStructure.ADC_NbrOfChannel=1;//顺序转化的ADC通道数量


	ADC_Init(ADC1,&ADC_InitStructure);
	
	//耗时 1/14KHz*239 ≈ 17.07us
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);

	
	ADC_Cmd(ADC1,ENABLE);

	/*ADC校准*/
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
}
  1. 转换、获取采样值。
uint16_t ReadADC(void)
{
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//启用ADC软件转换
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//等待转换结束
  return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1的转换结果
}

三、多通道采样+DMA搬运

多通道的时候我们一般用DMA来搬运数据,与单通道不同的是,ADC配置时有些变化,DMA需要进行配置。

void ADC1_Init(void)
{	
	

	ADC_InitTypeDef ADC_InitStructure; 
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	/*使能DMA通道1*/
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &DMA_Getvalue;//DMA_Getvalue[10]; 搬运数据的存放地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = 10; // 每次传输10个通道的值,就停止
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//存储地址固定
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//递增模式,可将上面的数组填充完整,否则永远是第一个
	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);
	
	DMA_Cmd(DMA1_Channel1,ENABLE);	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	/*ADC1工作模式为扫描模式、单次转换、14个通道、数据右对齐,*/
	ADC_DeInit(ADC1);
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;

	ADC_InitStructure.ADC_NbrOfChannel=SixChannelMax;


	ADC_Init(ADC1,&ADC_InitStructure);
	
	//排列好各通道的顺序,此顺序对应DMA数组内数据的顺序
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_4,4,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_5,5,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_6,6,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_7,7,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_8,8,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_9,9,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_10,10,ADC_SampleTime_239Cycles5);

	
	ADC_DMACmd(ADC1,ENABLE);
	
	ADC_Cmd(ADC1,ENABLE);

	/*ADC校准*/
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	
	/*启用ADC软件转换*/
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

然后获取转化值函数也发生相应的改变,此函数可以放在一个定时中断或定时任务中,固定多少间隔去读取

void Read_ADCValue(void)
{
	uint32_t Value[10];
	ADC_Cmd(ADC1,DISABLE);//先失能ADC
	int i = 0;

	//将读取到的值保存
	for(i =0; i < 10; i++)
	{
		Value[i] += DMA_Getvalue[i];//将搬运的数据取出
	}
	memset(DMA_Getvalue,0,sizeof(DMA_Getvalue));		//每次读取数据后清空DMA存储空间
	
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开始转换
}

读取函数也可以使用DMA中断,进行配置然后在中断内取出数据即可。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 ADC单/多通道采样及DMA传输详解

发表回复