当前位置:   article > 正文

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

stm32 ll dma

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

STM32CubeMX配置

  1. 配置时钟树在这里插入图片描述
    2.我这个是STM32F407VGT6 所以使用168MHZ主频在这里插入图片描述
  2. 串口配置

波特率采用默认的115200,都不做修改在这里插入图片描述

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

    别忘了开中断
    在这里插入图片描述
    至此STM32CubeMX配置完成

代码初始化

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

  1. 首先自己封装个函数用于初始化串口
void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
{
}
  • 1
  • 2
  • 3
  1. 然后调用STM32CubeMX配置的函数
void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
{
   MX_USART1_UART_Init();//硬件初始化
}
  • 1
  • 2
  • 3
  • 4
  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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

!!!注意!!!
以上代码配置中的 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);
  • 1
  • 2

所以我们只需要配置内存地址,数据长度再使能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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

为什么我要在发送中才设置 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);
}
  • 1
  • 2
  • 3
  • 4

很明显,我们可以看到这个函数的作用是配置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);
  • 1
  • 2

那我们可以在中断里面写一个函数用于置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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

接收功能

接收功能如下所示

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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/761827
推荐阅读
相关标签
  

闽ICP备14008679号