发新帖我要提问
12
返回列表
打印
[应用相关]

STM32 USART 串口 DMA 接收和发送的源码详解!

[复制链接]
楼主: hehhehee
手机看帖
扫描二维码
随时随地手机跟帖
21
hehhehee|  楼主 | 2021-8-4 22:03 | 只看该作者 回帖奖励 |倒序浏览


void
DMA_Uart_Init(void)

{

    DMA_InitTypeDef DMA_InitStructure;

   

    /* DMA clock enable */

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,
ENABLE); // 开启DMA1时钟

   

   

//=DMA_Configuration==============================================================================//


使用特权

评论回复
22
hehhehee|  楼主 | 2021-8-4 22:04 | 只看该作者
/*---
LUMMOD_UART_Tx_DMA_Channel DMA Config ---*/



    DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel,
DISABLE);                           // 关DMA通道

    DMA_DeInit(LUMMOD_UART_Tx_DMA_Channel);                                 // 恢复缺省值

    DMA_InitStructure.DMA_PeripheralBaseAddr =
(uint32_t)(&LUMMOD_UART->DR);// 设置串口发送数据寄存器

    DMA_InitStructure.DMA_MemoryBaseAddr =
(uint32_t)LumMod_Tx_Buf;         // 设置发送缓冲区首地址

    DMA_InitStructure.DMA_DIR =
DMA_DIR_PeripheralDST;                      //
设置外设位目标,内存缓冲区 -> 外设寄存器

    DMA_InitStructure.DMA_BufferSize =
LUMMOD_TX_BSIZE;                     //
需要发送的字节数,这里其实可以设置为0,因为在实际要发送的时候,会重新设置次值

    DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_Disable;        // 外设地址不做增加调整,调整不调整是DMA自动实现的

    DMA_InitStructure.DMA_MemoryInc =
DMA_MemoryInc_Enable;                 //
内存缓冲区地址增加调整

    DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节

    DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Byte;         // 内存数据宽度8位,1个字节

    DMA_InitStructure.DMA_Mode =
DMA_Mode_Normal;                           //
单次传输模式

    DMA_InitStructure.DMA_Priority =
DMA_Priority_VeryHigh;                 //
优先级设置

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                            //
关闭内存到内存的DMA模式

    DMA_Init(LUMMOD_UART_Tx_DMA_Channel,
&DMA_InitStructure);               // 写入配置

    DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG);                                 // 清除DMA所有标志

DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE); // 关闭DMA

    DMA_ITConfig(LUMMOD_UART_Tx_DMA_Channel,
DMA_IT_TC, ENABLE);            // 开启发送DMA通道中断

   

/*--- LUMMOD_UART_Rx_DMA_Channel
DMA Config ---*/


使用特权

评论回复
23
hehhehee|  楼主 | 2021-8-4 22:06 | 只看该作者
  DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel,
DISABLE);                           // 关DMA通道

    DMA_DeInit(LUMMOD_UART_Rx_DMA_Channel);                                 // 恢复缺省值

    DMA_InitStructure.DMA_PeripheralBaseAddr =
(uint32_t)(&LUMMOD_UART->DR);// 设置串口接收数据寄存器

    DMA_InitStructure.DMA_MemoryBaseAddr =
(uint32_t)LumMod_Rx_Buf;         // 设置接收缓冲区首地址

    DMA_InitStructure.DMA_DIR =
DMA_DIR_PeripheralSRC;                      //
设置外设为数据源,外设寄存器 -> 内存缓冲区

    DMA_InitStructure.DMA_BufferSize =
LUMMOD_RX_BSIZE;                     //
需要最大可能接收到的字节数

使用特权

评论回复
24
hehhehee|  楼主 | 2021-8-4 22:07 | 只看该作者
DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_Disable;        // 外设地址不做增加调整,调整不调整是DMA自动实现的

    DMA_InitStructure.DMA_MemoryInc =
DMA_MemoryInc_Enable;                 //
内存缓冲区地址增加调整

    DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节

    DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Byte;         // 内存数据宽度8位,1个字节

    DMA_InitStructure.DMA_Mode =
DMA_Mode_Normal;                           //
单次传输模式

    DMA_InitStructure.DMA_Priority =
DMA_Priority_VeryHigh;                 //
优先级设置

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                            //
关闭内存到内存的DMA模式

    DMA_Init(LUMMOD_UART_Rx_DMA_Channel,
&DMA_InitStructure);               // 写入配置

    DMA_ClearFlag(LUMMOD_UART_Rx_DMA_FLAG);                                 // 清除DMA所有标志

    DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, ENABLE);                            // 开启接收DMA通道,等待接收数据

使用特权

评论回复
25
hehhehee|  楼主 | 2021-8-4 22:08 | 只看该作者
}

void BSP_Init(void)

{

    Uart_Init();

}



//============================================================//

使用特权

评论回复
26
hehhehee|  楼主 | 2021-8-4 22:09 | 只看该作者
DMA 发送应用源码



void
DMA1_Channel2_IRQHandler(void)

{

    if(DMA_GetITStatus(DMA1_FLAG_TC2))

    {

        LumMod_Uart_DAM_Tx_Over();

    }

}

void
LumMod_Uart_DAM_Tx_Over(void)

{

    DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG);         // 清除标志

    DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel,
DISABLE);   // 关闭DMA通道

    OSMboxPost(mbLumModule_Tx, (void*)1);           // 设置标志位,这里我用的是UCOSII ,可以根据自己的需求进行修改

}

使用特权

评论回复
27
hehhehee|  楼主 | 2021-8-4 22:10 | 只看该作者
void
LumMod_Cmd_WriteParam( uint8 sample_num, uint8 *psz_param )

{

    uint8 err;

    uint8 LumMod_Tx_Index ;



    LumMod_Tx_Index = 0;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 1;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 2;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 3;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 4;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 5;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 6;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 7;

    LumMod_Tx_Buf[LumMod_Tx_Index++] = 8;

   

    LumMod_Uart_Start_DMA_Tx( LumMod_Tx_Index );

    OSMboxPend(mbLumModule_Tx, 0, &err);

}

使用特权

评论回复
28
hehhehee|  楼主 | 2021-8-4 22:11 | 只看该作者
void
LumMod_Uart_Start_DMA_Tx(uint16_t size)

{

    LUMMOD_UART_Tx_DMA_Channel->CNDTR =
(uint16_t)size; // 设置要发送的字节数目

    DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, ENABLE);        //开始DMA发送

}



//============================================================//

使用特权

评论回复
29
hehhehee|  楼主 | 2021-8-4 22:11 | 只看该作者
DMA 接收应用源码



void
USART3_IRQHandler(void)

{

    if(USART_GetITStatus(USART3, USART_IT_IDLE)
!= RESET)  // 空闲中断

    {

        LumMod_Uart_DMA_Rx_Data();

        USART_ReceiveData( USART3 ); // Clear
IDLE interrupt flag bit

    }

}

void
LumMod_Uart_DMA_Rx_Data(void)

{

使用特权

评论回复
30
hehhehee|  楼主 | 2021-8-4 22:12 | 只看该作者
    DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel,
DISABLE);       // 关闭DMA ,防止干扰

    DMA_ClearFlag( LUMMOD_UART_Rx_DMA_FLAG );           // 清DMA标志位

    LumMod_Rx_Data.index = LUMMOD_RX_BSIZE -
DMA_GetCurrDataCounter(LUMMOD_UART_Rx_DMA_Channel); //获得接收到的字节数

    LUMMOD_UART_Rx_DMA_Channel->CNDTR =
LUMMOD_RX_BSIZE;    //  重新赋值计数值,必须大于等于最大可能接收到的数据帧数目

    DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, ENABLE);        /* DMA 开启,等待数据。注意,如果中断发送数据帧的速率很快,MCU来不及处理此次接收到的数据,中断又发来数据的话,这里不能开启,否则数据会被覆盖。

使用特权

评论回复
31
hehhehee|  楼主 | 2021-8-4 22:13 | 只看该作者
1. 在重新开启接收DMA通道之前,将LumMod_Rx_Buf缓冲区里面的数据复制到另外一个数组中,然后再开启DMA,然后马上处理复制出来的数据。

使用特权

评论回复
32
hehhehee|  楼主 | 2021-8-4 22:15 | 只看该作者
   2. 建立双缓冲,在LumMod_Uart_DMA_Rx_Data函数中,重新配置DMA_MemoryBaseAddr 的缓冲区地址,那么下次接收到的数据就会保存到新的缓冲区中,不至于被覆盖。*/

使用特权

评论回复
33
hehhehee|  楼主 | 2021-8-4 22:16 | 只看该作者
OSMboxPost(mbLumModule_Rx,  LumMod_Rx_Buf); // 发送接收到新数据标志,供前台程序查询

}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则