在STM32开发中,串口是一种常见的通信方式。为了提高数据传输效率,我们可以利用STM32的DMA(Direct Memory Access)功能来实现串口的DMA发送和接收。在本篇文章中,我将详细介绍如何使用STM32的LL库进行串口DMA发送和接收的配置,并提供相应的代码示例。
STM32CubeMX配置
首先,我们需要打开STM32CubeMX软件进行配置。以下是配置步骤:
1. 配置时钟树:根据您的具体型号(例如:STM32F407VGT6),将主频设置为168MHz。
2. 串口配置:波特率采用默认的115200,不做修改。
3. DMA配置:配置DMA发送和接收,可根据需求选择正常模式或循环模式。
4. 开启中断:别忘了在配置中打开中断设置。
完成上述配置后,STM32CubeMX会自动生成相应的初始化代码。
代码初始化
在STM32CubeMX初始化完成后,我们可以开始进行发送和接收功能的配置。首先,我们需要封装一个函数用于初始化串口,例如`Debug_Init()`:
void Debug_Init(void) { MX_USART1_UART_Init(); // 硬件初始化 }
然后,在`Debug_Init()`函数中调用STM32CubeMX生成的初始化函数:
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串口发送和接收功能代码。
发送功能
串口发送功能很简单,由于我们在配置中已经设置了发送的外设固定为`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_SxCR_EN=1`时,数据长度寄存器、外设地址寄存器和内存地址寄存器均为只读状态。因此,`LL_DMA_EnableStream()`函数仅在所有设置完成后使用,以便发送数据。
然而,又出现了一个新问题:我们在发送函数中设置了`DMA_SxCR_EN=1`,但它不会自动复位为0,那我们该如何处理呢?实际上,在配置发送时我们已经设置了DMA发送完成中断:
// 使能DMA2发送完成中断 LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_7);
因此,我们可以在中断处理函数中添加一个用于复位的函数,例如:
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`代表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); 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); // 获取接收数据的长度(剩余内存大小) rx_len = MAX_SIZE - LL_DMA_GetDataLength(DMA2, LL_DMA_STREAM_2); } }
至此,我们完成了STM32 LL库的串口DMA发送和接收的配置。通过本教程,您学会了如何正确配置串口DMA,并实现高效的数据传输。希望这篇文章能对您在STM32开发中使用串口DMA有所帮助。
如果有任何问题,请随时提问。谢谢阅读!
文章来源:https://www.toymoban.com/news/detail-689631.html
关键词:STM32, LL库, 串口, DMA, 发送, 接收, 配置, 教程文章来源地址https://www.toymoban.com/news/detail-689631.html
到了这里,关于STM32 LL库 串口DMA发送接收配置教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!