声明
本文内容转载至https://www.mculover666.cn/posts/2251182441/
1.printf与fputc
printf
定义在 <stdio.h>
头文件中,如下:
int printf(const char *format, ...);
printf
函数根据 format
字符串给出的格式打印输出到 stdout
(标准输出)中,当然,printf
函数是不会一个字符一个字符去输出,它会调用更底层的 I/O 函数:fputc
去逐个字符打印。
fputc
也定义于头文件 <stdio.h>
中,如下:
int fputc(int ch, FILE *stream);
fputc
函数写入字符 ch
到给定输出流 stream
,printf
函数在调用该函数时,会向stream
参数传入stdout
从而打印数据到标准输出。
那么,要实现printf
打印到串口就变得非常简单了,只需要重新定义fputc
函数,在fputc
的函数中将数据通过串口发送,称之为:fputc
重定向或者printf
重定向。
2.在MDK中使用MicroLib重定向printf
勾选Use MicroLib
MicroLib是对标准C库进行了高度优化之后的库,供MDK默认使用,相比之下,MicroLIB的代码更少,资源占用更少:
重定义fputc到串口
重新实现fputc
函数,编写代码将这个字符通过串口发送,因为发送每个字符时都会调用该函数,所以为了效率,不再调用库函数 HAL_UART_Transmit
发送,而是直接操作寄存器发送。
- 检测串口当前状态
STM32L431的USART串口外设有一个 ISR 寄存器,全名 Interrupt and status register, 用来指示当前串口的状态,如图:
其中 BIT6 TC用来指示当前串口是否发送完成,可以通过判断该位来判断串口当前是否处于发送状态,代码如下:
while((USART1->ISR & 0X40) == 0);
串口发送字符ch,同样,为了提高发送效率,直接使用寄存器来操作:
USART1->TDR = (uint8_t) ch;
最后实现fputc函数就变的非常简单了,这里我放在usart.c文件的末尾:
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
while((USART1->ISR & 0X40) == 0);
USART1->TDR = (uint8_t) ch;
return ch;
}
#endif
或者
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
3.在MDK中使用标准库重定向printf
printf 函数使用了半主机模式,所以直接使用标准库会导致程序无法运行,因此必须提前告知编译器不使用半主机模式:
#pragma import(__use_no_semihosting)
void _sys_exit(int x)
{
x = x;
}
所以,重定向fputs()函数完整的代码如下:
#if 1
#include <stdio.h>
#pragma import(__use_no_semihosting)
void _sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
};
FILE __stdout;
int fputc(int ch, FILE *stream)
{
while((USART1->ISR & 0X40) == 0);
USART1->TDR = (uint8_t) ch;
return ch;
}
#endif
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)