【杂谈】stm32重定向printf为什么需要勾选MicroLIB

目录

一、什么是重定向?怎么重定向?

二、使用MicroLIB库重定向的优势

[1. 代码体积优化](#1. 代码体积优化)

[2. 重定向机制不同](#2. 重定向机制不同)

[3. 性能优化](#3. 性能优化)

三、注意事项:


一、什么是重定向?怎么重定向?

在C语言中,标准库函数(如printf、scanf、getchar、putchar等)默认使用标准输入输出设备。在桌面环境中,这些通常是键盘和屏幕。但在嵌入式系统中,没有这样的标准设备,因此我们需要将标准输入输出重定向到我们拥有的硬件设备上,比如UART、USB、LCD等。

重定向的过程就是重新实现C标准库中与输入输出相关的底层函数。这些底层函数在标准库中被高级函数(如printf)调用,具体需要重写哪些函数取决于使用的编译器和C库。

以重定向printf为例:重定向printf的核心是重写C标准库的底层I/O函数,让它们输出到硬件接口(如UART)。

复制代码
函数调用链:
printf() → vfprintf() → fputc() / _write() → 硬件接口

不同编译环境的重定向函数各不相同

编译器/库 需要重写的函数 头文件
Keil + MicroLIB fputc() stdio.h
Keil + 标准库 _write() stdio.h
GCC (STM32CubeIDE) _write() unistd.h
IAR __write() stdio.h
复制代码
#include <stdio.h>
#include "stm32f10x.h"  // 根据你的芯片型号调整,这里是STM32F1系列

// 假设你使用的是USART1
// USART初始化代码应该已经在其他地方配置好

// 方法1:重写fputc(最常用)
int fputc(int ch, FILE *f) {
    // 将字符发送到USART1
    USART_SendData(USART1, (uint16_t)ch);
    
    // 等待发送完成(轮询方式)
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    
    // 等待传输完成(可选,确保数据真正发送出去)
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    
    return ch;
}

// 方法2:重写fgetc(用于scanf等输入函数)
int fgetc(FILE *f) {
    // 等待接收到数据
    while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    
    // 读取接收到的数据
    return (int)USART_ReceiveData(USART1);
}

#include <stdio.h>
#include "stm32f10x.h"  // 根据你的芯片型号调整

// 假设已经初始化了USART1和USART2

// 方法1:使用标准FILE指针区分不同串口
int fputc(int ch, FILE *f) {
    // 检查文件指针,确定输出到哪个串口
    if (f == stdout) {
        // 输出到USART1(stdout)
        USART_SendData(USART1, (uint16_t)ch);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    } 
    else if (f == stderr) {
        // 输出到USART2(stderr)
        USART_SendData(USART2, (uint16_t)ch);
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    }
    else {
        // 默认输出到USART1
        USART_SendData(USART1, (uint16_t)ch);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }
    
    return ch;
}

二、使用MicroLIB库重定向的优势

在STM32中使用标准库函数printf时,勾选MicroLIB主要是为了减小代码体积和优化性能,具体原因如下:

1. 代码体积优化

  • MicroLIB是Keil MDK专门为嵌入式系统设计的简化C库,相比标准C库(如newlib-nano)体积更小

  • 标准C库可能占用10-20KB ROM,而MicroLIB通常只需2-5KB

  • 这对于Flash空间有限的STM32芯片(特别是低端型号)非常重要

2. 重定向机制不同

  • MicroLIB使用更简单的重定向机制

    • 只需要重写 fputc()fgetc() 函数

    • 或重写 __stdout__stdin 相关函数

  • 标准库可能需要更复杂的重定向

    • 需要处理更完整的文件描述符

    • 可能需要重写 _write()_read() 等底层系统调用

3. 性能优化

  • MicroLIB针对无操作系统环境优化,去除了许多不必要的功能

  • 没有线程安全锁等复杂机制

  • 标准I/O缓冲区管理更简单

三、注意事项:

  • 不支持浮点数格式化(printf("%f")需要额外设置)

    复制代码
    // 在Keil中需要额外设置
    // Project Options → Target → 勾选"Use MicroLIB"
    // 并在代码中添加:
    #pragma import(__use_no_semihosting)
  • 某些标准C函数可能缺失或不完整

  • 文件操作功能有限

相关推荐
LCG元2 小时前
STM32项目实战:基于STM32F103的智能农业监控系统
stm32·单片机·嵌入式硬件
ACP广源盛139246256732 小时前
IX8024与科学大模型的碰撞@ACP#筑牢科研 AI 算力高速枢纽分享
运维·服务器·网络·数据库·人工智能·嵌入式硬件·电脑
一起搞IT吧3 小时前
Android性能系列专题理论之十:systrace/perfetto相关指标知识点细节含义总结
android·嵌入式硬件·智能手机·性能优化
Truffle7电子4 小时前
STM32CubeIDE/Programmer/Touch GFX 应用
stm32·单片机·嵌入式硬件
constant_LDX5 小时前
步进电机开发(一、硬件设计)
单片机·嵌入式硬件
北山有鸟5 小时前
修改源码法和插件法
嵌入式硬件·学习
richxu202510015 小时前
嵌入式学习之路->stm32篇->(14)通用定时器(上)
stm32·单片机·嵌入式硬件·学习
Deitymoon5 小时前
STM32——串口通信(USART)
单片机·嵌入式硬件
iCxhust5 小时前
微机原理实践教程(C语言篇)---A002流水灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·课程设计·微机原理
Deitymoon7 小时前
STM32——外部中断按键控制led
stm32·单片机·嵌入式硬件