終於解決了MDK 3.80a中不能使用printf()函數的問題

剛開始學stm32,順着gpio、uart。。。的順序慢慢爬
初始化的方法學習了馬老師的STM32_Init.h大法,自己英文還可以,加上avr的基礎還不錯,所以gpio和時鐘配置都很順利
碰到uart就頭大了,看到各種例程裏都是printf()函數,自己也想用,畢竟是avr想用卻開銷不了的東西。但是我自己寫的程序裏一旦出現printf,單片機的不幹活了。查論壇首先發現要重定義fputc函數,照做了,還是不行。
後來懷疑是uart1初始化問題,用自己寫的put_c函數卻沒問題。
後來又發現一種說法,需要避免使用semihosting(半主機模式),我也把代碼加進去了(改fputc去掉了),還是不行。
再一想,重定義fputc是絕對必須的,加上了之後問題解決,成功使用printf("(敏感詞0373) \n");輸出了,哈哈
***************************************************************************************************

以上廢話,可以不看。
簡單地說:想在mdk 3.80a中用printf,需要同時重定義fputc函數和避免使用semihosting(半主機模式), 
論壇裏應該有完整介紹這個的帖子,但是我沒搜到,也許是沉了。重發出來希望能幫上像我這樣的菜鳥們。

需要添加以下代碼


#pragma import(__use_no_semihosting) 
/****************************************************************************** 
*標準庫需要的支持函數 
******************************************************************************/ 
struct __FILE 

int handle; 
/* Whatever you require here. If the only file you are using is */ 
/* standard output using printf() for debugging, no file handling */ 
/* is required. */ 
}; 
/* FILE is typedef’ d in stdio.h. */ 
FILE __stdout; 

/// <summary> 
/// 定義_sys_exit()以避免使用半主機模式 
/// </summary> 
/// <param name="x"></param> 
/// <returns></returns> 
_sys_exit(int x) 

x = x; 




int fputc(int ch, FILE *f)
{
    //USART_SendData(USART1, (u8) ch);
    USART1->DR = (u8) ch;
    
    /* Loop until the end of transmission */
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }

    return ch;
}

以上代碼來自goway 和 yugen 的發言,在此表示感謝



********************************************************************************************
更新:

根據四樓的帖子,發現在Options裏選上microlib之後,就不用關閉半主機模式了。



我順便查了一下semihosting的作用,介紹如下
Semihosting is a mechanism for ARM targets to communicate input/output requests
from application code to a host computer running a debugger. This mechanism could be
used, for example, to allow functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host rather than having a screen and keyboard on the target system.
This is useful because development hardware often does not have all the input and
output facilities of the final system. Semihosting allows the host computer to provide these facilities.
Semihosting is implemented by a set of defined software interrupt (SWI) operations.
The application invokes the appropriate SWI and the debug agent then handles the SWI
exception. The debug agent provides the required communication with the host.
In many cases, the semihosting SWI will be invoked by code within library functions. The application can also invoke the semihosting SWI directly. Refer to the C library descriptions in the ADS Compilers and Libraries Guide for more information on support for semihosting in the ARM C library.

找我的理解,這個模式是用來調試的,通過仿真器,使用主機的輸入輸出代替單片機自己的,也就是說即便單片機沒有輸出口也能printf到電腦上。反過來,由於這個模式更改了printf()等的實現方式,輸入輸出就不走單片機的外設了,所以只重定義fputc不起作用。

用代碼關閉此模式後,需要同時更新一下__stdout 和__stdin 的定義,所以有後面的語句。

以上僅爲個人理解,如有錯誤請指正。


另外,勾選microlib之後,也許編譯的時候就不把開啓semihosting的文件包進去了,所以沒事。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章