摘自:http://www.openedv.com/posts/list/3172.htmapp
usart這部分代碼我也是從網上copy出來的,一下是做者的解釋:
簡單地說:想在mdk 中用printf,須要同時重定義fputc函數和避免使用semihosting(半主機模式),
標準庫函數的默認輸出設備是顯示器,要實如今串口或LCD輸出,必須重定義標準庫函數裏調用的與輸出設備相關的函數.
例如:printf輸出到串口,須要將fputc裏面的輸出指向串口(重定向),方法以下:
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
因printf()之類的函數,使用了半主機模式。使用標準庫會致使程序沒法運行,如下是解決方法:
方法1.使用微庫,由於使用微庫的話,不會使用半主機模式.
方法2.仍然使用標準庫,在主程序添加下面代碼:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
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;
若是使用的是MDK,請在工程屬性的「Target「-》」Code Generation「中勾選」Use MicroLIB;今天參考了一下論壇,使用微庫能夠很好的解決這個問題。
2.另外一種方法:(其實大同小異)
須要添加如下代碼
(論壇裏應該有完整介紹這個的帖子,可是我沒搜到,也許是沉了。)
#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; ide
/// <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)
{
} oop
return ch;
}
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不起做用。 post
用代碼關閉此模式後,須要同時更新一下__stdout 和__stdin 的定義,因此有後面的語句。 ui
以上僅爲我的理解,若有錯誤請指正。 debug
另外,勾選microlib以後,也許編譯的時候就不把開啓semihosting的文件包進去了,因此沒事。調試
C庫函數重定向:
用戶能定義本身的C語言庫函數,鏈接器在鏈接時自動使用這些新的功能函數。這個過程叫作重定向C語言庫函數,以下圖所示。
舉例來講,用戶有一個I/O設備(如UART)。原本庫函數fputc()是把字符輸出到調試器控制窗口中去的,但用戶把輸出設備改爲了UART端口,這樣一來,全部基於fputc()函數的printf()系列函數輸出都被重定向到UART端口上去了。
下面是實現fputc()重定向的一個例子:
externvoidsendchar(char*ch);
intfputc(intch,FILE*f)
{/*e.g.writeacharactertoanUART*/
chartempch=ch;
sendchar(&tempch);
returnch;
}
這個例子簡單地將輸入字符從新定向到另外一個函數sendchar(),sendchar()假定是個另外定義的串口輸出函數。在這裏,fputc()就彷佛目標硬件和標準C庫函數之間的一個抽象層。code
<ignore_js_op>orm