发布时间:2026/8/31 16:05:19
STM32多串口动态printf重定向:1个fputc函数支持USART1/2/3切换 STM32多串口动态printf重定向1个fputc函数支持USART1/2/3切换在嵌入式开发中串口调试是最常用的调试手段之一。而printf作为C语言中最常用的输出函数如果能将其重定向到串口将极大提升调试效率。但对于需要同时调试多个外设或进行多设备通信的场景传统的单一串口重定向方案就显得力不从心了。本文将介绍一种创新的动态切换方案通过改造fputc函数实现运行时动态切换printf的输出目标串口如USART1、USART2、USART3。这种方法不仅代码简洁而且资源占用少非常适合中高级STM32开发者。1. 传统printf重定向的局限性在STM32开发中printf重定向到串口通常通过重写fputc函数实现。典型的实现方式如下int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); return ch; }这种方法虽然简单但存在明显不足固定输出串口一旦编译完成printf输出目标就被锁定在特定串口如USART1多串口需求当项目需要同时与多个设备通信时不得不为每个串口单独实现发送函数代码冗余多个发送函数导致代码膨胀维护困难2. 动态切换方案设计原理我们的解决方案核心在于引入一个当前串口的概念通过修改这个变量来动态切换printf的输出目标。具体实现需要以下关键组件全局指针变量存储当前使用的串口外设指针切换函数用于修改当前串口设置改造后的fputc根据当前串口设置选择输出目标2.1 数据结构定义首先在头文件中定义必要的枚举和变量// usart.h typedef enum { USART_NONE, USART1_IDX, USART2_IDX, USART3_IDX } Current_USART_Index; extern USART_TypeDef* Current_USART; // 当前使用的USART外设指针 extern Current_USART_Index Current_USART_Printf_Index; // 当前USART索引 void Set_Current_USART(Current_USART_Index index); // 设置当前USART函数声明2.2 核心实现代码在源文件中实现具体功能// usart.c USART_TypeDef* Current_USART NULL; Current_USART_Index Current_USART_Printf_Index USART_NONE; void Set_Current_USART(Current_USART_Index index) { switch(index) { case USART1_IDX: Current_USART USART1; Current_USART_Printf_Index USART1_IDX; break; case USART2_IDX: Current_USART USART2; Current_USART_Printf_Index USART2_IDX; break; case USART3_IDX: Current_USART USART3; Current_USART_Printf_Index USART3_IDX; break; default: Current_USART NULL; Current_USART_Printf_Index USART_NONE; } } int fputc(int ch, FILE *f) { if(Current_USART NULL) return EOF; // 等待发送完成 while((Current_USART-SR USART_SR_TXE) 0); // 发送数据 Current_USART-DR (uint8_t)ch; return ch; }3. 方案优势与性能对比与传统的多串口实现方案相比本方法具有显著优势对比项传统方案动态切换方案代码量多少内存占用高低切换灵活性差好维护难度高低执行效率相当相当性能说明执行时间与传统方案几乎相同仅增加一次指针判断内存占用仅增加两个全局变量指针和枚举代码复用所有串口共用同一套发送逻辑4. 完整工程示例下面提供一个基于STM32标准外设库的完整示例4.1 硬件初始化首先初始化需要用到的串口void USART_Init(USART_TypeDef* USARTx, uint32_t baudrate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; if(USARTx USART1) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; // TX GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; // RX GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); } // 类似地初始化USART2和USART3... USART_InitStructure.USART_BaudRate baudrate; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USARTx, USART_InitStructure); USART_Cmd(USARTx, ENABLE); }4.2 主函数示例int main(void) { // 硬件初始化 SystemInit(); USART_Init(USART1, 115200); USART_Init(USART2, 115200); USART_Init(USART3, 115200); // 启用MicroLIB #pragma import(__use_no_semihosting) // 初始输出到USART1 Set_Current_USART(USART1_IDX); printf(System Startup...\r\n); while(1) { // 切换到USART1输出 Set_Current_USART(USART1_IDX); printf(This message goes to USART1\r\n); // 切换到USART2输出 Set_Current_USART(USART2_IDX); printf(This message goes to USART2\r\n); // 切换到USART3输出 Set_Current_USART(USART3_IDX); printf(This message goes to USART3\r\n); Delay_ms(1000); } }5. 进阶优化与注意事项5.1 线程安全改进在多任务环境下需要考虑串口切换的原子性。可以增加互斥锁机制// 添加互斥锁变量 __IO uint32_t USART_Mutex 0; // 修改Set_Current_USART函数 void Set_Current_USART(Current_USART_Index index) { while(__sync_lock_test_and_set(USART_Mutex, 1)); // 自旋锁 // 原有切换逻辑... __sync_lock_release(USART_Mutex); // 释放锁 }5.2 性能优化技巧缓冲发送可以结合DMA实现批量发送减少CPU占用条件编译根据实际使用的串口数量进行条件编译节省代码空间寄存器优化直接操作寄存器可以进一步提升效率5.3 常见问题排查问题1printf无输出检查MicroLIB是否启用确认串口初始化正确验证Set_Current_USART是否被正确调用问题2输出乱码检查波特率设置确认时钟配置正确验证硬件连接是否可靠问题3程序卡在fputc检查串口发送完成标志确认串口使能检查硬件流控制设置6. 扩展应用场景这种动态切换方案不仅适用于调试还可应用于多设备通信同时与多个传感器、模块通信冗余设计重要信息通过多个通道发送日志分级不同级别日志输出到不同串口固件升级通过不同接口进行升级在实际项目中我曾将这套方案应用于工业控制器开发通过USART1连接HMIUSART2连接PLCUSART3输出调试信息极大提升了开发效率和系统可靠性。

相关新闻

2026/8/31 8:07:10

AI巨头技术动向解析:Anthropic J-lens、腾讯Hy3与NVIDIA初创计划

这次我们来关注AI领域的最新动态,特别是围绕Anthropic、腾讯、NVIDIA和微软这几家巨头的重大变化。从技术角度看,这些变化不仅影响投资格局,更直接关系到开发者的工具选择、部署方案和未来技术路线。最近的热点包括Anthropic推出的"J-le…

2026/8/30 23:57:31

AI智能体技术解析:从核心原理到实战开发与合规应对

最近在AI开发圈里,不少同行都在关注一个重要动态:字节跳动的豆包和阿里巴巴的通义千问相继宣布,将于2026年7月15日正式下线其智能体功能。这个时间点恰好与《人工智能拟人化互动服务管理暂行办法》正式施行之日重合,引发了业界对A…

2026/8/31 16:04:01

中文排版神器:横排文本转竖排PDF方案

软件介绍 这款由吾爱论坛makent原创开发的文本格式转换工具,专注于将TXT文件快速生成竖排PDF文档。 它突破常规排版限制,通过智能处理技术,将横排简体中文文本自动转换为竖排繁体格式,同时内置封面模板,为用户打造…

2026/8/31 16:04:01

网易有道测开笔试全复盘:能力模型、题型解析与备考要点

想进大厂做测开的同学,网易校招笔试基本是绕不开的一关。尤其是网易有道的测开岗位,题目风格和互联网公司里常见的“八股文算法测试设计”组合不太一样,更看重实际工程经验和场景拆解能力。我去年参加过2023校招有道的正式第二批笔试&#xf…

2026/8/31 16:04:01

Java电影院购票系统从零搭建:核心逻辑与代码实现

简介:这是一套基于SpringBoot开发的电影院购票系统完整源码,面向计算机、电子信息工程等专业学生,适用于毕业设计、课程设计及期末大作业等实践场景。系统采用B/S架构与MVC模式,整合Java、MySQL、MyBatis、Vue、Ajax等主流技术栈&…

2026/8/31 16:04:01

办公必备!支持Word/Excel的批量打印解决方案

软件介绍 文档批量打印工具「电脑」是一款专为Windows系统打造的轻量级办公辅助工具,专注于解决多文档快速打印难题。它支持批量处理Word、Excel、WPS等格式的文档和表格,集成双面打印、黑白模式等实用功能,帮助用户大幅提升办公效率。 极…

2026/8/31 16:04:01

克劳德核心词汇:提示词工程与Claude Code实战指南

“Show HN:克劳德的核心词汇”,名字听起来像是个提示词收藏夹,但实际上它更接近一份“Claude 使用频率最高的关键词清单 提示词工程模板”。这类项目在 Hacker News 上出现,通常不是为了介绍模型本身,而是帮你解决一个…

2026/8/31 15:59:00

Delphi 12.3 Athens中DISQLite3嵌入式SQLite数据库实战

简介:本资源是面向Delphi中高级开发者的一套SQLite数据库集成控件解决方案,专为适配Delphi 11至12 Athens版本(含12.3)设计,解决原生数据库组件在轻量级嵌入式场景下性能与部署灵活性不足的问题。压缩包共169个文件&am…

2026/8/31 1:05:20

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/31 2:14:20

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/31 1:41:28

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/8/31 0:07:32

STM32C5设备支持包(IAR DFP)安装指南与常见坑

上一阵子在IAR里折腾一块基于STM32C5系列的新板子,工程从STM32CubeMX导出来之后怎么都编译不过。报错信息很干脆:找不到设备描述文件。跟着错误路径去查,发现指向的是一个让我愣了一下的名字:STMicroelectronics.stm32c5xx.2.1.0.…

2026/8/31 0:07:32

STM32N657 SWO引脚矛盾:CubeMX显示PB3,数据手册为PB5

拿到STM32N657这颗料的第一天,我就撞上了一个让人原地懵圈的引脚矛盾:CubeMX里清清楚楚显示SWO在PB3,翻开数据手册的引脚说明表,却赫然写着PB5。对于一个靠SWO输出调试日志吃饭的人而言,这种"工具和手册打架"…

2026/8/31 12:44:45

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/31 9:19:59

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/31 6:53:02

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…