STM32F103_串口通信

发布时间:2026/10/16 9:02:23

STM32F103_串口通信 STM32F103C8T6 串口通信轮询 / 中断 / DMA 三种方式附 Keil 逻辑分析仪测波特率这次做的实验是 STM32 串口USART。要求挺全先用 HAL 库实现最基本的串口收发再把轮询、中断、DMA三种方式都过一遍最后在没有示波器的情况下用 Keil 的逻辑分析仪看波形、反推波特率。中间踩了不少坑记录一下留个档。一、实验是啥板子还是最常见的 STM32F103C8T6Blue Pill内容分基础 三个任务基础 1串口协议、RS232/RS485/TTL/CH340 这些理论。基础 2两台笔记本怎么通过串口传文件。任务一轮询STM32 往上位机连续发hello windows!观察不加延时连续发时上位机是不是会丢数据上位机发#暂停、发*继续。任务二用中断方式重做上面的#/*控制再用DMA方式连续发送。任务三没示波器用Keil 软件仿真 逻辑分析仪看串口输出波形算实际波特率。二、先理清串口那点事帧格式8N1串口是异步通信双方不共时钟线靠约定同样的波特率来对齐每一位。每个字符 10 个 bit[起始位 0] [8 个数据位 D0~D7] [停止位 1]起始位固定是低电平0停止位固定是高电平1数据位先发低位。波特率 115200 就是每秒 115200 bit所以1 bit ≈ 8.68µs一个字符 ≈ 86.8µs。三种电平TTL / RS232 / RS485协议帧格式、波特率是一样的区别在物理层电平| 标准 | 电平 逻辑 距离 用在哪儿| TTL | 0~3.3V 高1 低0 很短 单片机、CH340 之间| RS232 | ±15V 负逻辑 ~15m 老式电脑 DB9 串口| RS485 | 差分 A/B 压差正负 上千米 工业现场、多机总线单片机串口是 TTL 电平电脑上只有 USB所以要用CH340这个USB 转 TTL的桥接芯片电脑 USB → CH340 → TTL → STM32。CH340 插电脑上被识别成一个 COM 口我这是 COM3。三、两台笔记本怎么传文件下面讲原理硬件限制单独标出来。串口传文件是怎么回事串口一次只搬一个字节本身没有文件这个概念。串口传文件就是把文件当成一串字节按协议切成一块块发过去接收方校验对了再拼回文件。麻烦点有两个串口没时钟、还可能丢字节——两边只约定了波特率数据一多一快就可能错位、丢字节怎么知道传完没、传错没——光靠起止位不够得在每一块数据里加序号、长度、校验和收方算一遍对不上就让对方重发。这俩问题就是文件传输协议XMODEM / YMODEM / ZMODEM要解决的。三个文件传输协议| 协议 | 一块多大 | 校验 | 特点| XMODEM | 128 字节 | 累加和 | 最老最简单每块都要等对方 ACK慢| YMODEM | 1024 字节 | 累加和 | XMODEM 升级能一次传多个文件| ZMODEM | 动态 | CRC32 | 效率最高带文件名/大小、支持断点续传最常用流程都差不多发送方把文件切成块 → 加序号和校验发出去 → 接收方收到后校验 → 回 ACK对继续下一块或 NAK错重发这一块→ 全部发完再发结束标志。ZMODEM 因为自带文件名和断点续传实际最常用。硬件怎么接老台式机/笔记本背后有DB9 串口公头两台对连得用交叉串口线也叫空调制解调器线 / null modem2 脚 TX 接对方 3 脚 RX、3 脚 RX 接对方 2 脚 TXGND 共地。现在的笔记本基本没串口了就换成两根 USB 转串口比如两个 CH340一根的 TX 接另一根的 RX、RX 接 TX、GND 共地效果一样。软件怎么操作经典做法是用Windows 超级终端HyperTerminal两边设成一样的波特率/数据位/停止位比如 115200 8N1接收方点接收文件、发送方点发送文件协议选ZMODEM之后就自动握手、分块传输、校验、结束。四、轮询方式任务一接线USART1 用 PA9TX/ PA10RX串口是交叉接的PA9STM32 发送→ CH340 模块RXDPA10STM32 接收→ CH340 模块TXD两边 GND 共地核心代码轮询的精髓就在主循环里那句HAL_UART_Receive(huart1, ch, 1, 0)——最后一个参数0是超时时间意思是别等看一眼有没有字符没有立刻返回。CPU 每转一圈就主动问一次串口while(1){/* 非阻塞轮询查一眼有没有字符没有就继续 */if(HAL_UART_Receive(huart1,ch,1,0)HAL_OK){if(ch#)g_paused1;/* 收到 # 暂停 */elseif(ch*)g_paused0;/* 收到 * 继续 */}if(g_paused0){HAL_UART_Transmit(huart1,(uint8_t*)msg,strlen(msg),1000);HAL_Delay(200);/* 每句间隔 200ms */}}现象加 200ms 延时串口助手一行行稳定收到hello windows!不丢不乱不加延时把HAL_Delay(200)去掉STM32 最快速度连发串口助手直接刷屏肉眼可见丢数据——发送快于上位机接收就会丢。#停、*继续验证通过。五、中断方式现象跟任务一一模一样但底下机制不同任务一是主循环主动查字符任务二是主循环根本不查用HAL_UART_Receive_IT把接收中断挂上字符一到硬件自动打断 CPU、进回调处理。/* 先启动一次中断接收之后每收 1 字节都自动进回调 */HAL_UART_Receive_IT(huart1,g_rx_ch,1);while(1){if(g_paused0)/* 主循环只管发不查字符 */{HAL_UART_Transmit(huart1,(uint8_t*)msg,strlen(msg),1000);HAL_Delay(200);}}/* 接收完成回调HAL 每收满 1 个字节调用一次 */voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){if(huart-InstanceUSART1){if(g_rx_ch#)g_paused1;elseif(g_rx_ch*)g_paused0;HAL_UART_Receive_IT(huart1,g_rx_ch,1);/* 必须重新开否则只收一次 */}}别忘了在stm32f1xx_it.c里加串口中断入口和任务一唯一的区别就是 MspInit 里多开了 USART1 的 NVIC 中断voidUSART1_IRQHandler(void){HAL_UART_IRQHandler(huart1);}六、DMA 方式—— 含只发一句就停的坑DMA 的思路HAL_UART_Transmit_DMA启动一次数据由 DMA 硬件直接搬到串口发完在发送完成回调里立刻启动下一句实现无延时连续发送主循环彻底空着。USART1 的发送 DMA 固定用DMA1 通道 4。核心代码/* 发送完成回调发完这一句立刻启动下一句连续发送 */voidHAL_UART_TxCpltCallback(UART_HandleTypeDef*huart){if(huart-InstanceUSART1){g_tx_count;intlensprintf((char*)tx_buf,hello windows! DMA send #%lu\r\n,(unsignedlong)g_tx_count);HAL_UART_Transmit_DMA(huart1,tx_buf,len);![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b238d6d2518543f4aebe926a81fe22ee.gif#pic_center)}}intmain(void){HAL_Init();SystemClock_Config();MX_USART1_UART_Init();g_tx_count1;intlensprintf((char*)tx_buf,hello windows! DMA send #%lu\r\n,(unsignedlong)g_tx_count);HAL_UART_Transmit_DMA(huart1,tx_buf,len);/* 启动第一次 DMA */while(1){/* 主循环啥也不用干 */}}坑只发出 #1 就停了烧进去之后串口只蹦出一句#1就不动了按一下复位再蹦一句#1。我以为是 DMA 没配好折腾半天。最后是翻 HAL 源码找到的根因F1 的 HAL 里HAL_UART_Transmit_DMA用的是DMA 普通模式DMA 把最后一个字节搬完后并不会直接回调HAL_UART_TxCpltCallback而是干这么一件事——在UART_DMATransmitCplt里打开 USART1 的发送完成 TC中断// stm32f1xx_hal_uart.c 里的 UART_DMATransmitCpltDMA 普通模式分支ATOMIC_CLEAR_BIT(huart-Instance-CR3,USART_CR3_DMAT);// 关 DMA 请求ATOMIC_SET_BIT(huart-Instance-CR1,USART_CR1_TCIE);// 开 UART 的 TC 中断然后等 UART 把最后一个字节真正移位发完才由USART1 中断收尾USART1_IRQHandler → HAL_UART_IRQHandler → UART_EndTransmit_IT → 回调 HAL_UART_TxCpltCallback。我一开始只写了DMA1_Channel4_IRQHandler没写USART1_IRQHandler于是 DMA 搬完 → 打开 TC 中断 → 结果 USART1 中断没人接程序直接卡死所以只有第一句。补上这两处就好了/* MspInit 里除了 DMA 中断还要开 USART1 中断 */HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,0,0);HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);HAL_NVIC_SetPriority(USART1_IRQn,0,0);// 关键不能少HAL_NVIC_EnableIRQ(USART1_IRQn);/* stm32f1xx_it.c 里两个中断都得有 */voidDMA1_Channel4_IRQHandler(void){HAL_DMA_IRQHandler(hdma_usart1_tx);}voidUSART1_IRQHandler(void){HAL_UART_IRQHandler(huart1);}补完就能看到计数#1 #2 #3 …一路狂飙了。体会HAL 库是封装不是黑盒遇到异常就得敢去翻源码把中断是怎么链起来的搞清楚不然光靠猜能卡一晚上。七、三种方式到底差在哪三个版本波特率都是 115200每个 bit 一样快区别在每句之间隔多久以及谁在搬数据轮询 中断 DMA| 接收 主循环主动查 硬件打断 本实验只演示发送| 发送 CPU 阻塞发 CPU 阻塞发DMA 硬件搬| 主循环 边发边查 只管发空的| 每句间隔 200ms 200ms无延时连发| 输出速度 ~5 句/秒 ~5 句/秒几千句/秒一句话轮询是 CPU 追着数据跑中断是数据到了把 CPU 拽过来DMA 是数据自己搬、CPU 撒手不管。所以 DMA 版没有 200ms 延时、由硬件中断连续接力输出快了几百倍——这也是为什么老师问DMA 输出为什么那么快。八、Keil 逻辑分析仪测波特率配置步骤没示波器也能看时序Keil 自带软件仿真Options for Target → Debug左边选Use Simulator仿真器的 Dialog DLL 填DARMSTM.DLL、参数-pSTM32F103C8不填这个仿真器不会加载 STM32 外设模型逻辑分析仪认不到引脚F7 编译CtrlF5进调试纯仿真不连 ST-LinkF5运行View → Analysis Windows → Logic AnalyzerSetup 里加信号Signal 填PORTA.9PA9 USART1_TXDisplay Type 选BitRun 看波形。坑逻辑分析仪报 Unknown Signal两个原因我都踩了信号名写错一开始填GPIOA-ODR逻辑分析仪直接报Unknown Signal。Keil 的逻辑分析仪不认这种指针写法要用它自己的端口命名PORTA.9PORTA.x这种跟 8051 的老命名一样。DLL 没配切到 Use Simulator 后仿真器的 Dialog DLL 是空的得手动补DARMSTM.DLL -pSTM32F103C8。算波特率PA9 空闲是高电平发一个字符就是拉低 1 bit起始→ 8 个数据位 → 拉高 1 bit停止。量最窄的一段电平宽度就是 1 个 bit实测约8.68µs。理论也能精确算出来。USART1 在 APB2 上PCLK2 72MHz波特率 PCLK2 / (16 × USARTDIV) USARTDIV 72000000 / (16 × 115200) 39.062539.0625的整数部分 39 放进 BRR 的 12 位整数小数 0.0625 1/16 正好放进 4 位小数位所以BRR 0x271实际波特率72000000 / (16 × 39.0625) 115200 精确误差 0%原因就是 72MHz/16 4.5MHz被 39.0625 整除而且 0.0625 正好是 1/164 位小数位能精确表示。实测 8.68µs 反推也是 115200跟理论完全对上。九、踩过的坑汇总串口完全没反应先查 CH340 模块插没插。设备管理器里 COM 口显示幽灵设备CM_PROB_PHANTOM就是模块没插到电脑。烧录后不运行Flash Download 里没勾Reset and Run烧完芯片停在复位态。勾上或烧完按一下板子 RESET。DMA 只发一句就停缺USART1_IRQHandler详见第六节这个最隐蔽。逻辑分析仪 Unknown Signal信号名用PORTA.9别用GPIOA-ODR且 Dialog DLL 要配DARMSTM.DLL -pSTM32F103C8。Keil AC6 中文路径报错用户名是中文的话armclang 编译默认启动文件会报 “Unable to convert command-line to UTF-16”用 GNU 语法启动文件 MicroLIB 能绕开。附AI 在实验里帮了什么忙这次实验我用了大模型 AIClaude辅助主要帮了这些讲原理串口帧格式、TTL/RS232/RS485 区别、轮询/中断/DMA 三者区别AI 用类比“轮询像反复开门看快递中断像快递按门铃”讲得挺清楚。搭代码框架 注释三个工程的 HAL 代码骨架和逐段中文注释让我能看懂每行在干嘛。排错帮最大几个坑都是它帮我定位的——串口没反应查出是 CH340 没插、烧录不运行是没勾 Reset and Run、DMA 只发一句是缺 USART1 中断带我一起翻 HAL 源码、逻辑分析仪 Unknown Signal 是信号名和 DLL 的问题。算波特率 整理文档72MHz 下 115200 的 USARTDIV39.0625、BRR0x271 的完整推导以及这份博客的结构。反思AI 的结论我没有全盘照抄DMA 那个坑是跟着它一起读 HAL 源码、自己看懂中断链路才改对的。AI 能帮你更快定位问题、查资料、整理文档但真正掌握原理、判断它说得对不对还得靠自己去读代码、动手验证。合理用 AI 能省不少时间但不能替代自己动手和思考。
延伸阅读

更多相关文章

2026/10/16 9:02:23

【附源码】基于SpringBoot的在线骑行网站(源码+数据库+论文+答辩ppt一整套齐全)java开发springboot+vue框架javaweb,可做计算机毕业设计或课程设计

🙊作者简介:多年一线开发工作经验,分享技术代码帮助学生学习。自有计算机毕设的工作室团队,专注计算机毕设开发、定制、远程、文档编写指导等。 🍅 查看主页更多项目 | 计算机毕设工作室 🍅 🍅 …

2026/10/16 8:57:19

基于MATLAB的多特征融合火灾检测系统GUI实现

控制室里的监控画面往往是最枯燥的,但一旦画面里出现不该有的红色,谁都不敢大意。之前给某个厂区做安防监控需求评估时,对方问能不能用现有摄像头自动识别早期火情,不需要换硬件,最好快速出一版可演示的原型。当时我第…

2026/10/16 10:18:30

基于Python的动漫分析系统全攻略:从数据采集到深度学习建模

很多同学在选毕设题目的时候,一眼就被“基于Python的动漫分析系统”这种题目抓住了眼球。原因很简单:动漫是兴趣,Python是上手快,深度学习是大热点,这三个词叠在一起,摆在任何一个答辩现场,都比…

2026/10/16 10:18:30

Micromine 2016实操:建模制图开发与Win10/11兼容性全解析

做矿业软件这一行,手里的工具版本常常比很多人的工作年限还要长。Micromine 2016就是这样的存在——我最早在一处铜多金属矿的储量复核项目里接触它,当时项目组的老工程师用它出图、建模,电脑还是老款的Win7工作站。几年过去,操作…

2026/10/16 10:18:30

WPF TreeView 拖拽实现详解:从原理到避坑指南

简介:这份资源面向具备一定 WPF 基础的开发者,聚焦 TreeView 控件的拖放(Drag & Drop)功能实现,解决节点顺序调整、数据移动与复制等交互需求。压缩包共 12 个文件,约 11KB,以 6 个 cs 源码…

2026/10/16 10:18:30

Qt程序打包如何补全版本与公司信息:从qmake到Inno Setup全配置

1. 为什么Qt程序默认打包出来是个"三无"安装包 先说个我自己的经历。之前给某公司做的一个模拟项目X收尾,Qt 5.15写的Windows桌面工具,编译、调试、跑自动化测试都通过了,最后用Inno Setup打了个安装包发给测试组。结果对方打开安装…

2026/10/16 10:18:30

YOLO免环境训练工具全流程指南:从自动标注到模型转换

简介:这份资源面向深度学习目标检测方向的开发者与算法学习者,提供一套免环境搭建的YOLO系列训练与标注工具,解决从数据标注到模型训练、转换流程繁琐的问题。包内共14个文件,以txt技术解析、html说明页、doc文档及jpg示意图为主&…

2026/10/16 10:13:29

Gitee不只能存代码:从SSH到Pull Request评审的团队协作进阶指南

如果你的日常工作流还停留在“把Gitee当成免费网盘,clone下来push上去就完事”,那你可能只用了这个代码托管平台一半以上的能力。我在过去几年带过好几个小团队,从最开始互相clone压缩包传文件,到后来把需求管理、代码评审、自动构…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑