本文最后更新于54 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
前言
在没有显示屏的情况下,我们如何知道程序运行到了哪一步?传感器采集的数据是多少?串口可以将单片机中的变量、状态等信息发送到各种设备上。今天,我们就来搞定 STM32 的 UART 发送与接收。
一、 串口通信基础:UART 是什么?
UART(通用异步收发传输器)是一种简单的串行通信协议。它只需要两根线:
- TX (Transmit):发送数据。
- RX (Receive):接收数据。
(请先共地)
核心参数(必须两端一致):
- 波特率 (Baud Rate):通信速度(如 115200 bps)。
- 停止位 (Stop Bits):标志一帧数据的结束。
- 校验位 (Parity):用于奇偶校验,通常设为 None。
二、 实战步骤:串口打印与数据回传
我们将实现两个功能:
- 每隔一秒向电脑发送“Hello STM32!”。
- 串口中断回传:电脑发给单片机什么,单片机就立刻原样回传(Echo)。
1. CubeMX 配置
- 选择引脚:在左侧菜单栏选择 Connectivity -> USART1。
- 模式设置:Mode 选择
Asynchronous(异步模式)。 - 参数设置:
- Baud Rate:
115200 Bits/s - Word Length:
8 Bits - Parity:
None - Stop Bits:
1
- Baud Rate:
- 开启中断 (重点):点击 NVIC Settings 选项卡,勾选
USART1 global interrupt的 Enabled。这是实现高效接收的关键。 - 生成代码:点击右上角 GENERATE CODE。


2. 编写逻辑代码
功能一:阻塞式发送 (Polling Mode)
在 main.c 的 while(1) 循环中,我们可以直接发送字符串。
/* USER CODE BEGIN WHILE */
while (1)
{
char msg[] = "Hello STM32! \r\n";
// 参数:串口句柄,数据指针,数据长度,超时时间(ms)
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);
HAL_Delay(1000);
/* USER CODE END WHILE */
}
功能二:中断式接收 (Interrupt Mode)
阻塞式接收(HAL_UART_Receive)会让程序死等,效率极低。实际开发中,我们使用中断。
第一步:开启接收中断
在 main() 函数的 /* USER CODE BEGIN 2 */ 区域调用一次:
/* USER CODE BEGIN 2 */
uint8_t rxBuffer; // 定义一个接收缓冲区(单个字节)
// 开启接收中断,每收到 1 个字节触发一次中断
HAL_UART_Receive_IT(&huart1, &rxBuffer, 1);
/* USER CODE END 2 */
第二步:编写回调函数
在 main.c 的末尾(USER CODE BEGIN 4 区域)编写中断触发后的逻辑。
/* USER CODE BEGIN 4 */
// 当串口接收到指定数量的数据后,HAL库会自动调用这个回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// 1. 将接收到的数据原样发回
HAL_UART_Transmit(&huart1, &rxBuffer, 1, 10);
// 2. 重新开启中断(非常重要!HAL库的中断接收是一次性的)
HAL_UART_Receive_IT(&huart1, &rxBuffer, 1);
}
}
/* USER CODE END 4 */
3. 终极技巧:重定向 printf
每次都写 HAL_UART_Transmit 太麻烦了?我们可以把 C 语言的标准 printf 函数重定向到串口,这样就能像在电脑上编程一样使用 printf 了。
在 main.c 中添加以下代码(需 #include <stdio.h>):
/* USER CODE BEGIN 0 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 0 */
注:如果你使用的是 Keil,记得在 Project Settings 里勾选 “Use MicroLIB”。
现在,你可以在代码里随处调用 printf("传感器数值: %d \r\n", sensor_value); 了!
三、 常见问题与坑 (Troubleshooting)
- 串口助手乱码:
- 检查波特率是否匹配(工程里是 115200,助手也要设为 115200)。
- 检查外部晶振频率是否与 CubeMX 中配置的一致。
- 只能发不能收:
- 检查
HAL_UART_Receive_IT是否在while(1)之前调用了。 - 检查是否在回调函数里忘记了再次开启中断。
- 检查
- printf 无输出:
- 检查是否勾选了 “Use MicroLIB”。
- 确保
fputc重定向代码已正确添加。
四、 总结
UART 是 STM32 最基础也最重要的外设之一。
- 发送:简单打印调试信息,推荐重定向
printf。 - 接收:推荐使用中断模式(
HAL_UART_Receive_IT),或者更高级的 DMA + 串口空闲中断(适合处理长数据包,我们以后再聊)。
学会了串口,你就拥有了观察程序内部运行的“超能力”。
[下一篇预告:STM32 中断系统与按键消抖]



