先上代码
//加入以下代码,支持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;
}
上面的这一份代码看的很头晕,没怎么看明白,希望有大神能指点
//重定义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()函数,