STM32 DMA 应用之(二) DMA 串口 数据传输--发送
阅读原文时间:2021年04月20日阅读:1

一、DMA请求映像

由此我们知道如果需要使用串口1的发送功能需要用到的是DMA1_Channel4

使用串口1的接收功能需要用到的是DMA1_Channel5

二、怎样配置软件来使用DMA  把数据传到串口发送?

(1)配置dma

/**************************************************************************
*函数名称:  Dma_Init 
*功能描述: 利用DMA 把内存的数据传输到串口发送达到高速传输的目的
*  
*输入参数:无
*返回值  :无
*其他说明:无
*当前版本:v1.0 
*作者     :尹宣
*完成时间:2013年12月1日
*修改日期              版本号              修改人              修改内容
*----------------------------------------------------------------- 
* 
******************************************************************/ 
#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;

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;    //字(32位)
 DMA_InitStructure.DMA_MemoryDataSize            =DMA_PeripheralDataSize_Byte;  //内存存储方式:字节  DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode                                  =DMA_Mode_Circular;  //DMA_Mode_Normal 正常模式,只传送一次;  DMA_Mode_Circular:循环模式,不停的传送;
 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
//采用DMA方式发送
       USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); 
       //启动串口   
       USART_Cmd(USART1,ENABLE); 


  DMA_ITConfig(DMA1_Channel4,DMA_IT_TC, ENABLE);
传输完成则进入DMA1_Channel4中断;

注意这句话:USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  这是使能指定USART的DMA请求;(不同的外设都有这个  xxx_DMACmd()请求;)

USART_DMAReq_Tx:发送DMA请求

USART_DMAReq_Rx:接收DMA请求 

串口配置

/***************************************************************** 
*函数名称: USART1_Init
*功能描述:   配置串口1初始化
*  
*输入参数:无
*返回值  :无
*其他说明:无
*当前版本:v1.0 
*作者     :尹宣
*完成时间:2013年12月1日
*修改日期              版本号              修改人              修改内容
*----------------------------------------------------------------- 
* 
******************************************************************/ 
void USART1_Init(uint32 baud)
{
       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);  
       //串口1使用接收中断
       USART_ITConfig(USART1,USART_IT_RXNE,(FunctionalState)ENABLE);
}


2.设置DMA优先级

/***************************************************************** 
*函数名称:  NVIC_Config 
*功能描述:   配置DMA的中断优先级
*  
*输入参数:无
*返回值  :无
*其他说明:无
*当前版本:v1.0 
*作者     :尹宣
*完成时间:2013年12月1日
*修改日期              版本号              修改人              修改内容
*----------------------------------------------------------------- 
* 
******************************************************************/ 
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);   

}

3.在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);进行下一次的传输;

测试:

数据源地址为数组Uart_Send_Buffer ,它的定义如下:

#define UART_RX_LEN     5 

u8 Uart_Send_Buffer[UART_RX_LEN] ={0x12,0x34,0x56,0x78,0x90}; 

当程序开始全速运行时,串口助手打印