历史上的今天
返回首页

历史上的今天

今天是:2025年01月17日(星期五)

正在发生

2019年01月17日 | 关于在stm32中使用printf函数的问题

2019-01-17 来源:eefocus

想在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 //通过宏替换相当于int fputc(int ch,FILE *f)

 /* 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;  

///   
///   
///   
_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库函数之间的一个抽象层。


推荐阅读

史海拾趣

Aleph America Corporation公司的发展小趣事

Aleph America Corporation 是一家专注于光电传感器和光电开关解决方案的公司。以下是关于该公司发展的5个相关故事:

  1. 公司成立及发展: Aleph America Corporation 成立于1986年,总部位于美国新泽西州。公司专注于光电传感器技术的研发和生产,并提供广泛的光电开关产品线,包括光电接近传感器、光电开关、光电耦合器等。随着市场对自动化和安全系统需求的增长,Aleph 在行业内逐渐建立了良好的声誉。

  2. 技术创新与产品质量: Aleph America Corporation 致力于技术创新和产品质量的提升。公司拥有一支专业的研发团队,不断引入先进的光电传感技术,并且注重产品的生产工艺和质量控制,确保产品具有稳定的性能和可靠的品质。

  3. 应用领域广泛: Aleph 的产品广泛应用于各种工业和商业应用领域。光电传感器和光电开关被广泛应用于自动门、电梯、安防系统、自动化生产线等领域,为客户提供了安全可靠的解决方案。

  4. 全球市场拓展: 随着全球市场的不断扩大,Aleph 在海外市场的拓展也逐渐加强。除了在美国设立总部和生产基地外,公司还在欧洲、亚洲等地设立了销售办事处和代理商网络,以便更好地满足全球客户的需求。

  5. 参与行业标准和认证: Aleph America Corporation 积极参与行业标准的制定和产品认证工作。公司的产品符合国际标准和认证要求,如CE认证、UL认证等,确保产品在全球范围内的市场准入和使用安全。

以上故事展示了 Aleph America Corporation 在光电传感器和光电开关领域的发展历程和成就,突出了其在技术创新、产品质量、市场拓展和行业认证方面的重要贡献。

弘凯光电(BRIGHTEK)公司的发展小趣事

作为一家有社会责任感的企业,弘凯光电始终致力于环保和可持续发展。公司秉承“质量第一”的方针,不仅注重产品的品质和性能,还积极推广环保理念,致力于生产高质量、环保的LED产品。此外,公司还积极参与社会公益活动,回馈社会,为建设环保节能型社会贡献自己的力量。

以上五个故事,基于弘凯光电在电子行业中的发展历程和公开信息,尽量以事实为依据,避免了主观评价。这些故事展示了弘凯光电在技术创新、市场拓展、社会责任等方面的努力和成就,也反映了公司在电子行业中的崛起和影响力。

Endicott Research Group Inc (ERG)公司的发展小趣事

自1979年起,Endicott Research Group(ERG)就开始涉足电源转换产品的制造领域。在初创时期,公司面临着资金紧张和技术挑战,但团队坚持创新,专注于为LCD背光供电的LED驱动器及相关电源设备的研发。通过不断的试验和改进,他们成功地开发出了一系列高效稳定的产品,为公司的后续发展奠定了坚实的基础。这一时期的艰苦奋斗和技术积累,成为了ERG发展历程中的重要篇章。

华大北斗(Allystar)公司的发展小趣事

随着医疗、工业和军事市场对电源设备的需求不断增长,ERG凭借其深厚的技术积累和创新能力,逐渐在这些领域获得了广泛的认可。他们的产品以其高性能和稳定性赢得了众多客户的信赖。特别是在医疗设备领域,ERG的电源产品为诊断和治疗设备提供了可靠的动力支持,为医疗行业的发展做出了重要贡献。

CANOPUS公司的发展小趣事

随着电子技术的飞速发展,CANOPUS开始探索将传统鼓制作技艺与现代电子技术相结合。公司不断投入研发,推出了一系列具有创新性的电子鼓产品。这些产品不仅保留了传统鼓的音质和手感,还加入了现代电子元素,使得演奏更加多样化和便捷。

Fascomp公司的发展小趣事

随着公司规模的扩大,Fascomp开始关注更广阔的市场。公司针对智能手机市场推出了一款低功耗、高性能的处理器,迅速在市场上获得了成功。同时,公司还不断推出新的产品线,如平板电脑专用芯片、物联网设备等,以满足不同客户的需求。这些创新举措使Fascomp在激烈的市场竞争中脱颖而出。

问答坊 | AI 解惑

关于低频信号发生器的问题,请高手们指教

我的电路设计和程序都编写好了,但是输出波形很不理想,只有方波OK,三角波,锯齿波,正弦波都失真很厉害,求大侠们帮小弟解决下这个问题! ORG 0000H MAIN:          MOV A,#00H      MO ...…

查看全部问答>

运算放大器基本电路30例

运算放大器基本电路30例…

查看全部问答>

2440-camera-display????

在camera驱动的Display_Cam_Image 中 memcpy((void *)(FRAMEBUF_BASE+ (240*pos_y + pos_x) + y*240*2),(void *)buffer_rgb,(QCIF_XSIZE)*2); 这句中 FRAMEBUF_BASE+ (240*pos_y + pos_x) + y*240*2 这个地址为什么要这样计算???…

查看全部问答>

关于ARM+DSP双核开发系统的问题

我们现在做的一个关于嵌入式课题在开发系统选型时遇到了一点问题,因为我们的系统既需要良好的GUI又需要较强大的信号处理能力,因此我们不得不把目光放到了arm+dsp双核开发系统上,但过去的双核开发系统应用相对较少,大多是选取一片独立的arm芯片 ...…

查看全部问答>

讨论:各位在单片机中用什么算法去做菜单?

讨论:各位在单片机中用什么算法去做菜单?   比如我要用89s52和smc1602做个菜单。这个菜单有很多层的,即有子菜单。   不知道各位用的是什么方法和算法?   小弟我一开始就用树和链表方式做的。不好。 & ...…

查看全部问答>

自己做个数子示波器,液晶屏是用那款好!

动手做个示波器,液晶显示屏不知用那款好些.有的说用 NS 12864C,也有的的说用 NS 12864R 有点拿不准.想请教高手.用那款实用好些,二者有何区别.请给欲我答复.感激.谢谢!…

查看全部问答>

【低功耗】LDO的选用技术

LDO 是新一代的集成电路稳压器,它与三端稳压器最大的不同点在于,LDO 是一个自耗很低 的微型片上系统(SoC)。LDO 按 其 静 态 耗 流 来 分 , 分 为 OmniPowerTM / MicroPowerTM / NanoPowerTM 三种产品。OmniPowerTM LDO 的静态电流在 10 ...…

查看全部问答>

深入浅出ARM7

深入浅出ARM7-LPC213x_214x(上).pdf 深入浅出ARM7_LPC213x__214x_下册.pdf…

查看全部问答>

各位大侠看看这个Atmega128单片机接收数据代码有啥问题,谢谢!怀疑是中断接收那里

#include #include #include #define fosc 8000000 #define baud 4800 #define uchar unsigned char #define uint unsigned int char rev_buf[80];        //接收缓存      /*uchar rev ...…

查看全部问答>

cyclone v使用报告——内存内存控制器

使用Altera的UniPHY控制器,采用软核和硬核两种模式,使用的时候一般是PHY跟controller一起使用,例化的时候已经将两者合为一体了。使用软核或硬核的区别只是下图的一个check box是否选上。 本来还好好的,默认没有选上,一点击使用硬核之后,图表 ...…

查看全部问答>