news 2026/4/18 13:27:51

STM32串口通信在Keil中的实现:完整示例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32串口通信在Keil中的实现:完整示例

手把手教你用Keil点亮STM32串口通信:从零开始的实战指南

你有没有遇到过这样的场景?代码烧进STM32后,板子“安静如鸡”,既不报错也不输出,只能靠猜哪里出了问题。这时候,如果能通过串口打印一句Hello, I'm alive!,那简直是黑暗中的一束光。

别急——这篇文章就是来帮你解决这个痛点的。我们将完全基于Keil MDK环境,带你一步步实现STM32的串口通信功能,不仅让你看到数据“飞”起来,还要让你搞懂每一步背后的逻辑。无论你是刚入门的新手,还是想巩固基础的老兵,这篇内容都能直接上手复用。


为什么是USART?它真的比“软件模拟”强那么多吗?

在嵌入式世界里,串口(UART/USART)几乎是每个项目都会用到的功能。它可以用来:

  • 输出调试信息
  • 接收用户命令
  • 与GPS、蓝牙、Wi-Fi模块通信
  • 实现设备间简单协议交互

而STM32自带的硬件USART外设,远非GPIO翻转可比。很多人初学时喜欢用“延时+IO翻转”的方式模拟串口(也就是常说的Bit-Banging),但这种方式存在致命缺陷:

问题具体表现
波特率不准稍有中断干扰就丢帧
占用CPU高发送一个字节就得卡住几毫秒
不支持并发无法同时处理其他任务

相比之下,硬件USART配合DMA或中断机制,能做到近乎“零开销”地完成数据收发。更关键的是:精度高、稳定性好、资源利用率低。

所以,如果你想做真正可靠的产品级开发,必须掌握硬件串口的使用方法。


开发工具选型:为什么我坚持推荐Keil?

市面上STM32的开发工具有很多:STM32CubeIDE、IAR、VSCode + PlatformIO……但如果你追求稳定、高效、调试体验流畅,我还是会首选Keil MDK(μVision)

Keil到底强在哪?

  • ✅ 编译器优化极佳,生成代码紧凑
  • ✅ 调试响应快,尤其在复杂中断场景下不卡顿
  • ✅ 支持ITM/SWO输出,也能轻松重定向printf
  • ✅ 社区资源丰富,90%以上的例程都提供Keil工程
  • ✅ 与ST官方工具链兼容性最好(比如.ST-LINK驱动)

虽然它是收费软件,但免费版(Limited Edition)已经足够用于学习和中小型项目开发。而且对于熟悉ARM架构的人来说,Keil的操作逻辑非常直观。

小贴士:如果你打算长期从事嵌入式开发,建议尽早熟悉Keil。它不仅是工程师的“老朋友”,更是面试常客。


STM32串口核心配置:PA9和PA10怎么用?

我们以最常见的STM32F103C8T6(蓝丸板)为例,使用USART1实现串口通信。

第一步:确定引脚映射

查阅数据手册你会发现:

  • USART1_TX → PA9
  • USART1_RX → PA10

这两个引脚属于GPIOA端口,在默认复用模式下即可作为串口使用。不需要额外配置AFIO重映射。

第二步:时钟使能不能忘!

STM32所有外设工作前都必须开启对应时钟。顺序如下:

  1. 使能GPIOA时钟
  2. 使能USART1时钟

这一步看似简单,却是新手最容易忽略的地方——忘了开时钟,再正确的代码也跑不起来。


HAL库实战:三步搞定串口初始化

ST官方提供的HAL库大大简化了外设配置流程。我们要做的,就是填好一张“配置表”。

核心结构体:UART_HandleTypeDef

这是HAL库中控制串口的核心句柄,包含了所有参数设置:

UART_HandleTypeDef huart1;

我们需要为它赋值以下关键字段:

参数含义
InstanceUSART1使用哪个USART实例
BaudRate115200波特率设为115200bps
WordLengthUART_WORDLENGTH_8B数据位8位
StopBitsUART_STOPBITS_1停止位1位
ParityUART_PARITY_NONE无校验
ModeUART_MODE_TX_RX支持发送和接收
HwFlowCtlUART_HWCONTROL_NONE不启用硬件流控
OverSamplingUART_OVERSAMPLING_16采样倍率16倍

把这些写进初始化函数:

static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }

就这么几行代码,就把串口的基本通信能力打开了。

⚠️ 注意:Error_Handler()是你自己定义的错误处理函数,建议点亮LED或死循环,方便定位失败原因。


printf在单片机上跑起来:重定向的艺术

你在PC上习惯了printf("value = %d\n", x);,但在STM32上,默认是没有输出目的地的。怎么办?

答案是:printf重定向到串口!

如何实现?

只需要实现一个标准C库函数:__io_putchar

int __io_putchar(int ch) { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY); return ch; }

这样,每次调用printf,系统就会自动调用这个函数,把字符一个个发出去。

别忘了勾选MicroLIB!

在Keil中,打开Project → Options for Target → Target页面,勾选“Use MicroLIB”

Why?因为标准C库太大,不适合嵌入式系统。MicroLIB是一个轻量级替代版本,专为微控制器设计,且支持printf重定向。


主程序长什么样?来个完整例子

现在我们把所有部分拼起来,看看最终的main.c是什么样子:

#include "main.h" #include <stdio.h> #include <string.h> UART_HandleTypeDef huart1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); char msg[64]; int count = 0; while (1) { sprintf(msg, "Hello from STM32! Count: %d\r\n", count++); printf("%s", msg); HAL_Delay(1000); } }

编译、下载、重启——打开你的串口助手(XCOM、SSCOM、PuTTY都可以),设置波特率为115200,你将看到:

Hello from STM32! Count: 0 Hello from STM32! Count: 1 Hello from STM32! Count: 2 ...

每一秒刷新一次,稳得一批。


常见坑点与避坑秘籍

别高兴太早,实际调试中还有很多“隐藏陷阱”。以下是几个高频问题及解决方案:

❌ 问题1:串口助手收不到任何数据

排查方向:
- 检查TX/RX是否接反(TX→RX,RX←TX)
- 查看电平是否匹配(TTL vs RS232)
- 确认波特率一致(两边都要设成115200)
- 检查供电是否正常(尤其是CH340G等转换芯片)

❌ 问题2:收到乱码

最大可能原因:时钟配置错误!

STM32的波特率由APB总线时钟分频而来。若系统时钟没配对(例如该用HSE却用了HSI),会导致实际波特率偏差过大。

经验法则:波特率误差应小于3%。可通过STM32CubeMX辅助计算理想DIV值。

❌ 问题3:printf不输出

除了检查MicroLIB,还要确认:
-__io_putchar函数已正确定义
- 没有被优化掉(可加__attribute__((used))防止删除)
-HAL_UART_Transmit未进入阻塞状态(检查中断是否抢占)

✅ 高阶技巧:使用中断接收命令

目前我们只是单向发送。如果想让MCU接收PC指令怎么办?

可以用中断方式监听接收完成事件:

uint8_t rx_data; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { // 回显收到的字符 HAL_UART_Transmit(&huart1, &rx_data, 1, 100); // 重新启动中断接收(单字节模式) HAL_UART_Receive_IT(&huart1, &rx_data, 1); } }

main()中调用一次:

HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启动中断接收

从此以后,每收到一个字节就会触发回调函数,实现真正的双向通信。


工程实践建议:不只是“能用”

当你把串口跑通之后,下一步该怎么提升?

🔧 加入环形缓冲区(Ring Buffer)

中断接收单字节效率低,容易丢失数据。更好的做法是结合DMA + 环形缓冲区,实现高速、大批量接收。

#define RX_BUFFER_SIZE 128 uint8_t dma_rx_buffer[RX_BUFFER_SIZE]; uint8_t uart_rx_temp; // 用于空闲中断触发 // 启动DMA接收 HAL_UART_Receive_DMA(&huart1, dma_rx_buffer, RX_BUFFER_SIZE); // 开启空闲线检测(IDLE Line Detection) __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

利用空闲中断判断一帧数据结束,再交给主循环解析,是最高效的串口协议处理方案之一。

📦 构建简易日志系统

有了串口输出,就可以打造自己的嵌入式日志框架:

#define LOG_INFO(fmt, ...) printf("[INFO] " fmt "\r\n", ##__VA_ARGS__) #define LOG_WARN(fmt, ...) printf("[WARN] " fmt "\r\n", ##__VA_ARGS__) #define LOG_ERR(fmt, ...) printf("[ERROR] " fmt "\r\n", ##__VA_ARGS__) // 使用示例 LOG_INFO("System started, version %s", "v1.0"); LOG_WARN("Battery level low: %d%%", 15);

不仅能提高调试效率,还能为后期OTA升级、远程诊断打下基础。


写在最后:串口不止于“打印”

也许你会觉得:“串口不就是用来打log的吗?”但其实它的潜力远不止于此。

  • 它可以是Modbus协议的物理层
  • 可承载AT指令集控制4G模块
  • 能连接指纹识别、RFID读卡器
  • 甚至可以通过自定义协议实现多机协同

掌握了STM32 + Keil下的串口通信,你就拿到了通往更复杂系统的钥匙。

下次当你面对一块新板子时,不要再靠“灯闪几次”来猜状态了。拿起串口线,让MCU亲口告诉你发生了什么。

如果你也曾被串口折磨得夜不能寐,欢迎在评论区分享你的“踩坑史”。我们一起把这条路走得更稳、更快。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 2:33:15

VibeThinker-1.5B真实体验:AIME数学题全对有多爽

VibeThinker-1.5B真实体验&#xff1a;AIME数学题全对有多爽 在当前大模型普遍追求千亿参数、超大规模训练数据的背景下&#xff0c;微博开源的 VibeThinker-1.5B-WEBUI 却以仅15亿参数和极低训练成本&#xff08;约7,800美元&#xff09;&#xff0c;在AIME等高难度数学竞赛任…

作者头像 李华
网站建设 2026/4/18 2:34:29

unet image Face Fusion历史版本回顾:v1.0之前的迭代演进过程

unet image Face Fusion历史版本回顾&#xff1a;v1.0之前的迭代演进过程 1. 引言 人脸融合技术作为计算机视觉领域的重要应用方向&#xff0c;近年来在图像处理、娱乐社交、数字人生成等场景中得到了广泛使用。unet image Face Fusion 是基于阿里达摩院 ModelScope 平台模型…

作者头像 李华
网站建设 2026/4/17 16:47:16

Open-AutoGLM实战应用:打造个人专属的智能手机机器人

Open-AutoGLM实战应用&#xff1a;打造个人专属的智能手机机器人 1. 引言&#xff1a;Open-AutoGLM – 智谱开源的手机端AI Agent框架 随着大模型技术的发展&#xff0c;AI智能体&#xff08;Agent&#xff09;正从“被动响应”向“主动执行”演进。在移动端&#xff0c;用户…

作者头像 李华
网站建设 2026/4/18 2:27:26

Emotion2Vec+ Large镜像功能全测评,9种情绪识别真实表现

Emotion2Vec Large镜像功能全测评&#xff0c;9种情绪识别真实表现 1. 引言&#xff1a;语音情感识别的技术演进与应用前景 近年来&#xff0c;随着深度学习在语音处理领域的深入发展&#xff0c;语音情感识别&#xff08;Speech Emotion Recognition, SER&#xff09; 已成为…

作者头像 李华
网站建设 2026/4/18 2:25:04

AWPortrait-Z性能瓶颈分析:如何根据GPU选择最佳生成参数

AWPortrait-Z性能瓶颈分析&#xff1a;如何根据GPU选择最佳生成参数 1. 技术背景与问题提出 AWPortrait-Z 是基于 Z-Image 模型精心构建的人像美化 LoRA 模型&#xff0c;通过科哥的 WebUI 二次开发实现了直观易用的图形化操作界面。该工具广泛应用于人像生成、风格迁移和图像…

作者头像 李华
网站建设 2026/4/18 2:35:12

面向中大型企业,AI能力突出的招聘系统排名是怎样的?

2025 年&#xff0c;AI 大模型技术在企业服务领域的深度渗透&#xff0c;推动招聘数字化从 “流程线上化” 迈入 “智能决策化” 新阶段。据 IDC报告显示&#xff0c;今年全球AI招聘系统市场规模突破300亿元&#xff0c;其中中大型企业&#xff08;员工规模超 1000 人&#xff…

作者头像 李华