STM32使用printf问题总结
背景:使用STM32F4开发板串口时,想用c语言自带的printf函数把字符串输出到串口调试助手。
- 首先需要重定义fputc()、fgetc()函数
///重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口DEBUG_USART */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
///重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
int ch;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
-
勾选options for Target–>Target–>Use MicroLIB,使用MicroLIB库。
-microLIB 是标准C库的一个备选库,用于极少内存的嵌入式硬件中。
-microLIB不支持标准库
-主要完成以下工作:
-创建一个可执行C程序的环境:创建一个堆栈、创建一个堆(如果需要)、初始化程序用到的库
-调用main()开始执行 -
半主机(semi-hosting):它是一种机制,使得运行在ARM目标机上的代码能够通信,并使用运行了调试器的主机上的Input/Output工具
-开发初期,开发者可能根本不知道该ARM器件上有什么输入输出设备,而半主机机制使得开发者不用知道ARM器件的外设,利用主机电脑的外设就可以实现输入输出调试。
-如果要使用ARM器件上的输入、输出设备,首先要关闭semihosting。然后再将输入输出重定向到ARM器件上。
-microLIB 编译时通过Low-Level Functions与硬件连接,采用删减版high-level functions,没用system I/O functions。 -
如果不使用microLIB库,而使用标准库(默认使用semihosting),调用printf()之类的函数,会导致死机。解决方法:
-在程序中添加编译设置,不使用semihosting
//C语言中
#pragma import(__use_no_semihosting_swi)
//汇编语言中
IMPORT __use_no_semihosting_swi
2. 新增20240403
printf 在不同的编译器下,名称不同:
- GNUC下: __io_putchar()
- keil MDK下的arm_gcc下: fputc()
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(FILE *f)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif
//重定向printf函数
PUTCHAR_PROTOTYPE
{
txcplt_flag1 = 0;
HAL_UART_Transmit_IT(&huart1, (uint8_t*)&ch, 1);
while(txcplt_flag1==0);
return ch;
}
//不能用中断方式获取
GETCHAR_PROTOTYPE
{
char c = 0;
while(ring_buffer_read((unsigned char *)&c, &test_buffer) != 0);
return c;
}
参考: