良许Linux教程网 Linux教程 这两种printf()函数重定向方法,太实用了

这两种printf()函数重定向方法,太实用了

以前我们已经探讨了STM32上的串行通信编程,学习了如何通过USART1端口将数据发送至电脑的串行调试工具或从其接收数据。现在我们的目标是在STM32项目中植入printf()函数,以便在编写程序时能够轻松输出调试信息。

策略1:采用MicroLIB库

1.1 在KEIL-MDK中启用MicroLIB选项

使用KEIL-MDK集成开发环境时,

image-20240127191650274
image-20240127191650274

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();
printf("\r\nstm32f103rct6\r\n");
printf("\r\nCortex-M3\r\n");
while (1); 
return 0;
}

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

image-20240127191655065
image-20240127191655065

法2:不使用MicroLIB库

2.1 半主机模式

半主机模式是ARM的一种机制,实现将来ARM应用程序代码的输入/输出请求传送至运行着调试器的主机。例如设置使用半主机模式下的ARM应用程序,可以使用printf()和scanf()来使用主机的显示器和键盘,而不需要在ARM系统上搭配显示器和键盘。

半主机通过一组定义好的软件指令(如SVC)来实现的,这些指令在程序控制下产生异常,ARM应用程序调用半主机对应的异常处理函数,然后调试代理处理该异常。

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

2.2 实现代码

在工程中加上如下代码:

#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上了。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部