STM32printf重定向到串口含armcc和gcc两种方案

news2025/5/10 0:49:29

STM32串口重定向:MDK与GCC环境下需重写的函数差异

在嵌入式开发中,尤其是使用 STM32系列微控制器 的项目中,调试信息的输出是不可或缺的一部分。为了方便调试,开发者通常会选择将 printf 等标准输出函数通过 UART 串口发送到 PC 端进行查看和分析。

然而,在不同的编译器环境中(如 MDK(Keil)GCC),实现标准输出函数重定向的方式存在差异。本文将详细介绍如何在这两种环境下完成串口重定向,并指出它们之间需要重写的函数区别。


✅ 一、重定向的基本原理

无论是在 MDK 还是 GCC 编译环境下,串口重定向的核心思想都是通过重写底层的字符输出函数,使得标准库中的 printf 系列函数能够通过串口发送数据。

标准 C 库中的 printf 函数最终会调用底层的字符输出函数,而不同编译器对这些底层函数的命名和接口定义略有不同。因此,开发者需要根据所使用的编译器环境,选择并实现对应的函数。


🛠️ 二、在不同编译器下的实现方法

1. Keil MDK 环境(ARMCC / AC6)

Keil MDK 中,标准输入输出函数依赖于 ARM 自带的 C 标准库。要重定向 printf,需要重写 _sys_write() 或者更常用的 fputc() 函数。

// Keil MDK 下的标准重定向函数
int __io_putchar(int ch)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

或者使用传统的:

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

⚠️ 注意:如果使用的是 ARM Compiler 6(即基于 LLVM 的编译器),建议优先使用 __io_putchar()


2. GCC 编译器环境(适用于 STM32CubeIDE、Makefile + arm-none-eabi-gcc)

在 GCC 环境下,标准输出函数依赖于新lib库(newlib-nano)。此时需要实现 _write() 函数来捕捉 write() 调用,从而完成串口输出。

// GCC 下的重定向函数
int _write(int fd, char *ptr, int len)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);
    return len;
}

该函数接收文件描述符 fd(通常我们忽略它)、指向字符串的指针 ptr,以及长度 len,然后将整个缓冲区通过串口发送出去。


🔁 三、统一方式:使用宏定义简化适配

为了兼容不同编译器,可以使用预处理器宏定义统一代码风格,避免重复编写两个版本。

// 通用重定向头文件或代码段
#ifdef __GNUC__
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

// GCC 特定部分
#ifdef __GNUC__
int _write(int fd, char *ptr, int len)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);
    return len;
}
#endif

这样处理后,只需切换编译器即可自动适配对应函数,提高代码复用性和可维护性。


💡 四、注意事项

  • 串口句柄:确保 &huart1 已被正确初始化并在全局作用域中可用。
  • 阻塞问题HAL_UART_Transmit() 是阻塞函数,若用于中断上下文或实时性强的场景,请改用非阻塞方式(如DMA或中断发送)。
  • 性能优化:频繁调用 printf() 可能影响性能,建议仅用于调试阶段。
  • 重定向范围:除了输出,还可以重定向输入(如 scanf),但需重写对应的 _read()fgetc()

📌 五、总结

编译器需重写的函数函数原型
MDK(Keil)fputc / __io_putcharint fputc(int ch, FILE *f) / int __io_putchar(int ch)
GCC_writeint _write(int fd, char *ptr, int len)

通过以上方式,我们可以灵活地在 STM32 开发中实现串口重定向,为调试提供极大的便利。


📚 参考资料

  • CSDN 博客 - 原文链接
  • ST官方 HAL 库文档
  • GCC 新版标准库(newlib-nano)说明文档

📢 如您发现任何错误或有改进建议,欢迎留言交流!


版权声明:本文为原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请注明出处并保留原文链接。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2371913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为了摸鱼和吃瓜,我开发了一个网站

平时上班真的比较累,摸鱼和吃瓜还要跳转多个平台的话,就累上加累了。 所以做了一个聚合了全网主流平台热搜的网站。 目前市面上确实有很多这种网站了,所以目前最主要有两点和他们不同: 给热搜列表增加了配图,刷的时候…

Webug4.0靶场通关笔记11- 第15关任意文件下载与第16关MySQL配置文件下载

目录 一、文件下载 二、第15关 任意文件下载 1.打开靶场 2.源码分析 3.渗透实战 三、第16关 MySQL配置文件下载 1.打开靶场 2.源码分析 3.渗透实战 (1)Windows系统 (2)Linux系统 四、渗透防御 一、文件下载 本文通过…

k8s监控方案实践(一):部署Prometheus与Node Exporter

k8s监控方案实践(一):部署Prometheus与Node Exporter 文章目录 k8s监控方案实践(一):部署Prometheus与Node Exporter一、Prometheus简介二、PrometheusNode Exporter实战部署1. 创建Namespace(p…

具身系列——比较3种vpg算法方式玩CartPole游戏(强化学习)

文档1方式参考:https://gitee.com/chencib/ailib/blob/master/rl/vpg_baseline_cartpole.py 文档2方式参考:https://gitee.com/chencib/ailib/blob/master/rl/vpg_batchupdate_cartpole.py 文档3方式参考:https://gitee.com/chencib/ailib/bl…

面向未来的 TCP 协议设计:可扩展与兼容并存

目录 1.设计思路 (1)完整数据结构(字节布局) 1)字段解释: 2)Flags字段设计(1字节位图) (2)进阶版 Java 解码器实现(示例&#xf…

LSB图像信息隐藏系统(MATLAB)

图像信息隐藏系统 系统概述 图像信息隐藏系统是一个基于MATLAB开发的图像隐写工具,采用自适应LSB(最低有效位)隐写算法,实现了信息在图像中的隐藏与提取功能。系统配备了直观的图形用户界面,支持图像分析、信息隐藏、…

C++GO语言微服务项目之 go语言基础语法

目录 01 变量定义 02 自增语法 03 指针 04 go不支持的语法 05 string 06 定长数组-forrange 07 动态数组追加元素 08 切片截取-copy-make介绍 09 map介绍 10 函数 11 内存逃逸 12 import 13 命令行参数-switch 14 标签与continue-goto-break配合使用 15 枚举cons…

最新字节跳动运维云原生面经分享

继续分享最新的go面经。 今天分享的是组织内部的朋友在字节的go运维工程师岗位的云原生方向的面经,涉及Prometheus、Kubernetes、CI/CD、网络代理、MySQL主从、Redis哨兵、系统调优及基础命令行工具等知识点,问题我都整理在下面了 面经详解 Prometheus …

理解 Elasticsearch 的评分机制和 Explain API

作者:来自 Elastic Kofi Bartlett 深入了解 Elasticsearch 的评分机制并探索 Explain API。 想获得 Elastic 认证吗?查看下一期 Elasticsearch Engineer 培训的时间! Elasticsearch 拥有大量新功能,帮助你为你的使用场景构建最佳…

视频编解码学习三之显示器

整理自:显示器_百度百科,触摸屏_百度百科,百度安全验证 分为阴极射线管显示器(CRT),等离子显示器PDP,液晶显示器LCD 液晶显示器的组成。一般来说,液晶显示器由以下几个部分组成: […

K8s网络从0到1

K8s网络从0到1 前言 K8s是一个强大的平台,但它的网络比较复杂,涉及很多概念,例如Pod网络,Service网络,Cluster IPs,NodePort,LoadBalancer和Ingress等等。为了帮助大家理解,模仿TC…

13.Excel:分列

一 分列的作用 将一个单元格中的内容拆分到两个或多个单元格当中。 二 如何使用 1.常规分列使用 注意:分列功能一次只能拆分一列。 长度一致或者数据间有分隔符。 补充:快速选择一列。 CTRL shift 向下箭头。 补充:中英文逗号不同。 可以先通…

计算机网络应用层(5)-- P2P文件分发视频流和内容分发网

💓个人主页:mooridy 💓专栏地址:《计算机网络:自顶向下方法》 大纲式阅读笔记_mooridy的博客-CSDN博客 💓本博客内容为《计算机网络:自顶向下方法》第二章应用层第五、六节知识梳理 关注我&…

Gin优雅关闭 graceful-shutdown

文章目录 优雅关闭示例 - Close 方法项目结构使用方法代码如下代码说明如果去掉代码中的数字1,会发生什么 优雅关闭示例项目结构使用方法使用上下文通知不使用上下文通知 代码 notify-without-context-server.go代码说明 代码 notify-with-context-server.go代码说明…

五子棋html

<!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8" /> <meta name"viewport" content"widthdevice-width, initial-scale1" /> <title>五子棋游戏</title> <style>bo…

JavaWeb:后端web基础(TomcatServletHTTP)

一、今日内容 二、Tomcat 介绍与使用 介绍 基本使用 小结 配置 配置 查找进程 三、Servlet 什么是Servlet 快速入门 需求 步骤 1.新建工程-模块&#xff08;Maven&#xff09; 2.修改打包方式-war 3.编写代码 /*** 可以选择继承HttpServlet*/ WebServlet("/hello&q…

缓存(1):三级缓存

三级缓存是指什么 我们常说的三级缓存如下&#xff1a; CPU三级缓存Spring三级缓存应用架构&#xff08;JVM、分布式缓存、db&#xff09;三级缓存 CPU 基本概念 CPU 的访问速度每 18 个月就会翻 倍&#xff0c;相当于每年增⻓ 60% 左右&#xff0c;内存的速度当然也会不断…

Cursor —— AI编辑器 使用详解

Cursor - The AI Code Editor 一、Cursor 是什么&#xff1f; Cursor 是一款优秀的AI代码编辑器&#xff0c;它内置了 Deepseek-R1、GPT-4、Claude等 AI 模型。 简单说&#xff0c;就是&#xff1a;Cursor VS Code 编辑器 AI 大模型 Cursor 功能特性&#xff08;代码补全、…

Pytorch-CUDA版本环境配置

Pytorch-CUDA版本环境配置 电脑如果是Windows平台下的Nvidia GPU的用户&#xff0c;需配置Pytorch的CUDA版本&#xff0c;分为三步&#xff1a; 1. 安装或更新NVIDA显卡驱动 官方驱动下载地址&#xff1a; https://www.nvidia.cn/Download/index.aspx?langcn 2. 安装CUDA Too…

OpenCV 图形API(77)图像与通道拼接函数-----对图像进行几何变换函数remap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 对图像应用一个通用的几何变换。 函数 remap 使用指定的映射对源图像进行变换&#xff1a; dst ( x , y ) src ( m a p x ( x , y ) , m a p y…