浅谈MDK环境下使用#include <stdio.h>的问题

来源:互联网 发布:考研大数据 编辑:程序博客网 时间:2024/05/17 22:34

在使用MDK进行嵌入式开发,特别是调试串口的时候经常要用到C语言的标准输入输出库函数,如printf();。这样写出来的程序,通常编译和链接过程都不会报错,但是程序却无法正常运行,查看反汇编可以发现程序停在了BKPT 0xAB一行。


原因分析如下:

标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数. 
例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下: 只要自己添加一个int fputc(int ch, FILE *f)函数,能够输出字符就可以了 #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.使用微库,因为使用微库的话,不会使用半主机模式。
如果使用的是MDK,请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB“这样以后就可以使用printf,sprintf函数了 

方法2.仍然使用标准库,但在主程序中需要添加以下代码: 
 /*因为不使用半主机模式,所以标准Cstdio.h中有些使用半主机的函数需要重新写*/ 
#pragma import(__use_no_semihosting)  //确保没有从 C 库链接使用半主机的函数 _sys_exit(int x)     
//定义_sys_exit()以避免使用半主机模式 { x = x; }   
struct __FILE  //标准库需要的支持函数 { 
int handle; 
}; 
/* FILE is typedef’ d in stdio.h. */ 
FILE __stdout;   

在独立应用程序中,不太可能支持半主机操作。 因此,必须确保您的应用程序中没有链接 C 库半主机函数。 

为确保没有从 C 库链接使用半主机的函数,必须导入符号 __use_no_semihosting。可在工程的任何 C 或汇编语言源文件中执行此操作,如下所示: 

 C 模块中,使用 #pragma 指令: 

#pragma import(__use_no_semihosting)  

在汇编语言模块中,使用 IMPORT 指令: 

IMPORT __use_no_semihosting 

如果仍然链接了使用半主机的函数,则链接器就会报告错误。 
下面是网上关于半主机模式的解释:
【半主机是用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。 例如,使用此机制可以启用 C 库中的函数,如 printf() 和 scanf(),来使用主机的屏幕和键盘,而不是在目标系统上配备屏幕和键盘。
这种机制很有用,因为开发时使用的硬件通常没有最终系统的所有输入和输出设备。 半主机可让主机来提供这些设备。
半主机是通过一组定义好的软件指令(如 SVC)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。 调试代理提供与主机之间的必需通信。
半主机接口对 ARM 公司提供的所有调试代理都是通用的。 在无需移植的情况下使用 RealView ARMulator ISS、指令集系统模型 (ISSM)、实时系统模型 (RTSM)、RealView ICE 或 RealMonitor 时,会执行半主机操作,请参阅Figure 8.1。
在很多情况下,半主机由库函数内的代码调用。 应用程序还可以直接调用半主机操作。 有关 ARM C 库中的半主机支持的详细信息,请参阅《库和浮点支持指南》中的第 2 章 C 和 C++ 库。】 

0 0
原创粉丝点击