1. 程式人生 > >STM32F4四路ADC取樣問題探討

STM32F4四路ADC取樣問題探討

1.ADC配置

1.1模式確定

主從模式,選擇主ADC1模式帶動從ADC2模式
ADC模式
交替模式
對應程式碼段:

/* Enable DMA request after last transfer (Multi-ADC mode)  */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

1.2 時鐘初始化ADC

ADC時鐘掛在APB2上,這裡程式配置為168MHz

RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);

RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC2,ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC2,DISABLE);

1.3 引腳選擇和初始化

1.3.1 引腳

這裡的ADC是加DMA的,需要根據DMA和ADC相關預設引腳來選擇
簡化來說 PC0–ADC通道10,PC1–ADC通道11…
選定相應引腳

1.3.2 初始化配置

ADC_Init(ADC2, &ADC_InitStructure);
/* ADC2 regular channel5 configuration ****************/
ADC_RegularChannelConfig(ADC2,ADC_Channel_13,1,
ADC_SampleTime_15Cycles);		//PC3
/* ADC1 regular channel5 configuration ************/
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles);		//PA3

ADC_Init(ADC1, &ADC_InitStructure); 

/* ADC1 regular channel5 configuration ****************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_15Cycles);		//PC2
/* ADC1 regular channel5 configuration ******************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_15Cycles);		//PA5
...
ADC_Cmd(ADC1, ENABLE)
ADC_Cmd(ADC2, ENABLE);

2.DMA配置

2.1初始化

確定資料流,這裡F4系列的開發板有3個ADC
DMA2

2.2程式配置

/* DMA2 Stream0 channel2 configuration */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aADCConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_BUF_SIZE;
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_FIFOMode = DMA_FIFOMode_Enable;         
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);

3.濾波平均

3.1一般濾波方法

這裡嘗試過其他一些濾波方法,加權濾波,中值濾波,滑動濾波方法,在大資料量下,排序消耗時間和佔用資源都比較不好,經測試,一般濾波方法比較好。

u32 adc_filter(u32 cnt,u32 adc_num_value){
	u8 i;
	u32 adc_min=0,adc_max=0;
	u32 adc_sum=0,adc_ave=0;
	for(i=0;i<cnt;i++){
		adc_sum += adc_num_value;
		adc_min=adc_num_value;
		adc_max=adc_num_value;
		
		if(adc_num_value<=adc_min)
			adc_min=adc_num_value;
		if(adc_num_value>=adc_max)
			adc_max=adc_num_value;
	}
	adc_sum -= (adc_max+adc_min);	
	adc_ave=adc_sum/(cnt-2);
	adc_sum=0;
	return adc_ave;
}

3.2 取樣計算求值

根據之前規定的組合依次可計算出各取樣值,這裡優化了浮點計算方法

u8 j,k;
u32 adc_getvalue[4];
memset(&adc_getvalue,0,sizeof(adc_getvalue));
for(j=0;j<40;j++)
{
	for(k=0;k<4;k++)
	adc_getvalue[k] += adc_filter(8,aADCConvertedValue[k]);
}//PC3--[1] PC1--[3] PC2--[0] PA5--[2]
voltage1_calculate=	(float)adc_getvalue[0]*33/(400*4096);
voltage2_calculate=	(float)adc_getvalue[1]*33/(400*4096);
current1_calculate=	(float)adc_getvalue[2]*33/(400*4096);
current2_calculate=	(float)adc_getvalue[3]*33/(400*4096);
	
memset(&adc_getvalue,0,sizeof(adc_getvalue));
	
//減少線差
adc_voltage1=voltage1_calculate;
adc_voltage2=voltage2_calculate;
adc_current1=current1_calculate;
adc_current2=current2_calculate;			

這裡相關配置就可以結束了,需注意的是,計算取樣時需要定義陣列,陣列型別也有明確要求。這裡附上程式配置相關檔案