小知识:STM32 printf 重定向(串口输出)--让数据 “开口说话” 的关键技巧

news2025/6/3 19:42:22

引言

在 C 语言开发中,printf函数是我们调试程序、输出数据的得力助手,它能将格式化的数据输出到标准输出设备(通常是屏幕)。然而,在嵌入式领域,STM32 单片机并没有默认的显示设备,要让printf函数正常工作,就需要我们手动为它 “指定” 输出方向 —— 这就是重定向技术。通过重定向fputc函数,我们可以让 STM32 通过串口将数据输出到 PC 端或其他设备,实现实时调试与数据交互。本文将详细介绍如何在 STM32 上实现printf重定向到串口,让你的代码 “开口说话”。

一、重定向的核心概念

什么是重定向?

重定向的本质是修改标准库函数的输出目标。在 C 语言中,printf函数会调用fputc函数来完成实际的字符输出操作,而fputc默认指向的输出设备(如终端屏幕)在嵌入式系统中并不存在。因此,我们需要重新实现fputc函数,将字符输出的目标指向 STM32 的串口寄存器或 HAL 库的串口发送函数,这一过程就称为重定向

为什么需要重定向?

  • 无默认输出设备:STM32 本身没有显示屏,无法直接显示printf的输出内容。

  • 调试需求:通过串口将数据输出到 PC 端的串口调试助手,是嵌入式开发中最常用的调试手段之一。

  • 灵活扩展:除了串口,重定向技术还可将输出指向 LCD、OLED 等其他设备,但串口是最基础、最常用的场景。

二、标准库与 HAL 库的重定向实现

(一)标准库实现(以 USART1 为例)

代码实现
#include "stdio.h"
#include "stm32f10x.h"
​
// 重定向fputc函数到USART1
int fputc(int c, FILE* stream) {
    // 等待串口发送缓冲区为空(TC标志位为1)
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    // 将字符写入串口发送数据寄存器
    USART_SendData(USART1, (uint8_t)c);
    return c;
}
关键步骤解析
  1. 包含头文件:需要包含stdio.h以使用标准库函数。

  2. 等待发送完成USART_GetFlagStatus(USART1, USART_FLAG_TC)用于检测串口发送缓冲区是否为空。只有当TC标志位为 1 时,才能发送下一个字符,避免数据丢失。

  3. 发送字符:通过USART_SendData将字符写入串口的发送数据寄存器(DR),由硬件完成实际的串口发送过程。

使用注意事项
  • 串口初始化:在使用printf前,需先初始化 USART1(配置波特率、数据位、停止位等)。

  • MicroLIB 支持

    :在 Keil MDK 中,需勾选

    Target -> Use MicroLIB

    否则可能因标准库依赖问题导致编译错误。

(二)HAL 库实现(以 huart1 为例)

代码实现
#include "stdio.h"
#include "stm32f10x_hal.h"
​
UART_HandleTypeDef huart1; // 假设已在CubeMX中配置好huart1
​
int fputc(int c, FILE *f) {
    // 使用HAL库函数发送单个字符(阻塞模式)
    HAL_UART_Transmit(&huart1, (uint8_t *)&c, 1, 0xFFFF);
    return c;
}
关键步骤解析
  1. HAL 库函数调用HAL_UART_Transmit是 HAL 库提供的串口发送函数,参数包括串口句柄、发送数据指针、数据长度和超时时间。

  2. 阻塞模式发送:最后一个参数0xFFFF表示超时时间较长,确保发送成功。在非阻塞模式下,需结合中断或 DMA 使用,但重定向场景中阻塞模式更简单直接。

使用注意事项
  • CubeMX 配置:建议通过 CubeMX 工具初始化串口,生成huart1的配置代码(包括时钟、引脚、波特率等)。

  • 头文件包含:需包含stm32f10x_hal.h以使用 HAL 库函数。

三、重定向的调试应用场景

1. 实时数据监控

通过printf输出传感器采集的数据(如温度、电压等),在 PC 端串口调试助手中实时显示,方便观察数据变化趋势。

float temp = get_temperature(); // 假设获取温度的函数
printf("Current temperature: %.2f ℃\n", temp);

2. 程序流程跟踪

在代码中插入printf语句,输出关键变量或函数执行状态,快速定位程序运行中的问题。

void key_processing(void) {
    printf("Key pressed: %d\n", key_value); // 输出按键值
    // 处理按键逻辑
}

3. 命令交互

结合串口接收功能,实现简单的命令行交互界面,通过printf返回命令执行结果。

if (cmd == "version") {
    printf("System version: V1.0.0\n");
}

四、常见问题与解决方案

1. 输出乱码

  • 原因:串口波特率、数据位、停止位等参数与调试助手不一致。

  • 解决:确保 STM32 的串口配置与调试助手设置完全一致(如波特率 115200、8 位数据位、1 位停止位、无校验)。

2. 程序编译错误(未定义FILE类型)

  • 原因:未包含stdio.h头文件,或未启用 MicroLIB。

  • 解决:添加#include "stdio.h",并在 Keil 中勾选Use MicroLIB

3. 输出延迟或卡顿

  • 原因:串口发送缓冲区已满,后续字符被阻塞。

  • 解决:确保fputc函数中正确等待发送完成标志(如USART_FLAG_TC),或改用 DMA 方式发送以提高效率。

五、总结

通过重定向fputc函数,我们赋予了 STM32 使用printf函数的能力,使其能够通过串口与外界进行数据交互。无论是标准库还是 HAL 库,核心思路都是将字符输出指向串口的发送函数,并处理好发送过程中的同步问题。这一技巧不仅是调试的利器,也是实现设备监控、交互功能的基础。

六、最后

作为技术分享者,我一直致力于用清晰易懂的语言和详细的代码示例,帮助大家深入理解技术知识。但由于技术的复杂性和个人知识的局限性,文中可能存在不足或疏漏之处。非常期待大家在评论区提出宝贵意见和建议,无论是对内容的疑问,还是对代码优化的想法,都欢迎分享。让我们携手在技术学习的道路上不断探索、共同进步!

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

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

相关文章

【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“

欢迎来到一整颗红豆的博客✨,一个关于探索技术的角落,记录学习的点滴📖,分享实用的技巧🛠️,偶尔还有一些奇思妙想💡 本文由一整颗红豆原创✍️,感谢支持❤️!请尊重原创…

SCSAI平台面向对象建模技术的设计与实现

一、核心设计思想 SCSAI平台的核心目标是通过元建模(Meta-Modeling)技术实现面向对象建模的零编码化。其核心思想为: 自反性设计:定义ObjectClassInfo (OCI)为元类(Meta-Class),所有对象类均为…

pikachu通关教程-CSRF

CSRF(get) 用bp进行抓包 选择action value值的修改 点击test in browser copy然后放在bp代理的浏览器上,会出现一个提交按钮,这时候点击之后信息就被修改了。 CSRF(post) 请求的方式不同,其他都是一样 CSRF Token 存在cookie 首先要先下载一…

智能体觉醒:AI开始自己“动手”了-自主进化开启任务革命时代

1. 智能体:AI从“工具”到“伙伴”的关键跃迁 1.1 什么是智能体? 智能体(Agent)是AI的“进化版”——它不再局限于生成文字或图像,而是能像人类一样“规划任务”“调用工具”甚至“协同合作”。例如,一个…

【C++指南】C++ list容器完全解读(二):list模拟实现,底层架构揭秘

. 💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 文章目录 引言一、链表节点设计:双向链表的基石1.1 节点类的实现 二、list框架与核心成员函…

[神经网络]使用olivettiface数据集进行训练并优化,观察对比loss结果

结合归一化和正则化来优化网络模型结构,观察对比loss结果 搭建的神经网络,使用olivettiface数据集进行训练,结合归一化和正则化来优化网络模型结构,观察对比loss结果 from sklearn.datasets import fetch_olivetti_faces #倒入数…

华院计算出席信创论坛,分享AI教育创新实践并与燧原科技共同推出教育一体机

5月21日,信创论坛于上海漕河泾会议中心举办。本次论坛以“聚力融合,繁荣生态”为主题,话题聚焦工业制造、交通运输、金融、教育、医疗等领域。华院计算技术(上海)股份有限公司(以下简称“华院计算”&#x…

华为OD机试真题——会议接待 /代表团坐车(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《会议…

LabVIEW Val (Sgnl) 属性

在 LabVIEW 事件驱动架构中,Val (Sgnl) 属性(Value (Signaling))是实现编程触发与用户交互行为一致性的关键技术。与普通 Value 属性不同,Val (Sgnl) 在修改控件值的同时强制生成值改变事件,确保程序逻辑与 UI 交互保持…

STM32G4 电机外设篇(三) TIM1 发波 和 ADC COMP DAC级联

目录 一、STM32G4 电机外设篇(三) TIM1 发波 和 ADC COMP DAC级联1 TIM1 高级定时器发波1.1 stm32cubemx配置 2 TIM1 ADC COMP DAC级联2.1 stm32cubemx配置 附学习参考网址欢迎大家有问题评论交流 (* ^ ω ^) 一、STM32G4 电机外设篇(三&…

DAY 35 超大力王爱学Python

知识点回顾: 三种不同的模型可视化方法:推荐torchinfo打印summary权重分布可视化进度条功能:手动和自动写法,让打印结果更加美观推理的写法:评估模式 作业:调整模型定义时的超参数,对比下效果。…

【数据结构】图的存储(十字链表)

弧节点 tailvex数据域:存储弧尾一端顶点在顺序表中的位置下标;headvex 数据域:存储弧头一端顶点在顺序表中的位置下标;hlink 指针域:指向下一个以当前顶点作为弧头的弧;tlink 指针域:指向下一个…

Redis最佳实践——秒杀系统设计详解

基于Redis的高并发秒杀系统设计(十万级QPS) 一、秒杀系统核心挑战 瞬时流量洪峰:100万 QPS请求冲击库存超卖风险:精准扣减防止超卖系统高可用性:99.99%服务可用性要求数据强一致性:库存/订单/支付状态同步…

STM32软件spi和硬件spi

核心观点 本文主要介绍了SPI通信的两种实现方式:软件SPI和硬件SPI。详细阐述了SPI通信协议的基本概念、硬件电路连接方式、移位示意图、时序基本单元以及四种工作模式。同时,对W25Q64模块进行了详细介绍,包括其硬件电路、框图以及操作注意事…

深度刨析树结构(从入门到入土讲解AVL树及红黑树的奥秘)

目录 树的表示 二叉树的概念及结构(重点学习) 概念 : 特点: 树与非树 特殊的二叉树 二叉树的性质(重点) 二叉树的存储结构 堆的概念及结构 建堆方式: 向下调整算法 向上调整算法 建堆第一步初始化 建…

【Linux】shell的条件判断

目录 一.使用逻辑运算符判定命令执行结果 二.条件判断方法 三.判断表达式 3.1文件判断表达式 3.2字符串测试表达式 3.3整数测试表达式 3.4逻辑操作符 一.使用逻辑运算符判定命令执行结果 && 在命令执行后如果没有任何报错时会执行符号后面的动作|| 在命令执行后…

第九天:java注解

注解 1 什么是注解(Annotation) public class Test01 extends Object{//Override重写的注解Overridepublic String toString() {return "Test01{}";} }2 内置注解 2.1 Override Override重写的注解 Override public String toString() {ret…

十一、【核心功能篇】测试用例管理:设计用例新增编辑界面

【核心功能篇】测试用例管理:设计用例新增&编辑界面 前言准备工作第一步:创建测试用例相关的 API 服务 (src/api/testcase.ts)第二步:创建测试用例编辑页面组件 (src/views/testcase/TestCaseEditView.vue)第三步:配置测试用例…

Spring是如何实现属性占位符解析

Spring属性占位符解析 核心实现思路1️⃣ 定义占位符处理器类2️⃣ 处理 BeanDefinition 中的属性3️⃣ 替换具体的占位符4️⃣ 加载配置文件5️⃣ Getter / Setter 方法 源码见:mini-spring 在使用 Spring 框架开发过程中,为了实现配置的灵活性&#xf…

DDR4读写压力测试

1.1测试环境 1.1.1整体环境介绍 板卡: pcie-403板卡 主控芯片: Xilinx xcvu13p-fhgb2104-2 调试软件: Vivado 2018.3 代码环境: Vscode utf-8 测试工程: pcie403_user_top 1.1.2硬件介绍 UD PCIe-403…