如何在STM32中正确重定向fprintf到多个UART目标?
解决多UART目标的fprintf输出问题
问题根源
你直接将USART1(外设基地址)强转为FILE*是错误的——newlib的FILE是包含缓冲区、操作函数指针等的结构体,并非硬件地址。这种非法转换会导致newlib无法识别该“文件对象”,自然不会触发_write_r。
核心解决思路
利用newlib的重入函数机制处理标准流(stdout/stderr),同时通过fopencookie创建绑定特定UART的自定义FILE对象,实现多目标输出切换。
方案一:重定向标准流到不同UART
通过重写_write_r,根据文件描述符(fd)区分标准流,映射到对应UART:
#include <stdio.h> #include <reent.h> #include <unistd.h> #include <errno.h> // 实现各UART的批量发送函数 static void uart1_send(const char* data, size_t len) { for (size_t i = 0; i < len; i++) { while (!(USART1->SR & USART_SR_TXE)); // 等待发送寄存器空 USART1->DR = data[i]; } } static void uart2_send(const char* data, size_t len) { for (size_t i = 0; i < len; i++) { while (!(USART2->SR & USART_SR_TXE)); USART2->DR = data[i]; } } // 重写newlib重入版_write函数 int _write_r(struct _reent *reent, int fd, char *ptr, size_t len) { switch (fd) { case STDOUT_FILENO: // stdout对应fd=1 uart1_send(ptr, len); break; case STDERR_FILENO: // stderr对应fd=2 uart2_send(ptr, len); break; default: reent->_errno = EBADF; // 非法文件描述符 return -1; } return len; // 返回已发送字节数 }
使用方式:
fprintf(stdout, "输出到UART1的内容\n"); fprintf(stderr, "输出到UART2的内容\n");
方案二:创建自定义UART对应的FILE对象
如果需要更多UART输出目标,用fopencookie绑定自定义操作函数,生成合法的FILE对象:
#include <stdio.h> #include <sys/cookie_io_functions.h> // UART3的发送函数 static ssize_t uart3_write(void *cookie, const char *buf, size_t size) { for (size_t i = 0; i < size; i++) { while (!(USART3->SR & USART_SR_TXE)); USART3->DR = buf[i]; } return size; } // 自定义FILE的关闭函数(可空实现) static int uart3_close(void *cookie) { return 0; } // 全局自定义FILE对象 FILE* uart3_file; // 初始化自定义FILE void uart3_file_init(void) { uart3_file = fopencookie((void*)USART3, "w", (cookie_io_functions_t){ .read = NULL, // 写模式不需要读函数 .write = uart3_write, .seek = NULL, // UART无需定位操作 .close = uart3_close }); }
使用方式:
// 先初始化 uart3_file_init(); // 直接用fprintf输出到UART3 fprintf(uart3_file, "输出到UART3的内容\n");
额外优化建议
- 缓冲输出:用
setbuf(uart3_file, NULL)关闭缓冲(实时输出),或自定义缓冲区减少UART调用次数,提升效率。 - 编译选项:确保使用newlib/newlib-nano时开启重入模式(默认已开启,无需额外配置)。
- 非阻塞发送:如果需要异步输出,可结合DMA实现UART发送,避免阻塞主程序。
内容的提问来源于stack exchange,提问作者yo3hcv
相关产品推荐
相关产品推荐

