STM32之ADC多路采样开发踩过的坑

最近开发基于PH、ORP数据采集项目,两路PH,两路ORP所以用到了STM32ADC多路采样,

不足之处望指正。

一、存在问题

1、采样数据不准确,几路数据相同。

2、通道间数据互相影响,不准确等。

二、开发过程

非DMA模式

最开始只是在单通道非DMA模式下增加多路通道,结果AD采样数据显示都一样,经过各种修改未发现问题。

 DMA模式

在思绪百般无果下,想了下会不会是多路采样导致CPU负担过重,于是想起了DMA(个人理解DMA就是一个中转站,起到存数据,取数据的过程,这个存取过程不需要CPU直接参与,采样数据过大、过多时利用DMA收集数据,再处理,减轻了CPU负担),资源查询过程中又发现了一个问题,在非DMA模式下,多路ADC采集的数据储存位置是相同的,出现了数据覆盖,所以才会有互相影响,数据相同的奇怪现象。然而,开启ADC多通道DMA模式后采集数据还是存在互相干扰,最后查询资料得到的结论是,未连接的端口处于浮空状态,会受干扰,最后将每个采样口接通,恢复正常。

三、下面分享一下源码以及细节部分吧

1、ADC采样GPIO端口配置,这里配置六个PA端口

 void ADC1_GPIO_Config(void)
{ 
  GPIO_InitTypeDef GPIO_InitStructure;    
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		   
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);
		
}

2、ADC和DMA一起配置

void ADC1_Mode_Config(void)
{

  ADC_InitTypeDef ADC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  DMA_DeInit(DMA1_Channel1);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 6;	
  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);	
	
  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 =6;  			
  ADC_Init(ADC1, &ADC_InitStructure);
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);   
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 ); 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 ); 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5);
  ADC_DMACmd(ADC1, ENABLE);	
  ADC_Cmd(ADC1, ENABLE);
  ADC_ResetCalibration(ADC1);  

  while(ADC_GetResetCalibrationStatus(ADC1));

  ADC_StartCalibration(ADC1);

  while(ADC_GetCalibrationStatus(ADC1));  

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);  
}

3、注意细节

DMA_InitStructure.DMA_BufferSize = 6;这是配置DMA数据储存大小,由于STM32内置ADC采样为12位,所以一个IO口采集的数据咱们用16来储存,所以六个IO口填6。

ADC_DMACmd(ADC1, ENABLE);    这句是ADC请求DMA关键使能句,也就是ADC与DMA的桥梁。

其他区别对比单路ADC采样修改即可, DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT,这里ADCDAT定义为u16ADCDAT[5]数组,刚好储存六个IO口ADC值,为了储存数据强制转化为32位,在主函数中直接读取读取数组即为对应ADC值。

    

猜你喜欢

转载自blog.csdn.net/qq_41050642/article/details/105052191