zoukankan      html  css  js  c++  java
  • STM32的串口DMA收发以及双缓冲区的实现

    在使用STM32的UART的DMA功能总结如下:

    首先上代码,这里采用STM32 的USART1作为Demo,RX的DMA为DMA1_Channel5,TX的DMA为DMA1_Channel4.初始化如下,红色的标记需要注意:

    RX-DMA初始化

     1 // DMA Rx
     2 USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  
     3 DMA_Cmd(DMA1_Channel5,DISABLE);
     4 DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
     5 DMA_InitStruct.DMA_MemoryBaseAddr = (u32)RxBuf0;
     6 DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
     7 DMA_InitStruct.DMA_BufferSize = 10;
     8 DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
     9 DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    10 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    11 DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    12 DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
    13 DMA_InitStruct.DMA_Priority = DMA_Priority_High;
    14 DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    15 DMA_Init(DMA1_Channel5,&DMA_InitStruct);
    16 DMA_Cmd(DMA1_Channel5,ENABLE);

    中断的初始化如下:

        DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
        NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
    
        //ENABLE DMA TX ISR
        DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
        NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel4_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);

    TX发送函数如下:

     1 void USART1_SendDMA(uint8_t* buf,int len)
     2 {
     3     DMA_InitTypeDef DMA_InitStruct;
    5 DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); 6 7 DMA_Cmd(DMA1_Channel4,DISABLE);
    8 9 DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); 10 DMA_InitStruct.DMA_MemoryBaseAddr = (u32)buf; 11 DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; 12 DMA_InitStruct.DMA_BufferSize = len; 13 DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 14 DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; 15 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 16 DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; 17 DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; 18 DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; 19 DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; 20 DMA_Init(DMA1_Channel4,&DMA_InitStruct); 21 22 DMA_Cmd(DMA1_Channel4,ENABLE); 23 }

    两个服务函数如下:

    RX-DMA中断函数,实现RX的双缓冲区功能。值得注意的是,你的DMA设置成Normal模式的时候,在中断函数中就得设置DMABufferSize,应为Normal模式完成一次传输之后,BufferSize直接清零,设置成Circle模式就不会存在这个问题,下面的中断就是设置成Circle模式的。

    void DMA1_Channel5_IRQHandler()
    {
        if(DMA_GetITStatus(DMA1_IT_TC5))
      {
          if(using_buf0 ==0)
        {
          DMA1_Channel5->CMAR = (u32)RxBuf0;
             using_buf0 = 1;
        }
        else
        {
             DMA1_Channel5->CMAR = (u32)RxBuf1;
             using_buf0 = 0;
        }
        recv_flag = 1;
        DMA_ClearITPendingBit(DMA1_IT_TC5);
      }    
    }

    TX-DMA中断函数

    void DMA1_Channel4_IRQHandler()
    {
        if(DMA_GetITStatus(DMA1_IT_TC4))
        {
            //TODO:Add code here
            DMA_ClearITPendingBit(DMA1_IT_TC4);
        }    
    }

     几点说明

    1)这里采用双缓冲区的方式,对于大数据量的时候是很有效的,在处理一个缓冲区数据的时候,另外一个缓冲区能够正常接收数据

    2)TX的DMA中断,可以采用类似于操作系统中互斥量的操作,当一个数组还在发送的时候,另外一个数组如果检测到一个在发送,则不能够进行发送,不然这样子数据会乱掉;

    3)如果DMA接收想采用循环缓冲区的方式,可以直接将RX-DMA设置成Circle方式,然后数据就会硬件上自动实现环形缓冲区的功能,省了不少时间。

    4)DMA在采用Normal模式的时候,当一次任务完成后,DMA->DMA_BufferSize自动清零,并且DMA自动停止。如果想再次设置DMA的BufferSize的话,必须要进行如下操作:

       step1:DMA_CMD(DMAx_Channely,DISABLE);

       step2: 设置DMA_BufferLen

       step3:DMA_CMD(DMAx_Channely,ENABLE)

    5)DMA采用Circle模式的时候,在发送或者接受完成之后,仍然保存着BufferSize,并且DMA还处于使能状态,一直连续工作,直到用户停止DMA

  • 相关阅读:
    P4995 跳跳!
    P4306 [JSOI2010]连通数
    P1339 [USACO09OCT]热浪Heat Wave
    P2002 消息扩散
    P3388 【模板】割点(割顶)
    P1656 炸铁路
    P2863 [USACO06JAN]牛的舞会The Cow Prom
    P1516 青蛙的约会
    3.从尾到头打印链表
    2.替换空格
  • 原文地址:https://www.cnblogs.com/shangzhimeng/p/4154236.html
Copyright © 2011-2022 走看看