STM32 LL库串口DMA发送接收配置教程详解

STM32 LL库 串口DMA发送 接收配置教程

  • STM32CubeMX配置
  • 代码初始化
  • 发送功能
  • 接收功能
  • STM32CubeMX配置

    1. 配置时钟树
      2.我这个是STM32F407VGT6 所以使用168MHZ主频
    2. 串口配置

    波特率采用默认的115200,都不做修改

    1. DMA配置
      配置DMA发送和接收,接收可根据自己需要设置成正常模式和循环模式

      别忘了开中断

      至此STM32CubeMX配置完成

    代码初始化

    STM32CubeMX初始化完成后,配置的代码我们不用管,接下来写发送接收配置

    1. 首先自己封装个函数用于初始化串口
    void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
    {
    }
    
    1. 然后调用STM32CubeMX配置的函数
    void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
    {
       MX_USART1_UART_Init();//硬件初始化
    }
    
    1. 然后进行以下配置
    void Debug_Init(void)
    {
        MX_USART1_UART_Init();//硬件初始化
        
        //配置串口方向,我这里是发送和接收都要
        LL_USART_SetTransferDirection(USART1,LL_USART_DIRECTION_TX_RX);
    
        /*接收配置*/
        //使能空闲中断
        LL_USART_EnableIT_IDLE(USART1);
        //设置内存地址,也就是设置接收的数据要放哪
        LL_DMA_SetMemoryAddress(DMA2,LL_DMA_STREAM_2,(uint32_t)buf);
        //设置接收最大数据长度
        LL_DMA_SetDataLength(DMA2,LL_DMA_STREAM_2,MAX_SIZE);
        //设置外设地址,也就是设置串口的数据寄存器
        LL_DMA_SetPeriphAddress(DMA2,LL_DMA_STREAM_2,(uint32_t)&USART1->DR);
    	//使能DMA2发送完成中断
        LL_DMA_EnableIT_TC(DMA2,LL_DMA_STREAM_2);
        //使能接收的DMA2 STREAM_2
        LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);
        //使能DMA串口接收
        LL_USART_EnableDMAReq_RX(USART1);
        
        /*发送配置*/
        //设置外设地址,因为这个是DMA串口发送,
        LL_DMA_SetPeriphAddress(DMA2,LL_DMA_STREAM_7,(uint32_t)&USART1->DR);
        //使能DMA串口发送
        LL_USART_EnableDMAReq_TX(USART1);
        //使能DMA2发送完成中断
        LL_DMA_EnableIT_TC(DMA2,LL_DMA_STREAM_7);
    }
    

    !!!注意!!!
    以上代码配置中的 DMA2,LL_DMA_STREAM_2,LL_DMA_STREAM_7,是根据STM32CubeMX设置的,移植的时候注意一下自己的配置

    以上配置中我特意没写使能发送的 DMA_Stream,我们按下不表

    我这里
    USART1_RX 对应DMA2,DMA_STREAM_2
    USART1_TX 对应DMA2,DMA_STREAM_7

    以上配置完成,接下来编写DMA串口发送接收功能

    发送功能

    发送功能很简单,因为配置中设置了发送的外设固定为USART1->DR

      //设置外设地址,因为这个是DMA串口发送,
        LL_DMA_SetPeriphAddress(DMA2,LL_DMA_STREAM_7,(uint32_t)&USART1->DR);
    

    所以我们只需要配置内存地址,数据长度再使能DMA_Stream 即可发送
    如下

    void UART_DMA_Send(USART_TypeDef *USARTx,uint8_t *str,uint16_t size)
    {
    	//配置内存地址
        LL_DMA_SetMemoryAddress(DMA2,LL_DMA_STREAM_7,(uint32_t)str);
        //配置数据长度
        LL_DMA_SetDataLength(DMA2,LL_DMA_STREAM_7,size);
        //使能DMA STREAM  也就是发送数据
        LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_7);
    }
    

    为什么我要在发送中才设置 LL_DMA_EnableStream?

    首先我们先看一下这个函数

    __STATIC_INLINE void LL_DMA_EnableStream(DMA_TypeDef *DMAx, uint32_t Stream)
    {
      SET_BIT(((DMA_Stream_TypeDef *)((uint32_t)((uint32_t)DMAx + STREAM_OFFSET_TAB[Stream])))->CR, DMA_SxCR_EN);
    }
    

    很明显,我们可以看到这个函数的作用是配置DMA_SxCR_EN,我们查看手册

    这是一个使能DMA通道的,那这个和发送有啥关系呢,接收都可以在配置的时候使能,我们继续查看手册

    我们可以看到当DMA_SxCR_EN=1时数据长度寄存器,外设地址寄存器,内存地址寄存器均为只读状态,所以LL_DMA_EnableStream()这个函数我们只有在全部设置好的时候使用即可发送数据,那新的问题又出现了,我们在这里设置了DMA_SxCR_EN=1,这个又不会自动置0那应该怎么办呢?
    其实我们在配置发送的时候设置了DMA发送中断

        //使能DMA2发送完成中断
        LL_DMA_EnableIT_TC(DMA2,LL_DMA_STREAM_7);
    

    那我们可以在中断里面写一个函数用于置0,如下

    void DMA2_Stream7_IRQHandler(void)
    {
        if(LL_DMA_IsActiveFlag_TC7(DMA2))
        {
        	//清除Stream7 TC中断
            LL_DMA_ClearFlag_TC7(DMA2);
            //关闭DMA2 Stream7
            LL_DMA_DisableStream(DMA2,LL_DMA_STREAM_7);
        }
    }
    

    其中LL_DMA_IsActiveFlag_TC7 中的TC7的7指的是Stream7,所以大家要根据自己的实际情况修改

    最后我对这个发送函数做一个封装

    int uart_printf(USART_TypeDef *USARTx,const char *fmt, ...)
    {
        va_list arg;
        int cnt;
        char buffer[FIFO_MAX_SIZE];
    
        va_start(arg,fmt);
        cnt=vsprintf(buffer,fmt,arg);
        va_end(arg);
    	
    	//这里使用了strlen 记得声明string.h
        UART_DMA_Send(USARTx,(uint8_t*)buffer,strlen(buffer));
    
        return cnt;
    }
    

    接收功能

    接收功能如下所示

    void USART1_IRQHandler(void)
    {
        if(LL_USART_IsActiveFlag_IDLE(USART1))
        {
        	//清除空闲中断
            LL_USART_ClearFlag_IDLE(USART1);
            //得到接收数据的长度LL_DMA_GetDataLength(DMA2, LL_DMA_STREAM_2);得到的是剩余的内存大小
            rx_len =MAX_SZIE - LL_DMA_GetDataLength(DMA2, LL_DMA_STREAM_2);
        }
    }
    

    至此,STM32 LL库 DMA串口收发到此完成

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 LL库串口DMA发送接收配置教程详解

    发表回复