打印
[STM32F4]

STM32F446RE基于UART和DMA实现高效数据传输

[复制链接]
283|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Bblythe|  楼主 | 2024-11-23 07:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32F446RE是一款高性能的Cortex-M4核心微控制器,具有丰富的外设资源和较高的运行频率。在嵌入式开发中,UART通信是一个非常常见的需求,而DMA的引入可以显著提高数据传输的效率和性能。本文将介绍如何在STM32F446RE上结合UART和DMA,实现一个高效的数据收发机制。
项目需求
  • 使用UART接口发送和接收数据,通过DMA实现无CPU干预的数据传输。
  • 设定固定的数据缓冲区大小,用于存储接收到的数据。
  • 实现数据接收回调函数,在接收完成后触发处理逻辑。
  • 在主循环中模拟数据发送。
硬件环境
  • MCU型号:STM32F446RE
  • 开发工具:STM32CubeIDE
  • 外设配置:USART2与DMA通道结合使用。

代码实现以下是完整代码:
#include "main.h"
#include <string.h>

/* UART句柄和DMA缓冲区 */
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
uint8_t rx_buffer[64]; // 接收缓冲区
uint8_t tx_buffer[] = "Hello from STM32F446RE via UART DMA!\r\n";

/* UART初始化函数 */
void MX_USART2_UART_Init(void) {
    huart2.Instance = USART2;
    huart2.Init.BaudRate = 115200;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart2) != HAL_OK) {
        Error_Handler();
    }
}

/* DMA初始化函数 */
void MX_DMA_Init(void) {
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* 配置DMA RX通道 */
    hdma_usart2_rx.Instance = DMA1_Stream5;
    hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK) {
        Error_Handler();
    }

    /* 将DMA与UART关联 */
    __HAL_LINKDMA(&huart2, hdmarx, hdma_usart2_rx);
}

/* 主函数 */
int main(void) {
    HAL_Init();
    SystemClock_Config();

    MX_DMA_Init();
    MX_USART2_UART_Init();

    /* 启动DMA接收 */
    HAL_UART_Receive_DMA(&huart2, rx_buffer, sizeof(rx_buffer));

    while (1) {
        /* 模拟周期性发送数据 */
        HAL_UART_Transmit(&huart2, tx_buffer, strlen((char *)tx_buffer), HAL_MAX_DELAY);
        HAL_Delay(1000);
    }
}

/* 接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART2) {
        /* 数据处理逻辑:这里简单打印接收到的数据 */
        HAL_UART_Transmit(&huart2, rx_buffer, sizeof(rx_buffer), HAL_MAX_DELAY);
    }
}

/* 错误处理函数 */
void Error_Handler(void) {
    while (1) {
        // 错误循环
    }
}
代码说明
  • UART初始化:USART2配置为115200波特率,无校验位,使用全双工模式。
  • DMA初始化:DMA通道与UART接收器关联,配置为循环模式,用于持续接收数据。
  • 回调函数:当接收到数据时触发HAL_UART_RxCpltCallback回调函数,模拟数据的回显逻辑。
  • 数据发送:主循环中定时发送字符串,以验证UART发送功能。

项目特点
  • 使用DMA减少了CPU的负载,使得数据传输更加高效。
  • 循环模式使UART接收端能够持续处理数据,无需频繁重新配置。
  • HAL库的使用提高了代码的可读性和兼容性。

使用特权

评论回复
沙发
公羊子丹| | 2024-11-23 07:49 | 只看该作者
STM32F446RE性能确实不错,DMA加UART真的很实用!

使用特权

评论回复
板凳
周半梅| | 2024-11-23 07:50 | 只看该作者
UART回调函数写得挺好,接收到数据后直接回显,挺方便的。

使用特权

评论回复
地板
帛灿灿| | 2024-11-23 07:50 | 只看该作者
我用的STM32F103,代码看起来能直接改用到我的项目里。

使用特权

评论回复
5
童雨竹| | 2024-11-23 07:50 | 只看该作者
这个例子挺全的,连DMA的配置都包括了,学习了!

使用特权

评论回复
6
万图| | 2024-11-23 07:50 | 只看该作者
我发现HAL库确实方便,但性能要求高时还是更喜欢用LL。

使用特权

评论回复
7
Wordsworth| | 2024-11-23 07:50 | 只看该作者
如果想用多个UART通道,是不是每个都需要一个独立的DMA通道?

使用特权

评论回复
8
Bblythe|  楼主 | 2024-11-23 07:51 | 只看该作者
这个接收缓冲区大小会不会影响大文件传输的稳定性?

使用特权

评论回复
9
Pulitzer| | 2024-11-23 07:51 | 只看该作者
能不能加个超时检测逻辑,防止UART卡住?

使用特权

评论回复
10
Uriah| | 2024-11-23 07:51 | 只看该作者
下次能讲讲如何通过中断和DMA结合处理复杂协议吗?

使用特权

评论回复
11
Clyde011| | 2024-11-23 07:51 | 只看该作者
感觉这个例子扩展性很好,直接用到项目里没问题!

使用特权

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

本版积分规则

36

主题

3684

帖子

0

粉丝