串口->重定向
一、什么是重定向
重定向的实现原理,本质上是 拦截并自定义 C 标准库函数的底层输出行为,例如把 printf() 的输出,从默认的“终端/标准输出”改为你想要的输出设备(如串口)。
C 标准库默认把 printf() 输出重定向到 “标准输出设备” stdout。在嵌入式中没有屏幕或终端,所以我们自己告诉它“标准输出”该往哪里发,这就是重定向。
也就是说,printf重定向告诉系统:“以后所有 printf() 输出的字符都不要去默认终端,而是通过 UART 发送出去。”
重定向的原理图
printf("A");
↓
标准库调用内部的 fputc()
↓
你自己重写的 fputc() → 发送到 USART
也可以重定向:
fgetc() ← scanf():重写 fgetc(),实现串口接收。
puts() ← fputs():同理,也通过 fputc() 输出字符
二、什么是fputc()
重写fputc()是 printf()重定向的核心原理,适用于 STM32 等无终端系统。
那什么是fputc()?
int fputc(int ch, FILE *f);
fputc() 是 C 标准库中的一个字符输出函数,它将单个字符 ch 写入文件流 f,例如:
fputc('A', stdout); // 向标准输出写入 'A'
三、printf() 和 fputc() 的关系
printf() 的调用路径:
printf("ABC");
//内部调用路径
-> printf("ABC");
-> vfprintf(stdout, "ABC", ...);
-> fputc('A', stdout);
-> fputc('B', stdout);
-> fputc('C', stdout);
printf() 是一个标准库函数,它本身不负责输出字符!
-
printf() 不关心输出设备,只负责“产生字符”
-
具体往哪里输出?交给了 fputc()(字符级输出函数)
printf() 的作用是:
-
解析格式字符串(如 %d, %s )
-
把参数格式化成字符串
-
将这些字符逐个输出
-
每一个字符,最终都会通过 fputc() 或 _write() 输出(由编译器决定)
在 PC 上:
fputc() 输出默认是终端窗口或控制台。
在嵌入式系统(如 STM32)上:
默认没有终端窗口,我们通常需要:把 fputc() 输出的内容转为串口(UART)输出。
所以我们要 重写 fputc() 函数,将其输出改为发送到 UART。
当我们重写 fputc() 之后,链接器在链接时查找 fputc() 的定义:
-
如果你自己实现了 fputc() ,则用你的版本
-
如果你没有提供,才会用 C 标准库中默认的 fputc()(通常是空实现或弱定义)
大概就是,你接管了 printf() 底层的输出机制,替换了它原本默认调用的输出接口。
四、fputc() 重定向到串口的步骤(基于STM32 )
第一步:写串口发送函数
void uart_send(uint8_t data)
{
USART_SendData(USART1, data);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
第二步:重写 fputc() 函数
#include <stdio.h> // 必须包含
int fputc(int ch, FILE *f)
{
uart_send((uint8_t)ch); // 将字符通过串口发送
return ch; // 返回字符值表示成功
}
//有些库需要 __attribute__((weak)) 或声明为 extern
//具体取决于你使用的编译器(Keil、GCC、IAR)是否允许重载标准 I/O 函数。
五、完整示例(基于Keil MDK 标准库)
#include "stm32f4xx.h"
#include <stdio.h>
void uart_send(uint8_t data)
{
USART_SendData(USART1, data);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
int fputc(int ch, FILE *f)
{
uart_send((uint8_t)ch);
return ch;
}
int main(void)
{
uart_init(); // 此处不详述,一般包含GPIO初始化,USART初始化,NVIC初始化
printf("Hello UART!\r\n"); // 会通过 uart_send() 打印
while (1);
}
六、补充 FILE *f 参数
-
在 fputc 中这个参数通常是 stdout 。
-
在重定向中我们一般忽略 f,除非你想同时支持多个输出通道(比如串口 + LCD)
七、其他重定向方式(高级)
| 编译器 | 方式 | 示例 |
|---|---|---|
| GCC | 重写 _write() |
用于 newlib |
| Keil | 重写 fputc() |
最常见 |
| IAR | 重写 __write() |
类似 GCC |
重定向就到这里啦!
更多推荐


所有评论(0)