STM32_DMA_笔记

参考博文:http://blog.csdn.net/jdh99/article/details/8444474

STM32F103有两个DMA控制器DMA1(7通道)和DMA2(5通道),DMA2只存在大容量产品中。


案例1:DMA传输到串口发送

//配置DMA寄存器 
#define UART_RX_LEN     5   
u8 Uart_Send_Buffer[UART_RX_LEN] = {0x12,0x34,0x56,0x78,0x90};   //需发送到串口的数据
u8 i=0;  
u8 Flag_Uart_Send=0; //判断DMA传输是否结束 
   
void Dma_Init(void)  
{  
  DMA_InitTypeDef  DMA_InitStructure;  
        
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  
  /* DMA channel6configuration */  
  DMA_DeInit(DMA1_Channel1);  
  DMA_InitStructure.DMA_PeripheralBaseAddr   = (u32)(&USART1->DR);     //外设地址  
  DMA_InitStructure.DMA_MemoryBaseAddr       =(u32)Uart_Send_Buffer;  
  DMA_InitStructure.DMA_DIR                  =DMA_DIR_PeripheralDST;   //外设作为目的地址   //DMA_DIR_PeripheralSRC 外设作为DMA的源端  
  DMA_InitStructure.DMA_BufferSize           =5; //BufferSize;         //传输大小  
  DMA_InitStructure.DMA_PeripheralInc        =DMA_PeripheralInc_Disable; //外设递增模式禁止   //DMA_PeripheralInc_Enable 外设地址增加  
  DMA_InitStructure.DMA_MemoryInc            =DMA_MemoryInc_Enable;      //内存地址自增  
  DMA_InitStructure.DMA_PeripheralDataSize   = DMA_PeripheralDataSize_Byte; //传输方式:字节   DMA_PeripheralDataSize_Word;    
  DMA_InitStructure.DMA_MemoryDataSize       =DMA_PeripheralDataSize_Byte;  //内存存储方式:字节  DMA_MemoryDataSize_Word;  
  DMA_InitStructure.DMA_Mode                 =DMA_Mode_Circular;  //<span style="font-family: Arial, Helvetica, sans-serif;">循环模式,不停的传送    </span>DMA_Mode_Normal 正常模式,只传送一次;  
  DMA_InitStructure.DMA_Priority             =DMA_Priority_High;  //高优先级
  DMA_InitStructure.DMA_M2M                  =DMA_M2M_Disable;             //DMA_M2M_Enable;      
  DMA_Init(DMA1_Channel4,&DMA_InitStructure);  
   
  /* Enable DMA Channel4Transfer Complete interrupt */  
  DMA_ITConfig(DMA1_Channel4,DMA_IT_TC, ENABLE);  
  
// USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);    //串口接收器DMA   
  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);   <span style="font-family: Arial, Helvetica, sans-serif;">//采用DMA方式发送 </span>
    
  USART_Cmd(USART1,ENABLE);   <span style="font-family: Arial, Helvetica, sans-serif;">//启动串口 </span>
  
  DMA_ITConfig(DMA1_Channel4,DMA_IT_TC, ENABLE);  //传输完成则进入DMA1_Channel4中断;  

void USART1_Init(uint32 baud)  //配置UART1
{  
   GPIO_InitTypeDef       GPIO_InitStructure;  
   USART_InitTypeDef      USART_InitStructure;  
   USART_ClockInitTypeDefUSART_ClockInitStructure;  
        
   
        
   //使能串口1,PA,AFIO总线  
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |  
                          RCC_APB2Periph_AFIO |  
                          RCC_APB2Periph_USART1 ,  
                          (FunctionalState)ENABLE);  
        
   // A9 USART1_Tx  
   GPIO_InitStructure.GPIO_Pin   =GPIO_Pin_9;  
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
   GPIO_InitStructure.GPIO_Mode  =GPIO_Mode_AF_PP;  
    GPIO_Init(GPIOA,&GPIO_InitStructure);  
   
   // A10 USART1_Rx  
   GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;  
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
   GPIO_Init(GPIOA,&GPIO_InitStructure);  
        
   USART_InitStructure.USART_BaudRate            = baud;  
   USART_InitStructure.USART_WordLength          = USART_WordLength_8b;  
   USART_InitStructure.USART_StopBits            = USART_StopBits_1;  
   USART_InitStructure.USART_Parity              = USART_Parity_No;  
   USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;  
   USART_InitStructure.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;  
        
   USART_ClockInitStructure.USART_Clock   = USART_Clock_Disable;  
   USART_ClockInitStructure.USART_CPOL    = USART_CPOL_Low;  
   USART_ClockInitStructure.USART_CPHA    = USART_CPHA_2Edge;  
   USART_ClockInitStructure.USART_LastBit= USART_LastBit_Disable;  
   USART_ClockInit(USART1,&USART_ClockInitStructure);  
        
   USART_Init(USART1,&USART_InitStructure);  
   USART_Cmd(USART1,(FunctionalState)ENABLE);  
//  USART_ClearFlag(USART3, USART_FLAG_TC);    
    
   USART_ITConfig(USART1,USART_IT_RXNE,(FunctionalState)ENABLE);  <span style="font-family: Arial, Helvetica, sans-serif;">//串口1使用接收中断 </span>
}  

   
//******************************************************************/   
void NVIC_Config(void)  
{  
         NVIC_InitTypeDefNVIC_InitStructure;    
          
         //DMA中断优先级          
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);  
         NVIC_InitStructure.NVIC_IRQChannel= DMA1_Channel4_IRQn;   
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;   
         NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;   
         NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;   
         NVIC_Init(&NVIC_InitStructure);   
          
          
         /*Configure one bit for preemption priority --------------------- */  
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  
          
         /*UART1接收中断优先级 --------------------------------------- */  
         NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn;  
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;  
         NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;  
         NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;  
         NVIC_Init(&NVIC_InitStructure);     
          
}  


在stm3210x_it.c 文件中添加 DMA中断处理函数

/*******************************************************************************  
* Function Name  : DMAChannel1_IRQHandler  
* Description    : This function handles DMA Stream 1interrupt request.  
* Input          : None  
* Output         : None  
* Return         : None  
*******************************************************************************/  
//串口1  DMA方式发送中断  
void DMA1_Channel4_IRQHandler(void)  
{           
   //清除标志位  
   DMA_ClearFlag(DMA1_FLAG_TC4);   
   //关闭DMA   
   DMA_Cmd(DMA1_Channel4,DISABLE);   
   Flag_Uart_Send = 0;                     
}  

如果DMA是正常模式DMA_Mode_Normal时,传输结束后将不再产生DMA操作;所以需要在传输完成的中断中暂时把DMA关闭—即:DMA_Cmd(DMA1_Channel4,DISABLE); 

之后在main函数的while(1)循环中打开DMA_Cmd(DMA1_Channel4,ENABLE);进行下一次的传输;




案例2:利用DMA_UART + Timer 接收数据

原理:

1、打开UART1_RX的外部中断,当接收第一个数据的起始位时产生外部中断,在外部中断服务子程序中关闭外部中断,同时打开定时器计数。

2、当DMA接收到最长数据流,DMA中断处理程序中,清除中断标志,设置接收结束标志位和长度。

3、定时器服务程序,计数自加,当达到计数值,说明接收数据没有达到最大长度,停止定时器,设置接收结束标志位和长度

4、主循环中判断接收标志位,处理接收数据,打开RX中断功能。


初始化代码:

//初始化UART1
void USART1_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);  // Enable USB_LED_PORT(GPIO->F clock */

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);		// Set USART1 Tx (PA.09) as alternate function push-pull

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);		// Set USART1 Rx (PA.10) as input floating

	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);		// Configure the USART1

	USART_DMACmd(USART1, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);

	USART_Cmd(USART1, ENABLE);  // Enable the USART1
}

//初始化DMA
void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStructure;

	DMA_Cmd(DMA1_Channel5, DISABLE);				// disable DMA1 Channel5 recieve

	DMA_DeInit(DMA1_Channel5);
	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RX_Buffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //方向 外设 到 内存
	DMA_InitStructure.DMA_BufferSize = Rx_Buffer_Size;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);	// DMA1 Channel5 (triggered by USART1 Rx event) Config

	DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);  //使能DMA接收完成中断

	DMA_Cmd(DMA1_Channel5, ENABLE);		// Enable DMA1 Channel5 recieve
}

//初始化外部中断 PA10(RX)
void EXTI_Configuration(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;

	EXTI_InitStructure.EXTI_Line = EXTI_Line10;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);			// Configure EXTI Line10 to generate an interrupt on falling edge

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource10);	// Connect EXTI Line10 to PA.10
}

//初始化定时器10ms
void SysTick_Configuration(void)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);	// config systick to generate fixed time unit
	SysTick_SetReload(720000);			// SysTick interrupt each 100 Hz (time unit = 10ms) with HCLK equal to 72MHz
//	SysTick_SetReload(72000);			// SysTick interrupt each 1000 Hz (time unit = 1ms)

	SysTick_ITConfig(ENABLE);							// Enable the SysTick Interrupt
	SysTick_CounterCmd(SysTick_Counter_Clear);			// Clear the SysTick Counter
}

中断服务函数代码:

//PA10中断,关中断,并打开定时器
void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line10) != RESET) {
		EXTI->PR = EXTI_Line10;	// EXTI_ClearITPendingBit(EXTI_Line10);	// Clear the EXTI line 10 pending bit
		*(vu32 *)(EXTI_BASE + EXTI_Mode_Interrupt) &= ~EXTI_Line10;		// Mask EXTI line 10 interrupt

		SysTick_CounterCmd(SysTick_Counter_Enable);			// Enable the SysTick Counter
	}
}


//DMA接收完成中断
void DMA1_Channel5_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC5)) {
		DMA_ClearITPendingBit(DMA1_IT_GL5);		// Clear DMA1 Channel5 interrupt pending bits
		I_Length = Rx_Buffer_Size;   //设置最大长度
		RX_Flag = 1;   //接收标志
	}
}

//定时器中断,做超时处理
void SysTickHandler(void)
{
#ifdef _SysTick
	DMA_Delay_CNT ++;
	if (DMA_Delay_CNT == DELAY_TIME) {
		SysTick_CounterCmd(SysTick_Counter_Disable);	// Disable the SysTick Counter

		CurrDataCounterEnd = DMA_GetCurrDataCounter(DMA1_Channel5);		// Get Current Data Counter value after complete transfer
		I_Length = Rx_Buffer_Size - CurrDataCounterEnd;	// Count the data length which have received.

		RX_Flag = 1;
	}
#endif
}


主函数:

while (1) 
{
	if (RX_Flag == 1) 
	{
		RX_Flag = 0;
		/*
			处理接收数据
		*/

		DMA_Delay_CNT = 0;
		DMA_Configuration();	//重新设置DMA
		*(vu32 *)(EXTI_BASE + EXTI_Mode_Interrupt) |= EXTI_Line10;	//开外部中断
	}
}

PS:方法简单粗暴有效,据说还有通过判断uart空闲中断来接收不定长DMA数据的。

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值