stm32之DMA彻底研究(2)

1510阅读 0评论2014-02-24 枫海8深蓝
分类:C/C++

AD转换之DMA

1、DMA的配置

//DMA的配置
void DMA_Configuration(void)
{
 
 /* 允许 DMA1 */
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
 /* DMA通道1*/
 DMA_DeInit(DMA1_Channel1);
 DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)( &(ADC1->DR));  //ADC1数据寄存器
 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCCov;     //获取ADC的数组
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;     //片内外设作源头
 DMA_InitStructure.DMA_BufferSize = 16;        //每次DMA16个数据
 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_Normal;        //普通模式
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;       //高优先级
 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;        //非内存到内存
 DMA_Init(DMA1_Channel1, &DMA_InitStructure);
 
 DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);        //DMA通道1传输完成中断
 
 /* Enable DMA1 channel1 */
 DMA_Cmd(DMA1_Channel1, ENABLE);
}

要配置的内容有:

(1)DMA1的AHB时钟使能

(2)DMA的源端和目的端的配置以及传输方向的配置

(3)每次DMA的数据长度、地址是否增加、模式、优先级等等

(4)使能DMA中断

(5)使能DMA1的通道1(通道选择)

本例程中DMA中断的操作如下:

/*******************************************************************************
* Function Name  : DMAChannel1_IRQHandler
* Description    : This function handles DMA Stream 1 interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
extern volatile bool ADC_Ok;
void DMA1_Channel1_IRQHandler(void)
{
 if(DMA_GetITStatus(DMA1_IT_TC1))
  {
  DMA_ClearITPendingBit(DMA1_IT_GL1); //清除全部中断标志
  ADC_Ok=TRUE;
 }
}

在DMA1的1通道的中断程序中,清楚中断标志,并且将AD标志位置位。

重新允许DMA

void DMAReConfig(void)
{
 DMA_DeInit(DMA1_Channel1);
 DMA_Init(DMA1_Channel1, &DMA_InitStructure);
 DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
 DMA_Cmd(DMA1_Channel1, ENABLE);
}

下面是主程序中,对AD和DMA的使用操作:

int main(void)
{
 u16 adc;
 u8 a,b,c,d;
 
 ChipHalInit();   //片内硬件初始化
 ChipOutHalInit();  //片外硬件初始化
 
 
 for(;;)
 {
  if(ADC_Ok==TRUE)
  {
   ADC_Ok=FALSE;
   adc=DigitFilter(ADCCov,16); //滤波
   
   DMAReConfig();//重新启动DMA
   
   adc=(1.42 - adc*3.3/4096)*1000/4.35 25;

   //转换为温度值,实际应用中,可考虑用毫伏为单位,避免浮点运算

   a = adc/1000;
      b = (adc - a*1000)/100;
      c = (adc - a*1000 - b*100)/10;
      d = adc - a*1000 - b*100 - c*10;

      USART1_Puts("当前温度是:");
      USART1_Putc(a '0');
      USART1_Putc(b '0');
      USART1_Putc(c '0');
      USART1_Putc(d '0');
      USART1_Puts("C \r\n");
  }
 }
}

这段程序所完成的操作有:

(1)当一次DMA传输完成后,主程序根据标志量,计算转换出来的ad值。

(2)重新启动DMA

(3)将ad值计算成温度,然后将温度值通过串口发送出去。

(4)等待下一个DMA传输完成的到来,进行下一个周期的转换和计算。

还有一点比较重要的就是NVIC的配置,任何stm32的中断程序都需要配置NVIC,有的时候有一忽视掉。

//设置所有的中断允许

void NVIC_Configuration(void)
{
 NVIC_InitTypeDef NVIC_InitStructure;
 
 /* Configure one bit for preemption priority */
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  /* Enable DMA channel1 IRQ Channel */
 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);

}

另外,在配置DMA中断的时候,也可以配置成传输一半产生中断的方式。

我们可以做如下实验:

将DMA中断设置成传输一半产生中断,如下:

DMA_ITConfig(DMA1_Channel4, DMA_IT_HT, ENABLE);  

当数据传送到一半的时候发现进入到中断:

void DMA1_Channel4_IRQHandler(void)
{
  if(DMA_GetITStatus(DMA1_IT_HT4))
  {
    DMA_ClearITPendingBit(DMA1_IT_HT4); 

  }
}

在此中断中设置断点,当产生中断后,发现DMA传送并没有结束。

只是cpu“停止”了。

DMA仍然将剩下的一半数据传送完。

上一篇:stm32——ucos的中断使用
下一篇:STM32之如何封装自己的lib库