天天看點

STM32實作DMA讀取ADC資料

昨天學習了DMA寫了一個用DMA讀取ADC資料的程式,記錄下整個過程和一點心得

DMA配置詳細說明

(MDK的漢字2複制過來就是亂碼,我重新打了一遍注釋,暈~)

//DMA1各通道配置
//外設->存儲器/16位資料寬度
//DMA_CHx:DMA通道CHx
//cpar:外設位址
//cmar:存儲器位址
//cndtr:資料傳輸量(因為我是一個16位的資料,是以是一)
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA時鐘
    
    DMA_DeInit(DMA_CHx);   //重設DMA為預設值

    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //外設位址
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //存儲器位址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //外設到存儲器的傳輸模式
    DMA_InitStructure.DMA_BufferSize = 1;  //資料量為1(應該為cndtr參數)
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;  //
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord  ;  //16位!!!特别注意
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord  ; //16位!!!特别注意
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //循環模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //優先級高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //(記憶體到記憶體禁止)

    DMA_Init(DMA_CHx,&DMA_InitStructure);  //初始化
    DMA_SetCurrDataCounter(DMA1_Channel1,1);//設定資料量(應該為cndtr參數,若有其它需要改變即 
                                            //可,我這裡是為了直覺)
} 
           

ADC相關配置

//ADC初始化													   
void  Adc_Init(void)
{ 	
		ADC_InitTypeDef ADC_InitStructure; 
		GPIO_InitTypeDef GPIO_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1	, ENABLE );	  //相關時鐘使能
	 

		RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //設定分頻因子,ADC時間最大不過14M

		//PA1寄存器初始化                        
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟輸入模式
		GPIO_Init(GPIOA, &GPIO_InitStructure);	

		ADC_DeInit(ADC1);   

		ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//獨立模式,不與其它ADC協作
		ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//單通道模式
		ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//!!!單次轉換
		ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//!!軟體觸發
		ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//資料右對齊
		ADC_InitStructure.ADC_NbrOfChannel = 1;	//
		ADC_Init(ADC1, &ADC_InitStructure);	// 

		ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );	 			    
        //配置采樣時間
		ADC_Cmd(ADC1, ENABLE);	//使能指定ADC
		ADC_DMACmd(ADC1, ENABLE);//使能ADC - DMA
		
		ADC_ResetCalibration(ADC1);	//複位校準  
		while(ADC_GetResetCalibrationStatus(ADC1));	//等待複位校準
		ADC_StartCalibration(ADC1);	 //開啟AD校準
	  while(ADC_GetCalibrationStatus(ADC1));	 //等待結束
		
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//軟體啟動
}				  
           

主程式

u16 SendBuff = 0;	//資料緩存區

u16 MYGet_Adc()
{
		u32 temp_val=0;
		u8 t;
		for(t=0;t<5;t++)
		{
				temp_val+=SendBuff;
				delay_ms(5);
		}
		return temp_val/5;
} 	 


int main(void)
{	 
		u16 adcx = 0;//用于顯示的資料
		float temp;
		delay_init();	    	   
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
		uart_init(115200);	 	//波特率
		LED_Init();			 
		LCD_Init();			 	
		Adc_Init();		 
	
		POINT_COLOR=BLUE;//字型顔色
		LCD_ShowString(60,0,300,24,24,"MODE: ADC-DMA");		
		LCD_ShowString(60,300,300,24,24,"ADC_CH0_VAL:");	      
		LCD_ShowString(60,350,300,24,24,"ADC_CH0_VOL:0.000V");	
		
		POINT_COLOR=RED;
	    MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR, (u32)&SendBuff,1);//配置說明見上

	    DMA_Cmd(DMA1_Channel1, ENABLE);	//開啟DMA通道
		while(1)
		{

			
			

		    	adcx = MYGet_Adc();//»ñÈ¡DMAÊý¾Ý

				LCD_ShowxNum(204,300,adcx,4,24,0);//直接讀取的值
				temp=(float)adcx*(3.3/4096);
				adcx=temp;
				LCD_ShowxNum(204,350,adcx,1,24,0);//轉化為電壓
				temp-=adcx;
				temp*=1000;
				LCD_ShowxNum(228,350,temp,3,24,0X80);
								
				LED1 = ~LED1;//提示程式正常運作
				delay_ms(250);
			

		}
}
           

可能出現的問題:

資料錯位:可能是DMA啟動在ADC之前,而你設定存儲器主動加一,那資料自然錯位

資料殘缺:配置DMA時設定錯誤,一定要仔細

                 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord  ;  //16位!!!特别注意

                 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord  ; //16位!!!特别注意

ADC讀了一次就不讀了:ADC配置循環ENABLE即可

後記:

參數的了解是第一位,不能隻看别人的代碼複制過來,要自己去明白了解才行。

繼續閱讀