stm32中printf重定向

先上代码

//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
	int handle;
};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
	x = x;
}
//重定义fp
utc函数
int fputc(int ch, FILE *f)
{
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
	USART1->DR = (u8) ch;
	return ch;
}
#endif
//加入以下代码,支持printf函数,而不需要选择use MicroLIB

为什么要用标准库我也不清楚,下文是他们的解释:

实际上,我们大部分工程用到的标准C库函数很少,而且keil中的microLIB默认已将printf重定向到UART1,我们可以直接使用printf通过串口1输出数据,所以勾选使用microLIB是一种非常好的方法,如果不勾选microLIB,则keil变压器会自动链接标准库函数。

一旦没勾选可不就是要自己重定义么

#if 1
#endif

#if 1, 看起来是很鸡肋的东西,之所以要这样搞,假设#if 0,就可以不执行里面的代码,编译的时候会被优化掉,正常情况下那个数字应该变成一个宏定义,估计写这个的人一开始只是随意写的。

问题来了,为什么要一会执行,一会不执行,这得从长说起。

重新定义printf,是用来串口调试的,(调试有很多种方法,有硬件调试,软件调试,串口调试)在写代码逻辑的过程中,很可能会很混乱,出现一些bug,printf可以查看代码,相较于debug选项,他们各有各自的优缺点,

#pragma import(__use_no_semihosting)

在keil中编程时常会遇到use_no_semihosting_swi的警告,这时你就是进入了半主机模式。**在嵌入式的编程中你是避免不了使用printf、fopen、fclose等函数的但是因为嵌入式的程序中并没有对这些函数的底层实现,使得设备运行时会进入软件中断BAEB处,这时就需要use_no_semihosting_swi这 个声明,使程序遇到这些文件操作函数时不停在此中断处,具体操作如下,将下列程序加入你的工程中:**

pragma import(__use_no_semihosting_swi)

这条语句可以关闭半主机模式,只需要在任意一个C文件中加入即可。

什么是半主机模式?

半主机是用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。 例如,使用此机制可以启用 C 库中的函数,如 printf() 和 scanf(),来使用主机的屏幕和键盘,而不是在目标系统上配备屏幕和键盘。

这种机制很有用,因为开发时使用的硬件通常没有最终系统的所有输入和输出设备。 半主机可让主机来提供这些设备。

半主机是通过一组定义好的软件指令(如 SVC)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。 调试代理提供与主机之间的必需通信。

半主机接口对 ARM 公司提供的所有调试代理都是通用的。 在无需移植的情况下使用 RealView ARMulator® ISS、指令集系统模型 (ISSM)、实时系统模型 (RTSM)、RealView ICE 或 RealMonitor 时,会执行半主机操作。

标准库使用半主机模式,半主机是通过一组定义好的软件指令 (如 SVC)SVC 指令 (以前称为 SWI 指令)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。调试代理(这里的调试代理是仿真器)提供与主机之间的必需通信。也就是说使用半主机模式必须使用仿真器调试。

ARMv7 之前的 ARM 处理器使用 SVC 指令 (以前称为 SWI 指令)进行半主机调

用。 但是,如果要为 ARMv6-M 或 ARMv7-M (如 Cortex™-M1 或 Cortex-M3 处

理器)进行编译,请使用 BKPT 指令来实现半主机。

简单的来说,半主机模式就是通过仿真器实现开发板在电脑上的输入和输出。和半主机模式功能相同的是ITM调试机制。有关ITM调试机制可以参考这里http://www.douban.com/note/248637026/

问题来了,为什么要关闭半主机模式?

半主机是这么一种机制,它使得在ARM目标上跑的代码,如果主机电脑运行了调试器,那么该代码可以使用该主机电脑的输入输出设备。 这点非常重要,因为开发初期,可能开发者根本不知道该 ARM 器件上有什么输入输出设备,而半主基机制使得你不用知道ARM器件的外设,利用主机电脑的外设就可以实现输入输出调试。 所以要利用目标 ARM器件的输入输出设备,首先要关掉半主机机制。然后再将输入输出重定向到 ARM 器件上,如 printf 和 scanf,你需要重写 fputc和 fgetc 函数。

//标准库需要的支持函数
struct __FILE
{
	int handle;
};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
	x = x;
} //标准库需要的支持函数
struct __FILE
{
	int handle;
};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
	x = x;
}

上面的这一份代码看的很头晕,没怎么看明白,希望有大神能指点

//重定义fputc函数
int fputc(int ch, FILE *f)
{
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
	USART1->DR = (u8) ch;
	return ch;
}//重定义fputc函数
int fputc(int ch, FILE *f)
{
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
	USART1->DR = (u8) ch;
	return ch;
}

fpuct函数,重定义了stdio.h文件里的函数

fputc()默认是把字符输出到调试器控制窗口,要把数据通过USART输出到串口助手,需对基于fputc()的printf()系列函数的输出都重定向到USART端口上去,要想使用USART功能,需重定向fputc()函数,

fpuct函数,重定义了stdio.h文件里的函数

fputc()默认是把字符输出到调试器控制窗口,要把数据通过USART输出到串口助手,需对基于fputc()的printf()系列函数的输出都重定向到USART端口上去,要想使用USART功能,需重定向fputc()函数,

除了半主机模式还有ITM机制调试

semihost/ITM机制浅析以及使用JLINK通过ITM调试stm32单片机