1. 程式人生 > >STM32中如何對printf函數重定向

STM32中如何對printf函數重定向

https 差異 nco 標準 工作 顯示 結果 pretty 安全

轉載地址:https://blog.csdn.net/qq_29344757/article/details/75363639

  通過USART1向計算機的串口調試助手打印數據,或者接收計算機串口調試助手的數據,接下來我們現STM32工程上的printf()函數,方便用於程序開發中調試信息的打印。

方法一:使用MicroLIB庫

1.1 KEIL-MDK中的Use MicroLIB選項

在MDK開發環境中

技術分享圖片

MicroLib是缺省c庫的備選庫,它可裝入少量內存中,與嵌入式應用程序配合使用,且這些應用程序不在操作系統中運行。
MicroLib進行了高度優化以使代碼變得很小,功能比缺省c庫少,不具備某些ISO c特性,部分庫函數的運行速度也比較慢,如內存拷貝函數memcpy()。
MicroLib與缺省c庫之間的主要差異在網上有許多文章都有寫到,這裏摘抄記錄:
(1)MicroLib 不符合 ISO C 庫標準。 不支持某些 ISO 特性,並且其他特性具有的功能也較少。
(2)MicroLib 不符合 IEEE 754 二進制浮點算法標準。
(3)MicroLib 進行了高度優化以使代碼變得很小。
(4)無法對區域設置進行配置。 缺省 C 區域設置是唯一可用的區域設置。
(5)不能將 main() 聲明為使用參數,並且不能返回內容。
(6)不支持 stdio,但未緩沖的 stdin、stdout 和 stderr 除外。
(7)MicroLib對 C99 函數提供有限的支持。
(8)MicroLib不支持操作系統函數。
(9)MicroLib不支持與位置無關的代碼。
(10)MicroLib不提供互斥鎖來防止非線程安全的代碼。
(11)MicroLib不支持寬字符或多字節字符串。
(12)與stdlib不同,MicroLib不支持可選擇的單或雙區內存模型。MicroLib只提供雙區內存模型,即單獨的堆棧和堆區。

MicroLib提供了一個有限的stdio子系統,它僅支持未緩沖的stdin、stdout和stderr,那麽也就是說勾選了Use MicroLib選項後,在代碼工程中就可以使用printf()函數咯?
然而事實並非如此,這樣直接使用printf()函數,其打印的字符串最終不知道打印到何處。我們要做的是將調試信息打印到USART1中,所以需要對printf()函數所依賴的打印輸出函數fputc()重定向(MicroLib中的printf()函數打印操作依賴fputc())。

1.2 重定向fputc函數

在MicroLib的stdio.h中,fputc()函數的原型為:

1 int fputc(int
ch, FILE* stream)

此函數原本是將字符ch打印到文件指針stream所指向的文件流去的,現在我們不需要打印到文件流,而是打印到串口1。基於前面的代碼:

1 #include <stdio.h>
2 
3 int fputc(int ch, FILE* stream)
4 {
5     //USART_SendData(USART1, (unsigned char) ch);
6     //while (!(USART1->SR & USART_FLAG_TXE));
7 USART_SendChar(USART1, (uint8_t)ch); 8 return ch; 9 }

註意,需要包含頭文件stdio.h,否則FILE類型未定義。
勾選了Use MicroLib選項,重定向fputc()函數後,我們就可以在工程代碼中使用printf()函數了:

 1 int main(void)
 2 {
 3 
 4     USART_Configuration();
 5     //USART_SendString(USART1, "HelloWorld\n");
 6     //USART_SendChar(USART1, ‘h‘);
 7     printf("\r\nstm32f103rct6\r\n");
 8     printf("\r\nCortex-M3\r\n");
 9     while (1);  
10 
11     return 0;
12 }

printf()函數的使用方法跟之前一樣,運行結果:

技術分享圖片

方法2:不使用MicroLIB庫

2.1 半主機模式

半主機模式是ARM的一種機制,實現將來ARM應用程序代碼的輸入/輸出請求傳送至運行著調試器的主機。例如設置使用半主機模式下的ARM應用程序,可以使用printf()和scanf()來使用主機的顯示器和鍵盤,而不需要在ARM系統上搭配顯示器和鍵盤。
半主機通過一組定義好的軟件指令(如SVC)來實現的,這些指令在程序控制下產生異常,ARM應用程序調用半主機對應的異常處理函數,然後調試代理處理該異常。

第二段話感覺理解起來有點模糊,但是第一段還是懂它在講什麽的。一般的ARM應用程序中並不需要半主機操作,在這裏為確保ARM應用程序中沒有鏈接MicroLib的半主機相關函數,我們要取消ARM的半主機工作模式。

2.2 代碼實現

在工程中加上如下代碼:

 1 //取消ARM的半主機工作模式
 2 #pragma import(__use_no_semihosting)                             
 3 struct __FILE { 
 4     int handle; 
 5 }; 
 6 
 7 FILE __stdout;          
 8 _sys_exit(int x) 
 9 { 
10     x = x; 
11 }
12 
13 int fputc(int ch, FILE *f){      
14     while((USART1->SR&0X40)==0);
15     USART1->DR = (u8) ch;      
16     return ch;
17 }

上面的代碼摘自正點原子的範例程序。

STM32中如何對printf函數重定向