AT32 USART — printf 重定向到串口(嵌入式调试神器)

AT32F403A USART 串口 printf 重定向,嵌入式开发最常用的调试方法

USART — printf 重定向到串口

难度: ⭐(入门必学)
固件库: AT32F403A_407_Firmware_Library V2.2.2
源文件: project/at_start_f403a/examples/usart/printf/src/main.c


这个实验是干嘛的?

做嵌入式开发,最头疼的就是"程序跑起来了,但不知道里面发生了什么"。

在电脑上编程,你可以用 print() 打印变量值来调试。MCU 没有屏幕怎么办?

答案是:用串口把 printf 的输出发到电脑上。

这个实验教你把 C 语言的 printf 函数"重定向"到 USART 串口。之后你就可以在代码任意位置写 printf("温度=%d", temp),电脑串口助手就能看到输出。

这是嵌入式开发最常用、最实用的调试手段,没有之一。


硬件准备

你需要一个 USB 转串口模块(几块钱一个):

模块类型 价格 说明
CH340 ~3 块 最便宜,够用
CP2102 ~5 块 稳定
FT232 ~10 块 贵但好用

接线方式(3 根线):

1
2
3
4
开发板          USB转串口模块
  TX  ─────────→  RX
  RX  ←─────────  TX
  GND ──────────  GND

注意:TX 接 RX,RX 接 TX,要交叉!GND 必须共地。


串口助手软件

电脑端需要一个串口助手来查看输出:

软件 平台 推荐度
SSCOM Windows ⭐⭐⭐ 简单好用
XCOM Windows ⭐⭐⭐ 功能全
MobaXterm Windows ⭐⭐⭐ 自带串口
minicom Linux ⭐⭐

打开串口助手,选择正确的 COM 口(设备管理器里看),设置:

  • 波特率:115200
  • 数据位:8
  • 停止位:1
  • 校验位:None

完整代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "at32f403a_407_board.h"
#include "at32f403a_407_clock.h"

/* volatile 修饰,告诉编译器这个变量可能被中断修改,不要优化掉 */
__IO uint32_t time_cnt = 0;

int main(void)
{
  /* 第一步:系统时钟初始化 */
  system_clock_config();

  /* 第二步:板级初始化(LED、按键等) */
  at32_board_init();

  /* 第三步:串口初始化,波特率 115200 */
  uart_print_init(115200);

  /* 第四步:用 printf 打印一条启动消息 */
  printf("usart printf example: retarget the c library printf function to the usart\r\n");

  /* 第五步:主循环,每秒打印一次计数器 */
  while(1)
  {
    printf("usart printf counter: %u\r\n", time_cnt++);
    delay_sec(1);   // 等 1 秒
  }
}

代码逐行讲解

1. 头文件

1
2
#include "at32f403a_407_board.h"   // 板级支持包,包含 uart_print_init() 等
#include "at32f403a_407_clock.h"   // 时钟配置

2. 全局变量

1
__IO uint32_t time_cnt = 0;
  • __IOvolatile 的宏定义,表示这个变量可能被意外修改(比如中断里),编译器不要做优化
  • 如果不加 __IO,编译器可能把 time_cnt++ 优化掉,你就看不到计数器变化了

3. 串口初始化

1
uart_print_init(115200);

这行代码做了两件事:

  1. 配置 USART1:设置波特率 115200、8 数据位、无校验、1 停止位
  2. 重定向 printf:把 printf 的输出接到 USART1 的发送引脚

波特率 115200 意味着每秒可以传输约 11520 个字节(每个字节 10 bit),足够打印调试信息了。

4. printf 输出

1
printf("usart printf counter: %u\r\n", time_cnt++);
  • %u — 无符号整数格式
  • \r\n — 回车换行(串口助手需要这个才能正确显示)
  • time_cnt++ — 先打印值,再自增

5. 延时

1
delay_sec(1);   // 等 1 秒

如果不加延时,printf 会以 MCU 的速度疯狂输出,串口助手会收到一大堆数据。


printf 重定向的原理(进阶)

uart_print_init() 内部做了什么?其实很简单:

在 C 标准库里,printf 最终会调用一个叫 fputc 的函数来输出每个字符。我们只需要重写这个函数,让它把字符发到串口:

1
2
3
4
5
6
7
8
9
// 这段代码在 at32f403a_407_board.c 里,你不用自己写
int fputc(int ch, FILE *f)
{
  // 把字符 ch 通过 USART1 发出去
  usart_data_transmit(USART1, (uint16_t)ch);
  // 等待发送完成
  while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET);
  return ch;
}

这就是"重定向"的全部秘密:替换 fputc,把输出目标从屏幕改成串口


常用 printf 格式

1
2
3
4
5
printf("十进制: %d\n", 123);          // 十进制: 123
printf("十六进制: 0x%X\n", 0xFF);     // 十六进制: 0xFF
printf("浮点数: %.2f\n", 3.14);       // 浮点数: 3.14
printf("字符串: %s\n", "hello");      // 字符串: hello
printf("温度=%d, 湿度=%d\n", 25, 60); // 同时打印多个变量

实验现象

  1. 编译、下载程序
  2. 打开串口助手,选择正确的 COM 口,波特率 115200
  3. 应该看到:
1
2
3
4
5
usart printf example: retarget the c library printf function to the usart
usart printf counter: 0
usart printf counter: 1
usart printf counter: 2
...

每秒打印一行,计数器递增。


常见问题

Q: 串口助手收不到数据?

  1. 检查 COM 口是否选对(设备管理器里看)
  2. 波特率是否 115200
  3. TX/RX 是否交叉连接
  4. GND 是否共地
  5. 程序是否下载成功

Q: 收到乱码?

  • 波特率不匹配!代码里是 115200,串口助手也要设 115200
  • 如果时钟配置不对,实际波特率会偏移,也会乱码

Q: 只能用 USART1 吗?

  • uart_print_init() 默认用 USART1
  • 如果想用其他串口(如 USART2),需要自己修改 fputc 函数

小结

概念 说明
USART 通用同步异步收发器,最常用的串行通信接口
波特率 每秒传输的 bit 数,双方必须一致
printf 重定向 替换 fputc,让 printf 输出到串口
\r\n 回车换行,串口助手显示必需

学了串口能做什么?

串口是嵌入式开发的"万能接口"——调试、通信、联网都靠它:

调试与监控

用途 说明
变量监控 printf("温度=%d\n", temp) 实时查看传感器数据
状态打印 程序跑到哪一步了、有没有进中断、错误码是什么
性能测量 打印代码执行时间,找出性能瓶颈
日志系统 带时间戳的运行日志,出问题后可以回溯

通信与控制

项目 原理 难度
串口控制 LED 电脑发指令控制板子上的灯(“on”/“off”)
上位机通信 MCU 通过串口把数据发到电脑 Python/C# 程序 ⭐⭐
蓝牙透传 接 HC-05 蓝牙模块,手机就能控制 MCU ⭐⭐
WiFi 联网 接 ESP8266 模块,MCU 通过串口发 AT 指令联网 ⭐⭐⭐
GPS 定位 接 GPS 模块,解析 NMEA 协议获取经纬度 ⭐⭐⭐
RS485 总线 多设备联网通信(工业 Modbus 协议) ⭐⭐⭐
CAN 转串口 汽车/工业设备数据采集 ⭐⭐⭐

实际应用场景

  • 智能家居:MCU + ESP8266 + 串口 → 手机远程控制家电
  • 工业采集:MCU + RS485 + 串口 → 采集温湿度传感器数据上传
  • 无人机:MCU + GPS + 串口 → 获取位置信息
  • 调试一切:无论做什么项目,串口 printf 都是你的"眼睛"

核心思路:串口就是 MCU 的"嘴巴"和"耳朵"。能说(printf 发数据)能听(接收指令),就能和电脑、手机、其他设备对话。


下一步:学会了串口打印,接下来可以学 ADC 采样,用 printf 把 ADC 采样值打印出来。

世界是你们
使用 Hugo 构建
主题 StackJimmy 设计