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

  • 文件操作功能有限

相关推荐
周周记笔记5 小时前
GD32F450xx MCU Datasheet 解读:硬件测试工程师的测试方法论
单片机·嵌入式硬件
潘潘的嵌入式日记6 小时前
I²C 从机接收总被覆盖?双缓冲要在 STOP 时交接
c语言·开发语言·单片机
AOI小白新手上路8 小时前
江科协51单片机16-1 AD/DA ADC 三通道综合显示(LCD1602 版)改造说明
单片机·嵌入式硬件·51单片机
HUI-4748 小时前
EG1135|SSOP‑16 同步整流降压控制器,大功率外置 MOS 降压优选
单片机·嵌入式硬件·硬件工程
单片机仿真设计9 小时前
【proteus仿真】基于 STM32 单片机恒温箱控制系统设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
国科安芯9 小时前
星载CAN总线通信网络中抗辐射MCU的通信可靠性设计分析
网络·人工智能·分布式·单片机·嵌入式硬件·架构
新晨单片机设计11 小时前
S003A-基于STM32单片机温度计(数码管显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·stm32单片机功能定制
一条破秋裤11 小时前
TIM 输入捕获与 PWMI:从边沿到频率、占空比
笔记·stm32·学习
AOI小白新手上路11 小时前
江科协51单片机16-1 DA数模转换实验(PWM 呼吸灯)
单片机·嵌入式硬件·51单片机
hongmai66688812 小时前
告别Wi-Fi,专注Mesh:ESP32-H2-MINI-1U-H2S模组规格与应用
单片机·嵌入式硬件·物联网·5g·h.265