STM32让printf通过串口打印及自定义printf函数

https://blog.csdn.net/zhengyangliu123/article/details/50876993/

在嵌入式系统中,通过串口打印log是非常重要的调试手段,但是直接调用底层驱动打印信息非常不方便,在c语言中一般使用printf打印基本的显示信息,而默认printf的结果不会通过串口发送,所以需要对printf的输出进行重定向。

 有时候需要同时从多个串口输出信息,如果仍然想通过printf函数输出信息,就需要自己写printf的实现。

 

一. 初始化端口和配置

       对串口用到的GPIO进行配置,并对串口的参数进行初始化。

STM32让printf通过串口打印及自定义printf函数

STM32让printf通过串口打印及自定义printf函数

二.   宏定义并实现具体的发送函数

       代码在编译时首先判断__GNUC__有无定义,之后将PUTCHAR_PROTOTYPE替换成具体的定义。在keil5中,使用fputc函数,所以其实最后是重写了fputc的实现,在该函数中,调用串口的发送函数,每次发送一个字符。

STM32让printf通过串口打印及自定义printf函数

STM32让printf通过串口打印及自定义printf函数

 

三.  在使用标准库的时候,需要修改设置使用MicroLib,或者还是使用标准库并添加一部分代码,具体如图所示。

STM32让printf通过串口打印及自定义printf函数

STM32让printf通过串口打印及自定义printf函数

四.  最后,在需要用到printf函数的文件中要#include<stdio.h>

五.  嵌入式系统中,有时候可能会用到多个串口,如果都想使用形如printf的函数来打印信息,就需要另一个printf函数,此时可以使用以下方法自己调用更底层的函数来实现。

       1、申明头文件#include<stdarg.h>

       2、buffer的大小根据需要调整,相应的循环条件也要改,此处可以定义成宏,方便调节buffer大小。

       3、定义va_list变量,该变量是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。

       4、va_start让arg_ptr指向printf函数可变参数里边的第一个参数;

       5、vsnprintf()将按照fmt的格式将arg_ptr里的值依次转换成字符保存到buffer中,该函数有最大字符数限制,超过后会被截断,且该函数会自动在字符串末尾加‘\0’。

       6、最后必须调用va_end(),由此确保堆栈的正确恢复。

       这样就可以调用printf2向串口打印log了。

STM32让printf通过串口打印及自定义printf函数

六. 注意: 

  • 以上printf使用的是blocking模式,如果发送太多数据,会消耗比较多的时间,影响程序其他部分的及时执行

  • 此种方法对于其他平台同样适用,只需正确设置gpio和串口配置,再替换掉底层串口发送函数即可