在许多嵌入式系统中,UART(通用异步接收/发送)是一种常见的通信协议,用于低速串行数据传输。
通过DMA(直接内存访问)控制UART通信,可以有效地释放CPU资源,使其能够处理其他计算任务。
本文将介绍如何在STM32微控制器上实现DMA控制的UART通信。
⬇帮大家整理了单片机的资料
包括stm32的项目合集【源码+开发文档】
点击下方蓝字即可领取,感谢支持!⬇
点击领取更多嵌入式详细资料
问题讨论,stm32的资料领取可以私信!
一、开发环境准备
硬件要求
- 微控制器:STM32F407VGT6,具备高性能处理能力和丰富的外设支持。
- 开发板:STM32F4 Discovery,提供必要的调试和开发接口,包括UART接口。
- 外部设备:PC或其他UART兼容设备,用于接收和发送数据。
软件要求
- 集成开发环境(IDE):STM32CubeIDE,支持代码开发、编译及调试。
- 固件库:STM32CubeMX,用于配置微控制器的外设,包括UART接口和DMA通道。
安装和配置
- 安装STM32CubeIDE:从ST官网下载并安装。
- 使用STM32CubeMX创建项目:选择STM32F407VGT6芯片,配置UART接口和相应的DMA通道,生成初始化代码。
二、应用场景:高效UART数据传输
设计目标
创建一个系统,能够通过UART接口高效地接收和发送大量数据,使用DMA来自动处理数据传输,适用于例如日志记录、远程命令解析等场景。
代码实现
#include "stm32f4xx_hal.h"
UART_HandleTypeDef huart3;
DMA_HandleTypeDef hdma_uart3_rx;
DMA_HandleTypeDef hdma_uart3_tx;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_UART3_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_UART3_Init();
uint8_t txData[] = "Hello UART DMA!";
uint8_t rxData[100] = {0}; // 更大的接收缓冲区
// 启动DMA接收
HAL_UART_Receive_DMA(&huart3, rxData, sizeof(rxData));
// 启动DMA发送
HAL_UART_Transmit_DMA(&huart3, txData, sizeof(txData));
while (1)
{
// 主循环中不需要执行任何操作,DMA控制器处理所有UART数据传输
}
}
void MX_DMA_Init(void)
{
__HAL_RCC_DMA1_CLK_ENABLE();
// 配置UART3 RX DMA
hdma_uart3_rx.Instance = DMA1_Stream1;
hdma_uart3_rx.Init.Channel = DMA_CHANNEL_4;
hdma_uart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_uart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_uart3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart3_rx.Init.Mode = DMA_CIRCULAR;
hdma_uart3_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_uart3_rx);
__HAL_LINKDMA(&huart3, hdmarx, hdma_uart3_rx);
// 配置UART3 TX DMA
hdma_uart3_tx.Instance = DMA1_Stream3;
hdma_uart3_tx.Init.Channel = DMA_CHANNEL_4;
hdma_uart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_uart3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_uart3_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart3_tx.Init.Mode = DMA_NORMAL;
hdma_uart3_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_uart3_tx);
__HAL_LINKDMA(&huart3, hdmatx, hdma_uart3_tx);
}
void MX_UART3_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
// 当DMA完成UART数据发送时调用此回调函数
if(huart->Instance == USART3)
{
// 发送完成后的操作
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// 当DMA完成UART数据接收时调用此回调函数
if(huart->Instance == USART3)
{
// 接收完成后的操作,例如处理接收到的数据
}
}
void Error_Handler(void)
{
// 用户可以在此处添加错误处理代码
__disable_irq();
while (1)
{
}
}
问题解决方案
- DMA通道冲突:确保为UART接收和发送选择不同的DMA通道或流,以避免资源冲突。
- 数据对齐问题:在初始化DMA时,设置正确的数据对齐选项以确保数据的正确传输。
- 缓冲管理:使用合适的缓冲策略管理DMA缓冲,确保数据在处理前不被覆盖,同时优化内存使用。
通过本教程,开发者可以了解如何在STM32平台上实现基于DMA的UART数据传输,这对于需要高效通信的嵌入式应用非常有益。