优秀的编程知识分享平台

网站首页 > 技术文章 正文

STM32的printf是怎么实现的(stm32中printf如何输出)

nanyue 2024-07-25 06:06:56 技术文章 14 ℃

C语言中,printf函数默认的输出位置是stdout,即调试终端。但是对于单片机来说,没有stdout,所以一般将其重定向至串口来作输出。

然而很多使用过printf的STM32开发伙伴仅仅会使用而已,并不会自己实现这个函数。当没有这个函数的时候,就只能使用常见的sprintf函数和USART_SendData函数来实现数据的发送。显然这种方法比较笨,当printf函数可用的时候,大家更愿意使用printf。下面就帮助大家分析这个函数的实现方法。

printf函数属于系统调用,在不同编译环境下的实现方法略有不同,但其本质上会调用一个向stdout输出字符的系统调用函数。常用的STM32开发环境有两大类,keil MDK和GCC。在keil MDK环境下,这个系统函数是fputc,在GCC环境下这个系统函数是write。因此重写fputc或者write就可以实现STM32上的printf函数。

在MDK环境下重定义的方法如下。正点原子或野火的例程里就有。

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{   // 将这里的 USART1修改为USART2或USART3,即可实现printf函数输出到指定串口
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (uint8_t) ch;      
	return ch;
}


而由于缺少GCC环境下的例程,很多人照搬MDK的代码,发现printf函数根本无法使用,下面帮助大家重点分析GCC的代码。

#include <stdio.h>
// 减少编译器的警告
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
//确保程序中不包含任何半主机的函数
#pragma import(__use_no_semihosting)      
int _write (int fd, char *pBuffer, int size)  
{  
    int i = 0;
    for (i = 0; i < size; i++)  
    {   // 将这里的 USART1修改为USART2或USART3,即可实现printf函数输出到指定串口
        while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
        USART1->DR = (uint8_t) *pBuffer++;      
    }  
    return size;  
}

从上面的代码可以看出,GCC环境下printf函数的重定向方法更简单,只需要重写write函数就行了。

大家可能觉得掌握MDK的方法就可以了,但是随着开发的深入,我们才会发现GCC环境才是主流,ST官方的STM32CubeIDE,RT-Thread Studio等工具使用的都是GCC环境。我们有必要知道这一点,避免照搬keil MDK的代码。

另外,printf函数有个特点,在某些环境下遇见换行符才会更新输出。因此在STM32上使用printf函数的时候,必须在数据的结尾加上换行符 '\n'。有些地方喜欢 '\r\n',这是由于windows平台的换行就是'\r\n'。在GCC环境下,一个\n就可以了。

如果大家想要练手,可以使用这个嵌入式仿真平台,它很像Proteus,但是比Proteus人性化很多,还提供了许多学习例程,编译的hex文件还可以下载出来,非常方便。

平台的地址是 https://app.puliedu.com/#/,现在平台正在推广,可以免费注册体验

Tags:

最近发表
标签列表