历史上的今天
返回首页

历史上的今天

今天是:2024年10月21日(星期一)

正在发生

2018年10月21日 | STM32——关于printf重定向到串口的问题

2018-10-21 来源: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 

 /* 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()以避免使用半主机模式   

///

  

///   

///   

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

 

第二个问题,路径:D:\Keil3.80\ARM\Examples\ST\STM32F10xFWLib\Example

推荐阅读

史海拾趣

赛微(Cellwise)公司的发展小趣事

在技术创新和产品研发的过程中,赛微高度重视知识产权的保护和管理。公司积极申请各类专利和软件著作权,加强知识产权保护力度。截至目前,赛微已经拥有国际/国内软件著作权98项,国际/国内专利166项,正在申请的国际/国内专利64项。这些知识产权的积累不仅提升了公司的核心竞争力,也为公司的长期发展奠定了坚实基础。

Custom Connector Corporation公司的发展小趣事

随着电子行业的不断发展,CCC始终将技术创新作为公司发展的核心驱动力。公司投入大量研发资金,引进先进技术和设备,不断提升产品的性能和品质。同时,CCC还积极与高校、科研机构合作,共同研发具有自主知识产权的新产品。这些创新成果不仅为CCC赢得了市场的认可,也推动了整个电子连接器行业的技术进步。

DCX-CHOL Enterprises公司的发展小趣事

随着公司规模的扩大和市场竞争的加剧,DCX-CHOL Enterprises意识到品质管理的重要性。公司投入大量资源提升生产线自动化水平,引进先进的品质检测设备,并建立了严格的质量管理体系。这些措施有效地提高了产品的品质稳定性和可靠性,赢得了客户的信赖。同时,公司还注重员工培训和技能提升,培养了一支高素质、专业化的技术和管理团队。

喜美克斯(Cvilux)公司的发展小趣事

喜美克斯(Cvilux)公司自创立之初,就以其对电子技术的深刻理解和创新精神在行业中崭露头角。公司的创始人是一位电子工程领域的资深专家,他带领着一支充满激情的年轻团队,针对当时市场上电子产品的一些痛点,开始研发具有自主知识产权的新技术。经过数月的努力,他们成功开发出了一款具有高效能、低功耗特点的电子芯片,这一创新技术迅速获得了市场的认可,为喜美克斯公司的发展奠定了坚实的基础。

CALMIRCO公司的发展小趣事

随着电子行业的快速发展,市场竞争日益激烈,行业挑战也层出不穷。CALMIRCO公司始终保持敏锐的市场洞察力,积极应对各种挑战。在面对原材料价格波动、国际贸易摩擦等不利因素时,CALMIRCO公司及时调整战略,优化生产流程,降低成本,确保产品的竞争力。同时,公司还不断加大研发投入,推动技术创新和产业升级,以适应不断变化的市场需求。

这五个故事只是CALMIRCO公司在电子行业发展中众多精彩瞬间的缩影。正是这些不懈的努力和持续的创新,使得CALMIRCO公司在激烈的市场竞争中脱颖而出,成为电子行业的佼佼者。

Deutsch公司的发展小趣事

Deutsch公司自创立之初,就注重技术创新和产品研发。在早期阶段,公司成功开发出一款具有突破性的电子元件,这款元件以其高性能和低成本迅速在市场上获得了认可。随着技术的不断进步,Deutsch公司不断推出创新产品,满足日益增长的市场需求。这些技术突破和产品创新不仅提升了公司的竞争力,也推动了整个电子行业的发展。

问答坊 | AI 解惑

51完蛋了,赶紧转行学arm吧。

先从cortex-m0学,然后直接跳到cortex-v8! 51 月薪 1500,算是高薪。 cortex-m0能到4000啦, 如何学会cortex-v8,呵呵,月薪万元不用愁。…

查看全部问答>

驱动分层模型中的问题

底层的PDO是由PCI总线驱动创建的,那上面的PDO是由谁来创建的? 是不是由FDO创建的,这里有点不明白,不是说PDO是由MICROSOFT提供 FDO是由driverentry或addDevice历程用IoCreateDevice来创建的吗。 哪位大哥能仔细解释一下。…

查看全部问答>

Windows XP embedded中安装.msi文件

我有两个.msi安装包,A.msi和B.msi。 在windows xp下都能正确安装。 但在XPE中一个能安装,一个就失败,报错“This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installe ...…

查看全部问答>

★★★招聘硬件/嵌入式工程师

一、招聘: 硬件工程师  北京 学历:本科以上 工作经验:1年以上 工作要求:1、熟悉模拟电路和数字电路方面的知识,对单片机有比较深入的了解,熟练使用protel.         2、熟悉各类电子元器件以及其电气 ...…

查看全部问答>

应用程序如何读出SD卡里面一个较大文件

这个问题比较可笑吧。 可是我就是搞不定, 现在网上down下了一个例子程序,是读出SD卡的一个test.txt文件。 BOOL CSDMMCDlg::OnInitDialog() {         CDialog::OnInitDialog();         // Set the i ...…

查看全部问答>

请教,在SPI的从模式下,怎么发送一个字节的数据给主机

                                 请教,在SPI的从模式下,怎么发送一个字节的数据给主机,看STM32的手册上好象,MOSI和MISO是在同一个时钟边沿被被 ...…

查看全部问答>

cc2500无线模块、Si4432/4431模块、cc1101模块、无线DMX512模块

深圳市阅天信息技术有限公司 http://shop64482967.taobao.com/ 官网www.mcurf.com qq:343357509…

查看全部问答>

求救~~~

本帖最后由 paulhyde 于 2014-9-15 04:01 编辑 肯定有前辈玩过12864吧!所以···· 我现在想用12864显示出坐标和点的具体坐标,类似于能够显示的导航路线。 求哪位前辈可以给个方向~~很急呀!在线等!!!  …

查看全部问答>

2013电子竞赛有关宽带信号衰减及宽带小信号放大

本帖最后由 paulhyde 于 2014-9-15 03:27 编辑 请问各位有没有做过在高频100M的有关MV级小信号放大及大信号衰减为mv级的小信号的模块?主要用过的芯片有哪些推荐啊?谢谢了!!!    …

查看全部问答>

有没有懂c6000软件流水线级优化的

求懂得C6000软件流水线级优化的大神   给予指点   请先加站内好友 …

查看全部问答>