stm32 串口dma printf
时间: 2025-05-18 07:37:45 浏览: 13
### STM32 使用串口 DMA 实现 `printf` 功能
在 STM32 中,可以通过 HAL 库结合串口和 DMA 来实现类似于 C 标准库中的 `printf` 函数的功能。以下是具体的实现方法:
#### 1. **重定义 `_write` 函数**
为了使标准库的 `printf` 能够通过串口输出数据,需要重新定义 `_write` 函数。该函数会被 `printf` 调用以写入字符流。
```c
#include "stm32f4xx_hal.h"
int _write(int file, unsigned char *ptr, int len) {
if (file != STDOUT_FILENO && file != STDERR_FILENO) {
errno = EBADF;
return -1;
}
// 使用 HAL_UART_Transmit_DMA 发送数据
HAL_UART_Transmit_DMA(&huart4, (uint8_t *)ptr, len);
return len;
}
```
此部分代码实现了将 `printf` 的输出重定向到指定的 UART 接口中[^4]。
---
#### 2. **初始化串口并启用 DMA**
在使用 DMA 进行传输之前,需先正确配置串口及其对应的 DMA 控制器。
##### 初始化代码示例:
```c
UART_HandleTypeDef huart4;
void MX_USART4_UART_Init(void) {
huart4.Instance = USART4;
huart4.Init.BaudRate = 115200;
huart4.Init.WordLength = UART_WORDLENGTH_8B;
huart4.Init.StopBits = UART_STOPBITS_1;
huart4.Init.Parity = UART_PARITY_NONE;
huart4.Init.Mode = UART_MODE_TX_RX;
huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart4.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart4) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(&huart4, hdmatx, hdma_usart4_tx);
}
static void MX_DMA_Init(void) {
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_usart4_tx.Instance = DMA1_Stream4;
hdma_usart4_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart4_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart4_tx.Init.Mode = DMA_NORMAL;
hdma_usart4_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart4_tx) != HAL_OK) {
Error_Handler();
}
}
```
以上代码完成了串口和 DMA 的基本初始化工作。
---
#### 3. **处理 DMA 完成中断**
为了让程序能够连续发送数据而不阻塞 CPU,可以在 DMA 传输完成后触发回调函数来继续操作。
```c
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART4) {
// 如果存在更多待发数据,则再次启动 DMA
if (tx_buffer_length > 0) {
HAL_UART_Transmit_DMA(huart, tx_buffer_ptr, tx_buffer_length);
}
}
}
```
此处逻辑确保了即使当前 DMA 正处于忙碌状态,后续的数据也能被及时发送出去[^3]。
---
#### 4. **自定义 `print` 函数**
为了避免与标准库中的 `printf` 名称冲突,可创建一个新的名为 `print` 的封装函数。
```c
#include <stdarg.h>
void print(const char* format, ...) {
va_list args;
static char buffer[256]; // 缓冲区大小可根据实际需求调整
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
printf("%s", buffer); // 利用已重写的 printf 输出至串口
}
```
这样便能轻松调用类似 `print("Hello %d\n", value)` 的语句[^1]。
---
### 总结
上述方案展示了如何利用 STM32 的 HAL 库配合 DMA 技术高效地完成基于串口的 `printf` 数据打印任务。这种方法不仅释放了主处理器资源用于执行更重要的计算任务,还简化了开发流程。
阅读全文
相关推荐


















