<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > STM32編程中printf函數重定向背后的原理

STM32編程中printf函數重定向背后的原理

作者: 時(shí)間:2023-12-18 來(lái)源:歐工玩轉嵌入式 收藏

在C語(yǔ)言中,printf是一個(gè)非常好用的函數,尤其是在程序調試階段,我們可以通printf打印變量的值來(lái)幫助查錯。在學(xué)習C語(yǔ)言的時(shí)候我們的開(kāi)發(fā)環(huán)境和運行環(huán)境都是PC機,printf函數打印到PC機的屏幕上是順理成章的事。但當我們在做嵌入式開(kāi)發(fā)時(shí),即使目標機器上有LCD屏幕,直接使用printf函數也是觀(guān)察不到結果的。這時(shí)有經(jīng)驗的工程師一般都會(huì )通過(guò)重定向printf函數來(lái)將printf的定向到串口,再通過(guò)USB轉TTL等工具從目標主機的串口上讀取數據流到電腦。

本文引用地址:http://dyxdggzs.com/article/202312/453992.htm

  下面先介紹在Keil中如何重定向printf的輸出到USART3。實(shí)際操作很簡(jiǎn)單,總共分為3步:

1.在工程設置中開(kāi)啟Use MicroLIB選項:

開(kāi)啟Use MicroLIB選項

2.在代碼中實(shí)現自定義的fputc函數,其函數原型為 int fputc(int c, FILE *stream)。printf函數底層是通過(guò)調用fputc函數來(lái)實(shí)現字符輸出的,所以我們只需對fputc函數重定義即可。本例中將printf重定向到的USART3,所以函數中用到的寄存器是USART3->SR:

添加自定義的fputc函數

3.最后一步,初始化USART3,使能輸出。初始化函數:

USART3初始化函數

  經(jīng)過(guò)以上3個(gè)步驟,的USART3已經(jīng)能夠通過(guò)printf打印輸出了,效果如下:

測試代碼

printf實(shí)際輸出效果

  可以看到,要想在開(kāi)發(fā)中實(shí)現printf重定向在操作上很簡(jiǎn)單。但其背后的原理又是什么?我們知道C語(yǔ)言是不支持函數重定義語(yǔ)法的,如果我們自己在同一作用域下定義2個(gè)同名函數編譯是必然報錯的。為什么我們可以重定義fputc函數而不會(huì )和函數庫中原有的fputc發(fā)生沖突呢?要解釋這個(gè)問(wèn)題,就要引入新的概念:“強符號”、“弱符號”。在gcc編譯器中使用 "__attribute__((weak)) " 修飾的函數或變量屬于弱符號,否則就是強符號。關(guān)于"強符號"和"弱符號",有以下規則:

  • 規則1:不允許強符號被多次定義(即不同的目標文件中不能有同名的強符號);如果有多個(gè)強符號定義,則鏈接器報符號重復定義錯誤。

  • 規則2:如果一個(gè)符號在某個(gè)目標文件中是強符號,在其他文件中都是弱符號,那么選擇強符號。

  • 規則3:如果一個(gè)符號在所有目標文件中都是弱符號,那么選擇其中占用空間最大的一個(gè)。比如目標文件A定義全局變量global為int型,占4個(gè)字節;目標文件B定義global為doulbe型,占8個(gè)字節,那么目標文件A和B鏈接后,符號global占8個(gè)字節(盡量不要使用多個(gè)不同類(lèi)型的弱符號,否則容易導致很難發(fā)現的程序錯誤)。

  在函數庫中默認的fputc函數就是通過(guò)"__attribute__((weak)) " 修飾的弱符號函數。所以在我們重定義了fputc函數后,編譯器就選擇了我們定義的fputc函數進(jìn)行鏈接。我們定義的fputc函數將字符輸出到USART3,printf函數在底層調用了fputc函數,因此printf的輸出便重定向到了USART3。如果你愿意,你也可以將printf函數重定向到SPI等外設輸出,但由于串口使用方便,我們一般選擇重定向到串口。

最后要注意一點(diǎn):強弱符號的鏈接特性是由鏈接器決定的,并不是C語(yǔ)言語(yǔ)法本身的特性。所以如果使用的是不同的編譯工具鏈,這個(gè)特性不一定存在??吹竭@里,想必大家已經(jīng)清楚STM32中printf重定向背后的原理了。




關(guān)鍵詞: STM32 編程

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>