STM32 LL库 串口DMA发送 接收配置教程
STM32CubeMX配置
- 配置时钟树
2.我这个是STM32F407VGT6 所以使用168MHZ主频 - 串口配置
波特率采用默认的115200,都不做修改
- DMA配置
配置DMA发送和接收,接收可根据自己需要设置成正常模式和循环模式
别忘了开中断
至此STM32CubeMX配置完成
代码初始化
STM32CubeMX初始化完成后,配置的代码我们不用管,接下来写发送接收配置
- 首先自己封装个函数用于初始化串口
void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
{
}
- 然后调用STM32CubeMX配置的函数
void Debug_Init(void)//我这里就叫 Debug_Init 可以自己设置
{
MX_USART1_UART_Init();//硬件初始化
}
- 然后进行以下配置
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串口收发到此完成