STM32CubeIDE实现printf重定向输出到串口

本文详细介绍了在STM32上配置串口并重写__io_putchar和_write函数,以支持printf功能的过程。通过修改main.c文件中的USERCODEBEGIN0部分,实现了串口数据的正确发送,并提供了多种实现方式,包括使用HAL库和直接操作寄存器。此外,还提及了如何使printf支持浮点数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了好多的文章都是重写的函数__io_putchar 和 fputc

/* USER CODE BEGIN 0 */
#include "stdio.h"

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

PUTCHAR_PROTOTYPE
{

  // 注意下面第一个参数是&huart1,因为cubemx配置了串口1自动生成的
  HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);

  return ch;
}
#endif
/* USER CODE END 0 */ 

上面的方法在之前的版本中是可行的。 现在的版本升级以后就变了。
必须重写_write函数。
搞了好半天,最后搞通了。
感谢这位大神的指点https://blog.csdn.net/kyzb002/article/details/101100922

串口怎么配置的就不细述了。
只要在main.c文件中。 USER CODE BEGIN 0 之间加入下面这段代码即可
网上有的文章只写了第二个函数 __io_putchar 却没写必须要重新定义 _write 函数
这里是两个函数都必须实现的。
attribute((weak))的作用是叫弱函数
_write函數在syscalls.c中, 使用__weak定義, 所以可以直接在其他文件中定義_write函數

之前只需要重写一个__io_putchar函数就能运行,我猜是因为stdio.h里面的代码变了。

/* USER CODE BEGIN 0 */
#include "stdio.h"
// 重定向print start
int __io_putchar(int ch)
{
    //具体哪个串口可以更改USART1为其它串口
    while ((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕
    USART1->DR = (uint8_t) ch;
    return ch;
}

//_write函數在syscalls.c中, 使用__weak定義, 所以可以直接在其他文件中定義_write函數
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		__io_putchar(*ptr++);
	}
	return len;
}
// 重定向print  end
/* USER CODE END 0 */

或者两个合并成一个函数

/* USER CODE BEGIN 0 */
#include "stdio.h"
// 重定向print start 
//_write函數在syscalls.c中, 使用__weak定義, 所以可以直接在其他文件中定義_write函數
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		  while ((USART1->SR & 0X40) == 0); //等待发送完毕
		  USART1->DR = (uint8_t) *ptr++;
	}
	return len;
}
// 重定向print  end
/* USER CODE END 0 */

再来个更简洁的

/* USER CODE BEGIN 0 */
#include "stdio.h"
// 重定向printf start 
//_write函數在syscalls.c中, 使用__weak定義, 所以可以直接在其他文件中定義_write函數
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	 if(HAL_UART_Transmit(&huart1,ptr,len,0xffff) != HAL_OK)
	 {
		 Error_Handler();
	 }
}
// 重定向printf end

如果要让printf 支持浮点数 %f 还需要打开配置。参考下面的文章
https://blog.csdn.net/qq_42980638/article/details/98359026

### STM32CubeIDE实现 `printf` 函数重定向的方法 在嵌入式开发中,为了通过串口或其他外设输出调试信息,通常需要对标准库中的 `printf` 函数进行重定向。以下是基于多个参考资料总结的实现方法。 #### 1. 添加必要的头文件 要实现 `printf` 的重定向功能,首先需要包含 `<stdio.h>` 头文件,这是因为在该头文件中定义了与输入/输出操作相关的数据结构和函数原型[^1]。 ```c #include <stdio.h> ``` --- #### 2. 定义 `PUTCHAR_PROTOTYPE` 由于不同的编译器可能有不同的函数签名需求,因此需要根据使用的编译器来适配 `printf` 输出字符的函数原型。对于 GNU 编译器(如 ARM GCC),推荐使用 `__io_putchar`;而对于其他编译器,则可以继续沿用传统的 `fputc` 方法[^2]。 ```c #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif ``` --- #### 3. 实现核心函数 接下来,需实现实际发送单个字符的功能。此部分依赖于 HAL 库提供的 UART 发送接口 `HAL_UART_Transmit` 来完成字符传输。以下是一个典型的实现: ```c PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY); return ch; } ``` 在此代码片段中: - `&huart1` 是指代已初始化好的 USART 句柄。 - `(uint8_t*)&ch` 表示将待发送字符转换为字节数组形式。 - 参数 `1` 指定仅发送一个字节的数据长度。 - 超时时间参数设置为 `HAL_MAX_DELAY`,表示无限等待直到发送成功为止[^3]。 需要注意的是,在某些情况下,如果发现仅有 `\n` 不会触发换行效果而必须手动加入回车符 `\r` 才能生效的话,可以在每次调用前自动附加回车控制码。 --- #### 4. 配置项目属性 除了上述软件层面的操作之外,还需要确保硬件资源已被正确定义并启用。具体来说就是确认已经在 CubeMX 工具里启用了对应USART模块及其中断服务程序,并且完成了基本时钟树及时序设定等工作。 另外值得注意的一点是在多线程环境下运行 RTOS 时可能会遇到 Hard Fault 错误的情况。这可能是由于默认分配给各任务堆栈大小不足以容纳复杂的 I/O 操作所致。此时可以通过增加相关任务所占用内存区域的方式来解决问题[^4]。 --- ### 总结 综上所述,要在 STM32CubeIDE 下顺利完成 `printf` 函数向指定串口设备方向上的映射工作,主要涉及以下几个方面的工作内容:一是引入适当的标准 IO 接口描述文档;二是根据不同环境调整目标平台特定版本下的写法差异;三是编写具体的驱动层交互逻辑以支持逐位传递机制;四是合理规划整个系统的资源配置策略从而规避潜在风险因素的影响。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值