📋 文章目录
本文记录了嵌入式开发中 USART 串口通信的学习过程,包含理论学习、环境搭建、代码实现与问题排查等内容。以下是文章结构概览:
- 📅 学习进度概览
- 📝 学习记录与问题追踪
- 1. 理论学习与概念梳理
- 2. 环境搭建与第一个工程
- 3. 轮询模式工程创建:代码实现与调试过程
- 4. 中断模式工程创建:代码实现与调试过程
- 5. DMA模式工程创建:代码实现与调试过程
- 6. printf重定向到usart串口上,实现printf打印信息到串口助手上
📅 学习进度概览
当前学习阶段:嵌入式开发 - USART 串口通信
当前使用的开发板:STM32F407VGT6-Disk
开始时间:2026 年 8 月 22 日
学习目标:
- 理解 USART(通用同步异步收发器)的基本工作原理
- 掌握 STM32(或其他 MCU)的 USART 外设配置流程
- 能够实现基本的串口收发功能(查询/中断/DMA 方式)
- 记录并解决学习过程中遇到的实际问题
注意:本文中每个实验均另开了一个工作空间并重新创建项目,并非在原先工程上做出改变
📝 学习记录与问题追踪
1. 理论学习与概念梳理
时间:2026/08/16
内容:
- 复习了串行通信与并行通信的区别。
- 理解了 USART 与 UART 的关键差异:USART 支持同步模式(有时钟线),UART 仅支持异步。
- 学习了波特率、数据位、停止位、奇偶校验等关键参数的含义。
2. 环境搭建与第一个工程
时间:2026/08/20
内容:
- 使用 STM32CubeMX 初始化 USART 外设,生成代码。
- 使用 STM32CubeIDE 进行开发。
- 使用 USB 转 TTL 模块连接电脑配合串口助手工具进行调试。
遇到的问题:
- 串口助手打印结果乱码
- 串口助手无打印结果
- 配合 printf 函数重定向但 printf 函数没能打印出结果
3.轮询模式工程创建:代码实现与调试过程
时间:2026/08/20
使用 STM32CubeMX 创建新工程,并开启外部高速晶振(HSE)作为系统时钟源。
创建工程,开启外部晶振:
配置时钟:
修改 debug 模式:
开启串口为异步模式:
勾选为每个外设单独生成 .c/.h 文件
生成代码,使用 VS Code 打开项目,借助扩展包采用提示词工程给出的代码写好测试发送的代码
打开 CubeIDE,代码自动更新,点击小锤子编译,无报错无警告
按照设置的串口连接好硬件及开发板,为 USB 转 TTL 模块下载好驱动,本文采用波特律动串口助手中提供的驱动下载链接下载好 CH340 型号驱动,并按如图方式连接好硬件部分,TXD 接 PA10,RXD 接 PA9,并将 USB 口接在电脑上
烧录代码
打开波特律动串口助手,选择好串口并开启,查看串口信息打印
遇到的实际问题与解决方案:
- 发现串口有东西打印出来,且打印间隔为原 while 函数中设置的 1 秒,但是打印出来的数据是乱码,本应该是 "Hello World"
- 时间间隔没问题,则程序确实进入了 while 循环,且循环没问题,但数据乱码,问题大概率出在波特率不匹配,硬件接线问题
- [最终解决方案]:修改连接的串口,我最终改成使用usart2串口,使用PA2,PA3两个引脚,--取消时钟配置--并重新生成代码,代码最终逻辑如图,波特率,校验位等无任何修改,最终得到串口输出结果
改写代码为接收电脑发送的数据,并用发送函数检验是否收到
最终也能成功返回发送的数据
- 最后总结原因:成功与失败的最大区别是取消了外部晶振提供时钟,采用的内部HSI,大概率就是这个原因影响了串口
4.中断模式工程创建:代码实现与调试过程
时间:2026/08/21
MX工程创建与轮询方式类似,但本次不使用外部时钟,且勾选usart2的全局中断,点击usart2的NVIC标签,勾选全局中断,保存并生成代码,代码仅需将发送,接收函数加上_IT后缀,将传递的超时时间字段去掉即可。
编译并烧录,查看串口助手打印结果
结果在未发送任何数据时界面不断发送空,发送了R0后界面不断发送R0回来
查看代码发现将两个中断模式的发送接收函数都写到while循环里了,中断模式不像轮询模式一样,是非阻塞的,会一直循环执行,导致循环过快而显示如图样式,只要将中断接收函数放到while循环外即可,但是一般不会将中断发送放在while循环里,不然也会导致上述结果,一般是中断接收后调用中断处理函数HAL_UART_RxCpltCallback,此函数可自己重新定义一下,并将逻辑写入,而后中断接收完成后将执行函数中的逻辑
那有要求中断接收不能放在while循环里,要保证能不断接收则可将中断接收函数放在中断处理函数的末尾,这样中断处理函数逻辑完成前就会进入下一次中断接收。
5.DMA模式工程创建:代码实现与调试过程
时间:2026/08/21
MX项目创建只要基于中断模式下再添加DMA通道即可,如图分别添加Rx和Tx的DMA通道保持默认设置即可
保存并生成代码,发送、接收函数仅需在中断发送函数的基础上将_IT后缀改为_DMA即可,我在中断回调处理函数中加上了阻塞式发送并在末尾补上DMA接收,将接收数组放在PV注释对中以防报错
编译,烧录,查看串口助手,发现能正常接收并回复
接收不定长数据
主要靠的是串口空闲中断,使用HAL_UARTEx_ReceiveToIdle,这个函数也有阻塞,中断,DMA三种方式,也是通过修改后缀即可使用,另外,使用此函数对应的回调函数也有所不同,这里应使用HAL_UARTEx_RxEventCallback回调函数,这里我直接使用DMA方式在本工程里进行测试结果如图,由于我定义的数组长度是50,所以发送过长时触发了传输过半中断,故而后面的数据没能返回,可以使用_HAL_DMA_DISABLE_IT函数取消传输过半中断。
6.printf重定向到usart串口上,实现printf打印信息到串口助手上
时间:2026/08/21
目前尝试了各种方法,如重写fputc函数,重写_write函数,关闭半主机模式(代码实现,写在fputc函数后)均未能实现,须待解决