printf函数指向串⼝的⽅法
简单地说:想在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 transmon */
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 rire here. If the only file you are using is */
printf函数是如何实现的/* standard output using printf() for debugging, no file handling */
/
* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
如果使⽤的是,请在⼯程属性的“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;
///
/
// 定义_sys_exit()以避免使⽤半主机模式
///
///
///
_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  (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库函数之间的⼀个抽象层。