历史上的今天
返回首页

历史上的今天

今天是:2025年06月10日(星期二)

正在发生

2018年06月10日 | STM32的printf函数重定向

2018-06-10 来源:eefocus

在前面学习了STM32的串口编程,通过USART1向计算机的串口调试助手打印数据,或者接收计算机串口调试助手的数据,接下来我们可以实现STM32工程上的printf()函数了,方便用于程序开发中调试信息的打印。

1. 法1:使用MicroLIB库

1.1 KEIL-MDK中的Use MicroLIB选项

在MDK开发环境中, 
这里写图片描述

MicroLib是缺省c库的备选库,它可装入少量内存中,与嵌入式应用程序配合使用,且这些应用程序不在操作系统中运行。 
MicroLib进行了高度优化以使代码变得很小,功能比缺省c库少,不具备某些ISO c特性,部分库函数的运行速度也比较慢,如内存拷贝函数memcpy()。 
MicroLib与缺省c库之间的主要差异在网上有许多文章都有写到,这里摘抄记录: 
(1)MicroLib 不符合 ISO C 库标准。 不支持某些 ISO 特性,并且其他特性具有的功能也较少。 
(2)MicroLib 不符合 IEEE 754 二进制浮点算法标准。 
(3)MicroLib 进行了高度优化以使代码变得很小。 
(4)无法对区域设置进行配置。 缺省 C 区域设置是唯一可用的区域设置。 
(5)不能将 main() 声明为使用参数,并且不能返回内容。 
(6)不支持 stdio,但未缓冲的 stdin、stdout 和 stderr 除外。 
(7)MicroLib对 C99 函数提供有限的支持。 
(8)MicroLib不支持操作系统函数。 
(9)MicroLib不支持与位置无关的代码。 
(10)MicroLib不提供互斥锁来防止非线程安全的代码。 
(11)MicroLib不支持宽字符或多字节字符串。 
(12)与stdlib不同,MicroLib不支持可选择的单或双区内存模型。MicroLib只提供双区内存模型,即单独的堆栈和堆区。

MicroLib提供了一个有限的stdio子系统,它仅支持未缓冲的stdin、stdout和stderr,那么也就是说勾选了Use MicroLib选项后,在代码工程中就可以使用printf()函数咯? 
然而事实并非如此,这样直接使用printf()函数,其打印的字符串最终不知道打印到何处。我们要做的是将调试信息打印到USART1中,所以需要对printf()函数所依赖的打印输出函数fputc()重定向(MicroLib中的printf()函数打印操作依赖fputc())。

1.2 重定向fputc函数

在MicroLib的stdio.h中,fputc()函数的原型为:

int fputc(int ch, FILE* stream)


此函数原本是将字符ch打印到文件指针stream所指向的文件流去的,现在我们不需要打印到文件流,而是打印到串口1。基于前面的代码:


#include

int fputc(int ch, FILE* stream)

{

    //USART_SendData(USART1, (unsigned char) ch);

    //while (!(USART1->SR & USART_FLAG_TXE));

    USART_SendChar(USART1, (uint8_t)ch);

    return ch;

}


注意,需要包含头文件stdio.h,否则FILE类型未定义。 

勾选了Use MicroLib选项,重定向fputc()函数后,我们就可以在工程代码中使用printf()函数了:


int main(void)

{


    USART_Configuration();

    //USART_SendString(USART1, "HelloWorld\n");

    //USART_SendChar(USART1, 'h');

    printf("\r\nstm32f103rct6\r\n");

    printf("\r\nCortex-M3\r\n");

    while (1);  


    return 0;

}


printf()函数的使用方法跟之前一样,运行结果: 

这里写图片描述

2. 法2:不使用MicroLIB库

2.1 半主机模式

半主机模式是ARM的一种机制,实现将来ARM应用程序代码的输入/输出请求传送至运行着调试器的主机。例如设置使用半主机模式下的ARM应用程序,可以使用printf()和scanf()来使用主机的显示器和键盘,而不需要在ARM系统上搭配显示器和键盘。 
半主机通过一组定义好的软件指令(如SVC)来实现的,这些指令在程序控制下产生异常,ARM应用程序调用半主机对应的异常处理函数,然后调试代理处理该异常。

第二段话感觉理解起来有点模糊,但是第一段还是懂它在讲什么的。一般的ARM应用程序中并不需要半主机操作,在这里为确保ARM应用程序中没有链接MicroLib的半主机相关函数,我们要取消ARM的半主机工作模式。

2.2 实现代码

在工程中加上如下代码:

//取消ARM的半主机工作模式

#pragma import(__use_no_semihosting)                             

struct __FILE { 

    int handle; 

}; 


FILE __stdout;          

_sys_exit(int x) 

    x = x; 

}


int fputc(int ch, FILE *f){      

    while((USART1->SR&0X40)==0);

    USART1->DR = (u8) ch;      

    return ch;

}

上面的代码摘自正点原子的范例程序,具体每一行的意义目前也不大清楚。这样操作后,在不使用MicroLib的前提下,仍能使用printf()函数将调试信息打印到USART1上了。

推荐阅读

史海拾趣

Box Enclosures公司的发展小趣事

Box Enclosures公司自创立之初,就明确了自己的定位——专注于为电子行业提供高品质的机箱和外壳产品。公司始终坚持严格的质量控制标准,从原材料采购到生产工艺,每一个环节都力求精益求精。这种对品质的执着追求,使得Box Enclosures的产品在市场上赢得了良好的口碑,逐渐在电子行业中占据了一席之地。

Coors Components Inc公司的发展小趣事

在某个关键项目的研发过程中,Coors Components Inc公司遇到了前所未有的技术难题。然而,公司的研发团队并没有因此而气馁,他们通过加强内部沟通、分享经验以及相互支持,最终成功攻克了难关。这一经历不仅增强了团队的凝聚力,也为公司培养了一批忠诚且能力出众的员工。

Guerrilla RF公司的发展小趣事
避免灰尘和异物进入硬盘内部,定期清理硬盘周围的环境。
Hilscher Gesellschaft für Systemautomation mbH公司的发展小趣事

HVPSI成立于本世纪初,起初是一家小型的技术初创企业,专注于研发高效、可靠的高压电源模块。在创始人及核心团队的带领下,公司迅速在MOV(金属氧化物压敏电阻)模块领域取得了突破。这些模块在电力电子设备中起到了关键的过压保护作用,有效提高了系统的稳定性和安全性。通过不断的技术迭代和产品优化,HVPSI逐渐在行业内树立了技术领先的形象。

Electromagnetic Industries Llp公司的发展小趣事

EMI公司深知产品质量对企业的重要性。因此,公司建立了严格的质量管理体系,从原材料采购到生产加工再到产品检验,每一个环节都严格把关。同时,公司还引进了先进的检测设备和技术手段,确保产品质量的稳定性和可靠性。这些措施的实施使得EMI公司的产品质量得到了客户的广泛认可。

DAPAudio公司的发展小趣事

DAPAudio深知产品质量对于企业长远发展的重要性。因此,公司投入大量资源用于提升产品的品质和生产效率。通过严格的质量控制流程和持续的技术创新,DAPAudio的产品在音质、稳定性和耐用性方面均达到了行业领先水平。这一努力不仅赢得了客户的信赖,也树立了公司高品质的品牌形象。

问答坊 | AI 解惑

我对如何编写高质量的程序的看法

我对嵌入式软件开发的时间也不是很长,仅仅只有5年,算不上高手,也不是老手只能算是5岁的老菜鸟 ,在前面的3年里没有高人指点,靠着自己摸索也写了不少的程序吧,那时侯我没有想过要写出容易理解 和维护以及移植的问题,仅仅想着如何把这个功能 ...…

查看全部问答>

请大家帮我看看ALPHA是什么型号

请大家帮我看看M-AUDIO FireWire 410声卡机上声音调节器型号 在那可以买到   附件所示图片谢谢大家!!…

查看全部问答>

开机自动加载USB设备

在WinCE启动完成后,插入U盘或者USB网卡,系统可以检测到新设备的插入,并自动加载,但是这时候如果重启,硬件不拔下来,开机后必须拔下U盘或者USB网卡,重新插入,才能再次被识别。请问各位大大,有什么办法能让WinCE启动后自动加载这些硬件?谢谢 ...…

查看全部问答>

使用SetDevicePower开启wifi,几秒钟之后自动关闭

        string path = \"{98C5250D-C29A-4985-AE5F-AFE5367E5006}\\\\\"; string deviceName=\"SDIO86881\";   DevicePowerNotify(path2 + deviceName, DevicePowerState.FullOn, POWER_NAME);   ...…

查看全部问答>

EVC下怎么实现这样的界面?给高分!

我要做的是个MP4的UI,这里没办法贴图,我给个链接,http://www.idoodoo.com/ui-design2.asp 大家帮忙看看这个UI是怎么实现的? 主要是实现上面的两个图的效果,以前没做过上层的东西,这两天看了些资料,还是有点迷糊,有一下几个问题: 1、左上 ...…

查看全部问答>

用Micro Framework 3.0对GPIO的操作

我的开发环境是VS2008,我想写一个WinCE下对S3C2440的GPIO操作的程序,应该怎样写呢?比如,我希望操作GPB的某个管脚,应当怎样写代码?另外,Micorsoft.SPOT.Hardware下的CPU.PIN的用法有些不解,(CPU.PIN)15是什么意思呢?是表示芯片的第15个管脚 ...…

查看全部问答>

短信猫原理图

有人有短信猫的原理图没?? 希望有的好心人共享。…

查看全部问答>

tlc5510的应用

本帖最后由 paulhyde 于 2014-9-15 03:00 编辑 高速AD——tlc5510的应用,采样率是20M。 包含经典应用的电路图。    …

查看全部问答>

请问“ON安森美半导体”和“Fairchild”可以申请样品吗?

本帖最后由 jameswangsynnex 于 2015-3-3 19:52 编辑 大家好: 请问大家有没有在 ON 和 Fairchild 的网站上申请过样品呢?我初步看了一下没有看到申请样片的地方, 如果您有申请过的话能否给点指教,谢谢。 …

查看全部问答>