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

  • 文件操作功能有限

相关推荐
全栈游侠34 分钟前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_36 分钟前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技3 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计3 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦4 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习
小龙报4 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
范纹杉想快点毕业4 小时前
嵌入式与单片机开发核心学习指南——从思维转变到第一性原理的深度实践
单片机·嵌入式硬件
Industio_触觉智能4 小时前
瑞芯微RK3566开发板规格书,详细参数配置,型号EVB3566-V1,基于RK3566核心板SOM3566邮票孔封装
嵌入式硬件·开发板·rk3568·rk3566·核心板·瑞芯微
czwxkn5 小时前
4STM32(stdl)TIM定时器
stm32·单片机·嵌入式硬件
Love Song残响5 小时前
NVIDIA显卡终极优化指南
stm32·单片机·嵌入式硬件