参考学习文章:【STM32系列】多路USART串口Printf重定向详解——通用
最近在学习过程中对串口便捷输出数据有应用需求,原本的实现思路是将串口重定向到printf进行数据输出,但是通常情况下只能重定向到一个串口,后来随着对上述文章的学习,在使用STM32F103C8T6实现了多路USART串口Printf重定向,以达到在多个串口上进行输出,而又不用为每个串口单独封装发送函数。
目录
1.#include "stm32f10x_usart.h"
2.添加了枚举类型,方便用来索引某个串口,用于printf定向
3.增加新的串口句柄和当前串口的索引,分别存储当前使用的USART句柄和串口的索引
1.Current_USART_Handle 和 Current_USART_Printf_Indx的定义(一定要在.c里面定义,否则会报错)
多路USART串口Printf重定向
1.USART.h中要添加和更改的内容
1.#include "stm32f10x_usart.h"
句柄:串口库中存在的固有类型,指明了我们操作的是哪个串口,类型为USART_TypeDef* ,在STM32F103C8T6中有USART1,USART2,USART3
首先在usart.h文件中包含标准库中的串口库 stm32f10x_usart.h(为了使用与之匹配的USART的句柄)
#include "stm32f10x_usart.h"
2.添加了枚举类型,方便用来索引某个串口,用于printf定向
/* 定义USART索引枚举 */
typedef enum {
USART_NONE, /* 无USART */
USART1_IDX, /* USART1索引 */
USART2_IDX, /* USART2索引 */
USART3_IDX, /* USART3索引 */
}Current_USART_Indx;
3.增加新的串口句柄和当前串口的索引,分别存储当前使用的USART句柄和串口的索引
extern USART_TypeDef* Current_USART_Handle; /* 当前某个USART的句柄 */
extern Current_USART_Indx Current_USART_Printf_Indx; /* 当前某个USART的索引 */
4.声明我们即将要用到的函数
void Set_Current_USART(Current_USART_Indx indx); /* 函数声明,用于设置当前使用的USART */
5.上述总共添加的代码
2.USART.c 中要添加和更改的内容
1.Current_USART_Handle
和 Current_USART_Printf_Indx的定义(一定要在.c里面定义,否则会报错)
我们在 serial.h
中使用了 extern
关键字声明了Current_USART_Handle
和 Current_USART_Printf_Indx这
两个变量,这意味着我们告诉编译器这些变量在其他地方定义了,所以我们需要在.c文件中对这两个变量进行定义,初次之外由于我们接下来需要使用我们在.h中定义的枚举类型的句柄,所以在这里我们还需要包含我们的头文件#include "Serial.h"
#include "Serial.h"/* 包含句柄所在的头文件 */
USART_TypeDef* Current_USART_Handle; /* 当前某个USART的句柄 */
Current_USART_Indx Current_USART_Printf_Indx; /* 当前某个USART的索引 */
2.添加Set_Current_USART函数用于设置当前使用的USART。它接受一个Current_USART_Indx
类型的参数,并根据该参数更新Current_USART_Handle
句柄和Current_USART_Printf_Indx
索引
/*
* 简介:设置当前使用的USART
* 参数:indx - 要设置的USART索引
* 这个参数可以是:USARTx_IDX,其中x可以从1~3
* 使用举例:(必须要将其放在printf函数前面,指定其中一个串口)
* Set_Current_USART(USART1_IDX);
* printf("我是串口1\r\n");
*/
void Set_Current_USART(Current_USART_Indx indx)
{
switch(indx)
{
case USART1_IDX:
Current_USART_Handle = USART1;
Current_USART_Printf_Indx = USART1_IDX;
break;
case USART2_IDX:
Current_USART_Handle = USART2;
Current_USART_Printf_Indx = USART2_IDX;
break;
case USART3_IDX:
Current_USART_Handle = USART3;
Current_USART_Printf_Indx = USART3_IDX;
break;
default:
Current_USART_Handle = NULL;
Current_USART_Printf_Indx = USART_NONE;
break;
}
}
3.fputc
函数
fputc
函数是printf
函数输出字符时调用的底层函数,进行了一些改变,使其可以随时自定义重定向到不同串口
/*
* 简介:重定义fputc函数,用于将字符输出到当前设置的USART
* 参数:
* ch - 要发送的字符
* f - 文件指针(在此实现中未使用)
* 返回值:发送的字符(或EOF如果出错)
*/
int fputc(int ch, FILE *f) //printf()函数重定向输出信息到串口
{
if(Current_USART_Handle == NULL){ /* 如果当前没有设置USART句柄,则返回EOF表示错误 */
return EOF;
}
/* 根据当前设置的USART句柄,选择对应的USART外设发送字符 */
if(Current_USART_Handle == USART1){
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
else if(Current_USART_Handle == USART2){
USART_SendData(USART2,ch);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
}
else if(Current_USART_Handle == USART3){
USART_SendData(USART3,ch);
while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);
}
return ch; /* 返回发送的字符 */
}
4.上述总共添加的代码
特别说明
首先感谢膝盖中箭-_-#大佬伟大的开源精神,让我在困惑时找到了解决问题的方案,得益于这种伟大精神,特此将我在用标准库复现成功的经验和源码分享出来,希望能够帮助到那些同样面对此问题有些困惑的使用标准库的小伙伴。
初次之外,程序中我仅使用了USART1(PA9)和USART2(PA2)两个串口的TX来进行重定向后的printf函数的使用测试,需要注意的是,一定要切记我们在使用对应的串口之前一定要记得串口进行初始化配置后才能够使用,在使用printf发送数据之前一定要先Set_Current_USART()进行选择,源码在顶部,需要参考的小伙伴请自取,如有不足之处,敬请多多批评指正!