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

  • 文件操作功能有限

相关推荐
码农三叔2 小时前
(7-3-01)电机与执行器系统:驱动器开发与控制接口(1)电机驱动电路+编码器与反馈
人工智能·单片机·嵌入式硬件·架构·机器人·人形机器人
YONYON-R&D3 小时前
USB电容麦 方案
嵌入式硬件
三佛科技-134163842123 小时前
HN3401_P沟道-30V -4.2A场效应管MOSFET应用场景分析
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
三佛科技-187366133973 小时前
宠物泡泡机方案开发,宠物洗澡打泡机方案
单片机·嵌入式硬件
方芯半导体4 小时前
EtherCAT从站控制器芯片(FCE1353)与MCU(STM32H743)功能板解析!
xml·stm32·单片机·嵌入式硬件·物联网·自动化
上海合宙LuatOS4 小时前
LuatOS socket基础知识和应用开发
开发语言·人工智能·单片机·嵌入式硬件·物联网·开源·php
松涛和鸣4 小时前
66、SPI驱动ADXL345加速度计
linux·运维·单片机·嵌入式硬件·ubuntu
Hello_Embed4 小时前
libmodbus 源码分析(发送请求篇)
笔记·单片机·嵌入式·freertos·libmodbus
上海合宙LuatOS4 小时前
LuatOS框架的使用(1)
java·开发语言·单片机·嵌入式硬件·物联网·ios·iphone