参考文章:

使用clion进行STM32开发的串口重定向实现_clion stm32 printf-CSDN博客

前言

在STM32开发中,使用printf进行调试输出是一种非常便捷的方式。本文将详细介绍如何在CLion环境下实现STM32的串口重定向,基于F103C8T6实现,让你能够像在PC端一样使用printf函数。

一、实现步骤

1.1 添加必要的头文件

main.c文件开头引入标准输入输出头文件:

#include <stdio.h>
#include "stm32f1xx_hal.h"  // 根据你的MCU型号选择对应的头文件

1.2 实现重定向函数

main.c中添加以下代码,实现printf的重定向:

// 假设使用USART2,根据实际情况修改
extern UART_HandleTypeDef huart2;

// 重定向printf
int __io_putchar(int ch) {
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

// 可选:重定向scanf
int __io_getchar(void) {
    uint8_t ch = 0;
    HAL_UART_Receive(&huart2, &ch, 1, HAL_MAX_DELAY);
    return ch;
}

1.3 配置CMakeLists.txt

为了支持浮点数打印等高级功能,需要在CMakeLists.txt文件末尾添加以下配置:

# 设置浮点运算模式(根据MCU选择)
# 对于没有硬件FPU的MCU使用soft
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=soft")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=soft")

# 对于有硬件FPU的MCU(如F4系列)使用
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard -mfpu=fpv4-sp-d16")
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=fpv4-sp-d16")

# 使能printf浮点数支持
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -u _printf_float)

# 可选:使能scanf浮点数支持
# target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -u _scanf_float)

# 可选:使用nano库减小代码体积
# target_link_options(${CMAKE_PROJECT_NAME} PRIVATE 
#     --specs=nano.specs
#     --specs=nosys.specs
# )

二、使用示例

配置完成后,你就可以在代码中自由使用printf了:

int main(void) {
    // 系统初始化
    HAL_Init();
    SystemClock_Config();
    MX_USART2_UART_Init();
    
    // 基本使用
    printf("STM32 Serial Redirect Test\r\n");
    printf("System Clock: %lu Hz\r\n", SystemCoreClock);
    
    // 浮点数输出
    float temperature = 25.6f;
    printf("Temperature: %.2f °C\r\n", temperature);
    
    // 十六进制输出
    uint32_t value = 0xDEADBEEF;
    printf("Hex value: 0x%08X\r\n", value);
    
    while (1) {
        printf("Tick: %lu\r\n", HAL_GetTick());
        HAL_Delay(1000);
    }
}

三、重要注意事项

3.1 换行符的使用

在使用printf时,务必在字符串末尾加上\r\n,否则可能无法正常输出。

这是因为串口输出通常使用行缓冲(line buffering)模式。输出缓冲区的内容只有在以下情况才会被刷新:

  1. 遇到换行符\n(换行)或 \r\n(回车+换行)
  2. 缓冲区满:当缓冲区达到一定大小时
  3. 显式刷新:调用 fflush() 函数
  4. 程序结束:程序退出时自动刷新所有缓冲区

3.2 为什么需要\r\n

在串口通信中,\r\n 是标准的行结束符:

  • \r(Carriage Return,回车):将光标移到行首
  • \n(Line Feed,换行):将光标移到下一行

大多数串口终端软件(如SecureCRT、Xshell、串口助手等)都期望接收\r\n作为完整的换行标志。

3.3 其他解决方案

如果不想每次都写\r\n,可以采用以下方法:

方法1:禁用缓冲

setbuf(stdout, NULL);  // 完全禁用缓冲

方法2:手动刷新

printf("Hello World");
fflush(stdout);  // 强制刷新缓冲区

方法3:设置行缓冲模式

setvbuf(stdout, NULL, _IOLBF, 0);  // 显式设置行缓冲

四、常见问题排查

  1. 无输出
    • 检查串口波特率是否匹配
    • 确认TX/RX引脚连接正确
    • 验证时钟配置是否正确
  2. 输出乱码
    • 波特率设置不一致
    • 时钟源配置错误
    • 数据位、停止位、校验位设置不匹配
  3. 只能输出部分字符
    • 缓冲区问题,记得加\r\n
    • HAL_MAX_DELAY时间过短
  4. 浮点数无法输出
    • CMakeLists.txt中未添加浮点支持选项
    • 编译器优化等级过高,尝试降低优化等级

总结

通过本文的配置,你可以在CLion中轻松使用printf进行STM32调试。记住关键点:正确实现重定向函数、配置CMakeLists.txt支持浮点数、使用\r\n结尾确保输出。掌握这些技巧后,你的STM32开发调试效率将大大提升。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐