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和串口配置,再替換掉底層串口發送函數即可