STM32的ADC的DMA方式

之前了解了ADC的单独使用,由于AD的采样和处理对CPU的消耗较大,单独使用AD会对CPU 的很有要求

void  Adc_Init(void)
{
  ADC_InitTypeDef ADC_InitStructure; 
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1,ENABLE );//使能端口1的时钟和ADC1的时钟,因为ADC1的通道1在PA1上

  RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12M,ADC最大时间不能超过14M,也就是ADC的时钟频率为12MHz
  
  //PAx 作为模拟通道输入引脚                         
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  //PCx 作为模拟通道输入引脚                         
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//本次实验使用的是ADC1,并ADC1工作在独立模式ADC_CR1的位19:16,即这几位为0000
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//ADC_ScanConvMode 用来设置是否开启扫描模式,本实验开启扫面模式.ADC_CR1的位8
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC_ContinuousConvMode 用来设置是否开启连续转换模式 模数转换工作在连续转换模式,ADC_CR2的位1
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动 ADC_CR2的位19:17
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐ADC_CR2的位11
  ADC_InitStructure.ADC_NbrOfChannel = N;	//顺序进行规则转换的ADC通道的数目ADC_SQR1位23:20
  ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道0;第1转换;采样时间为239.5周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 2, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道1;第2转换;采样时间为239.5周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道3;第3转换;采样时间为239.5周期

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 4, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道0;第1转换;采样时间为239.5周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 5, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道1;第2转换;采样时间为239.5周期
	
  ADC_DMACmd(ADC1, ENABLE); //使能ADC1的DMA传输,ADC_CR2位8
    
  ADC_Cmd(ADC1, ENABLE);	//使能的ADC1,ADC_CR2位0
	
  ADC_ResetCalibration(ADC1);	//使能复位校准,ADC_CR2位3  
  while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
  ADC_StartCalibration(ADC1);	 //开启AD校准,ADC_CR2位2
  while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束

   ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动AD转换
   
}

,下面上传一点AD的DMA方式的应用,有不对之处欢迎指正:

 Adc_Init();//AD初始化函数
    MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)&AD_DATA,N);//DMA1通道1;外设为ADC1;存储器为AD_DATA;通道数为N个.

u8 DMA1_MEM_LEN;
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从外设模式->存储器/16位数据宽度/存储器增量模式
                  //DMA_CHx:DMA通道CHx		   //cpar:外设地址 //cmar:存储器地址//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{	  
    DMA_InitTypeDef DMA_InitStructure;

 	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA时钟
	
    DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值

	DMA1_MEM_LEN=cndtr;//通道数据长度
	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设基地址
	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设发送到内存  DMA_CCRX位4
	DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
	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通道 x拥有高优先级 
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
	DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
	 
	 DMA_Cmd(DMA1_Channel1, ENABLE);//启动DMA通道 	
} 

下面是在中断中调用的时候,如何使用:


void TIM2_IRQHandler(void)
{
	int i;
//	if(START_FLAG == 0)
//	{
//		START_TIME++;
//		if(START_TIME > 2000) 
//		{
//			g_fangle0 -= 30;
//			START_TIME = 0;
//			START_FLAG = 1;
//		}
//	}
//	if((Magnetic_L1+Magnetic_R2) < 20) g_fangle0 = 1918;
	g_nspeedcontroltime++;
	SpeedControlout();
	g_nDirectionControlPeriod++;
	DirectionControlOutput();
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
	if(g_nspeedcishu == 0) 
    {
		/* Enable the TIM Counter */
		TIM4->CNT = 0;
    	TIM4->CR1 |= TIM_CR1_CEN;
		TIM5->CNT = 0;
    	TIM5->CR1 |= TIM_CR1_CEN;
    }
    g_nspeedcishu++;
	if(g_nspeedcishu >= 100) 
    {  
		g_fspeedrightce = TIM4->CNT;
		if(g_fspeedrightce > 32767)  g_fspeedrightce =  65535 - g_fspeedrightce;	 //正转为0xffff-CNT,反转为CNT-0
		g_fspeedleftce = TIM5->CNT;
		if(g_fspeedleftce > 32767)  g_fspeedleftce =  65535 - g_fspeedleftce;	 //正转为0xffff-CNT,反转为CNT-0  
        g_nspeedcishu = 0;
		/* Disable the TIM Counter */
		TIM4->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));		
		TIM5->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
    }

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    if(TimeCount == 1) 	//AD转换,采集陀螺仪+加速度+方向
    {
		for(i = 0; i < 20; i++)
		{
			ATDTUO[i]   =  AD_DATA[0];
			ATDDIR[i]   =  AD_DATA[1];
			ATDJIA[i]   =  AD_DATA[2];
			ATDLEFT[i]  =  AD_DATA[3];
			ATDRIGHT[i] =  AD_DATA[4];		
		}
		AVE();
		Kalman_Filter(g_fanglespeed, g_fangle,     0.1, 0.003, 0.05, 0.0122, &Angle_Z,     &Gyro_T2_t);
		Kalman_Filter(g_fangle,      g_fanglespeed,0.1, 0.003, 0.05, 0.0122, &Gyro_T2,     &Angle_Z_t);
		Kalman_Filter(g_fangle,      g_fdirection, 0.1, 0.003, 0.05, 0.0122, &Gyro_T1,     &Angle_Z2);
		Kalman_Filter(g_fmagneticl,  g_fmagneticl, 0.1, 0.003, 0.05, 0.0122, &Magnetic_L1, &Magnetic_R1);
		Kalman_Filter(g_fmagneticl,  g_fmagneticr, 0.1, 0.003, 0.05, 0.0122, &Magnetic_R2, &Magnetic_L2);
		OutData[0] = Angle_Z;    
    	OutData[1] = Gyro_T2;
		OutData[2] = AD_DATA[2];
		OutData[3] = AD_DATA[0];
//		printf("Jiasudu=%d\n",AD_DATA[2]);
//		printf("Tuoluoyi=%d\n",AD_DATA[0]);
//		printf("Fangxiang=%d\n",AD_DATA[1]);
//		printf("Zuodianci=%d\n",AD_DATA[3]);
//		printf("Youdianci=%d\n",AD_DATA[4]);
    }

    else if(TimeCount == 2)  //角度控制	
    {  
		AngleControl();		     
    }  

    else if(TimeCount == 3)  //方向控制
    {    
        DirectionControl();       
    }
																  
	else if(TimeCount == 4)	 //速度控制
	{
	  	SpeedControl();
	    Motoroutput();
    	Motorspeedout();
    	Setmotorvoltage(g_fleftval,g_frightval);
		TIM3_Mode_Config(PWMDTY01,PWMDTY23,PWMDTY45,PWMDTY67);
	}     
    if(TimeCount >= 5) 
    {
        TimeCount = 0;
    }
	TimeCount++; 
	TIM2->SR = 0;//清中断标志位	 
}


再下面是我对ADC的DMA的处理方式的一些理解,不足之处望指正:STM32的ADC的DMA方式_第1张图片

你可能感兴趣的:(STM32)