1. 程式人生 > >C庫函式重定向(在玩兒STM32的時候看到有這麼個用法)

C庫函式重定向(在玩兒STM32的時候看到有這麼個用法)

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;  

/// <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;  
}  
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的檔案包進去了,所以沒事。

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庫函式之間的一個抽象層。

第二個問題,路徑:D:\Keil3.80\ARM\Examples\ST\STM32F10xFWLib\Examples