【杂谈】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函数可能缺失或不完整

  • 文件操作功能有限

相关推荐
UTP协同自动化测试6 小时前
物联网模组测试难点 |APP指令下发+UART 响应+GPIO 电平变化,如何一次性验证?
功能测试·嵌入式硬件·物联网·模块测试
yoyobravery7 小时前
蓝桥杯第15届单片机满分
单片机·职场和发展·蓝桥杯
4caf19 小时前
作业2:6位数码管静态显示
嵌入式硬件·51单片机
不做无法实现的梦~9 小时前
STM32解析PPM协议
stm32·单片机·嵌入式硬件
czhaii10 小时前
基于Arm Cortex-M7内核GD32H7
单片机·嵌入式硬件
番茄灭世神10 小时前
MCU开发常见软件BUG总结(持续更新)
c语言·stm32·单片机·嵌入式·gd32
wanghanjiett10 小时前
双轮平衡车建模及控制 2 PID控制原理与调参
嵌入式硬件·控制算法
EVERSPIN11 小时前
SQPI PSRAM为单片机提供RAM扩展方案
单片机·嵌入式硬件·psram·sqpi psram
Ar-Sr-Na11 小时前
STM32现代化AI开发指南-VSCode环境配置(macOS)
c语言·人工智能·vscode·stm32·嵌入式硬件·硬件工程
进击的小头11 小时前
第6篇:嵌入式芯片算力核心来源:多级流水线架构与指令并行机制详解
单片机·嵌入式硬件·架构