STM32F103 UART 第一层复习:USART1 收发、回显与默写测试

STM32F103 UART 第一层复习:USART1 收发、回显与默写测试

芯片/板卡:STM32F103C8T6 最小系统板

开发方式:Keil + STM32F10x 标准外设库 V3.5.0

对照工程:程序源码/STM32Project-有注释版/9-1 串口发送9-2 串口发送+接收

前置复习:已经完成 RCC、GPIO 第一层

整理日期:2026-09-11

本节边界:用标准库完成 USART1 轮询发送、轮询接收和单字节回显。寄存器只理解作用和库函数对应关系,不直接用寄存器写驱动;中断、DMA、环形缓冲区留到通过本测试以后。


1. 这一步只完成一个目标

不看原例程,允许查手册,使用标准库把 USART1 配置为 9600、8 位数据、无校验、1 位停止位、无硬件流控、收发模式 。上电向电脑发送 UART READY;电脑发送测试字节 0x55,单片机接收后原样回发,并在 OLED 上显示接收值以及 PASS/FAIL

完整流程如下,图故意按从上到下排列:
#mermaid-svg-de1j9iNEX6BbVJMw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-de1j9iNEX6BbVJMw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-de1j9iNEX6BbVJMw .error-icon{fill:#552222;}#mermaid-svg-de1j9iNEX6BbVJMw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-de1j9iNEX6BbVJMw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-de1j9iNEX6BbVJMw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-de1j9iNEX6BbVJMw .marker.cross{stroke:#333333;}#mermaid-svg-de1j9iNEX6BbVJMw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-de1j9iNEX6BbVJMw p{margin:0;}#mermaid-svg-de1j9iNEX6BbVJMw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-de1j9iNEX6BbVJMw .cluster-label text{fill:#333;}#mermaid-svg-de1j9iNEX6BbVJMw .cluster-label span{color:#333;}#mermaid-svg-de1j9iNEX6BbVJMw .cluster-label span p{background-color:transparent;}#mermaid-svg-de1j9iNEX6BbVJMw .label text,#mermaid-svg-de1j9iNEX6BbVJMw span{fill:#333;color:#333;}#mermaid-svg-de1j9iNEX6BbVJMw .node rect,#mermaid-svg-de1j9iNEX6BbVJMw .node circle,#mermaid-svg-de1j9iNEX6BbVJMw .node ellipse,#mermaid-svg-de1j9iNEX6BbVJMw .node polygon,#mermaid-svg-de1j9iNEX6BbVJMw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-de1j9iNEX6BbVJMw .rough-node .label text,#mermaid-svg-de1j9iNEX6BbVJMw .node .label text,#mermaid-svg-de1j9iNEX6BbVJMw .image-shape .label,#mermaid-svg-de1j9iNEX6BbVJMw .icon-shape .label{text-anchor:middle;}#mermaid-svg-de1j9iNEX6BbVJMw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-de1j9iNEX6BbVJMw .rough-node .label,#mermaid-svg-de1j9iNEX6BbVJMw .node .label,#mermaid-svg-de1j9iNEX6BbVJMw .image-shape .label,#mermaid-svg-de1j9iNEX6BbVJMw .icon-shape .label{text-align:center;}#mermaid-svg-de1j9iNEX6BbVJMw .node.clickable{cursor:pointer;}#mermaid-svg-de1j9iNEX6BbVJMw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-de1j9iNEX6BbVJMw .arrowheadPath{fill:#333333;}#mermaid-svg-de1j9iNEX6BbVJMw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-de1j9iNEX6BbVJMw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-de1j9iNEX6BbVJMw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-de1j9iNEX6BbVJMw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-de1j9iNEX6BbVJMw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-de1j9iNEX6BbVJMw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-de1j9iNEX6BbVJMw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-de1j9iNEX6BbVJMw .cluster text{fill:#333;}#mermaid-svg-de1j9iNEX6BbVJMw .cluster span{color:#333;}#mermaid-svg-de1j9iNEX6BbVJMw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-de1j9iNEX6BbVJMw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-de1j9iNEX6BbVJMw rect.text{fill:none;stroke-width:0;}#mermaid-svg-de1j9iNEX6BbVJMw .icon-shape,#mermaid-svg-de1j9iNEX6BbVJMw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-de1j9iNEX6BbVJMw .icon-shape p,#mermaid-svg-de1j9iNEX6BbVJMw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-de1j9iNEX6BbVJMw .icon-shape .label rect,#mermaid-svg-de1j9iNEX6BbVJMw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-de1j9iNEX6BbVJMw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-de1j9iNEX6BbVJMw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-de1j9iNEX6BbVJMw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否



开启 GPIOA 和 USART1 时钟
PA9 配置为复用推挽输出 TX
PA10 配置为上拉输入 RX
配置 USART1 为 9600 8N1 收发
使能 USART1
发送 UART READY
RXNE 是否置 1
读取 DR 得到接收字节
把该字节写回 DR
OLED 显示接收值
是否等于 0x55
显示 PASS
显示 FAIL

这份主代码比 RCC、GPIO 多两个小函数:UART1_SendByte()UART1_SendString()。这是串口最必要的封装,不涉及复杂协议。


2. 第一层与第二层的边界

第一层现在必须会 第二层以后再做
会接 TX、RX、GND 依据手册直接配置 USART 寄存器
会配置 9600 8N1 手算并直接写 BRR
会用标准库初始化 USART1 单步进入 USART_Init() 研究位操作
会发送一个字节和字符串 用 TXE 中断或 DMA 连续发送
会轮询 RXNE 并读出一个字节 中断接收、环形缓冲区、数据包状态机
会区分 TXE、TC、RXNE 系统处理 ORE、FE、NE、PE 等异常

第一层可以看寄存器图、说出每个关键位的作用,但不要花大量时间背地址、偏移和全部位定义。当前评价标准是:能独立写、能接线、能看到数据、能定位常见故障。


3. 硬件连接与通信参数

图 1 串口的 TX 与 RX 必须交叉连接,并且两端必须共地。

本次使用 USART1 默认引脚:

STM32F103C8T6 USB 转串口模块 方向 GPIO 模式
PA9 / USART1_TX RXD STM32 → 电脑 GPIO_Mode_AF_PP
PA10 / USART1_RX TXD 电脑 → STM32 GPIO_Mode_IPU
GND GND 公共参考地 必须连接

必须背会:

text 复制代码
发送接收要交叉:PA9(TX) 接模块 RXD,PA10(RX) 接模块 TXD。
两端必须共地。
使用 3.3 V TTL 串口电平,不能把 PA9/PA10 直接接传统 RS-232 电平。

图 2 异步串口一帧由起始位、数据位、可选校验位和停止位组成。

本实验统一使用:

text 复制代码
波特率:9600
数据位:8
校验位:无
停止位:1
硬件流控:无
简称:9600 8N1

9600 波特时,每一位约为 1 / 9600 = 104.17 μs。发送一个 8N1 字节实际包含 1 个起始位、8 个数据位、1 个停止位,共 10 位,约需 1.04 ms


4. USART1 的硬件数据通路

图 3 发送与接收各有数据寄存器和移位寄存器;软件通过统一的 USART_DR 地址访问它们。

4.1 发送发生了什么

#mermaid-svg-250E8xJ8PBsXLvvo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-250E8xJ8PBsXLvvo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-250E8xJ8PBsXLvvo .error-icon{fill:#552222;}#mermaid-svg-250E8xJ8PBsXLvvo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-250E8xJ8PBsXLvvo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-250E8xJ8PBsXLvvo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-250E8xJ8PBsXLvvo .marker.cross{stroke:#333333;}#mermaid-svg-250E8xJ8PBsXLvvo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-250E8xJ8PBsXLvvo p{margin:0;}#mermaid-svg-250E8xJ8PBsXLvvo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-250E8xJ8PBsXLvvo .cluster-label text{fill:#333;}#mermaid-svg-250E8xJ8PBsXLvvo .cluster-label span{color:#333;}#mermaid-svg-250E8xJ8PBsXLvvo .cluster-label span p{background-color:transparent;}#mermaid-svg-250E8xJ8PBsXLvvo .label text,#mermaid-svg-250E8xJ8PBsXLvvo span{fill:#333;color:#333;}#mermaid-svg-250E8xJ8PBsXLvvo .node rect,#mermaid-svg-250E8xJ8PBsXLvvo .node circle,#mermaid-svg-250E8xJ8PBsXLvvo .node ellipse,#mermaid-svg-250E8xJ8PBsXLvvo .node polygon,#mermaid-svg-250E8xJ8PBsXLvvo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-250E8xJ8PBsXLvvo .rough-node .label text,#mermaid-svg-250E8xJ8PBsXLvvo .node .label text,#mermaid-svg-250E8xJ8PBsXLvvo .image-shape .label,#mermaid-svg-250E8xJ8PBsXLvvo .icon-shape .label{text-anchor:middle;}#mermaid-svg-250E8xJ8PBsXLvvo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-250E8xJ8PBsXLvvo .rough-node .label,#mermaid-svg-250E8xJ8PBsXLvvo .node .label,#mermaid-svg-250E8xJ8PBsXLvvo .image-shape .label,#mermaid-svg-250E8xJ8PBsXLvvo .icon-shape .label{text-align:center;}#mermaid-svg-250E8xJ8PBsXLvvo .node.clickable{cursor:pointer;}#mermaid-svg-250E8xJ8PBsXLvvo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-250E8xJ8PBsXLvvo .arrowheadPath{fill:#333333;}#mermaid-svg-250E8xJ8PBsXLvvo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-250E8xJ8PBsXLvvo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-250E8xJ8PBsXLvvo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-250E8xJ8PBsXLvvo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-250E8xJ8PBsXLvvo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-250E8xJ8PBsXLvvo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-250E8xJ8PBsXLvvo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-250E8xJ8PBsXLvvo .cluster text{fill:#333;}#mermaid-svg-250E8xJ8PBsXLvvo .cluster span{color:#333;}#mermaid-svg-250E8xJ8PBsXLvvo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-250E8xJ8PBsXLvvo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-250E8xJ8PBsXLvvo rect.text{fill:none;stroke-width:0;}#mermaid-svg-250E8xJ8PBsXLvvo .icon-shape,#mermaid-svg-250E8xJ8PBsXLvvo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-250E8xJ8PBsXLvvo .icon-shape p,#mermaid-svg-250E8xJ8PBsXLvvo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-250E8xJ8PBsXLvvo .icon-shape .label rect,#mermaid-svg-250E8xJ8PBsXLvvo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-250E8xJ8PBsXLvvo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-250E8xJ8PBsXLvvo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-250E8xJ8PBsXLvvo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 程序调用 USART_SendData
数据写入 USART_DR/TDR
TXE 清 0
数据转入发送移位寄存器
TXE 置 1:可以写下一个字节
硬件从 PA9 逐位发送
停止位发送结束
TC 置 1:整个字节真正发完

  • TXE = 1:发送数据寄存器已经空,可以交付下一个字节。
  • TC = 1:数据寄存器和发送移位寄存器都空,最后一个停止位也已发完。
  • 连续发送字符串时通常等待 TXE;如果马上要关闭串口、切换半双工方向或进入低功耗,最后一个字节后应等待 TC

4.2 接收发生了什么

#mermaid-svg-tcs50a7OMVYeFzfz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tcs50a7OMVYeFzfz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tcs50a7OMVYeFzfz .error-icon{fill:#552222;}#mermaid-svg-tcs50a7OMVYeFzfz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tcs50a7OMVYeFzfz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tcs50a7OMVYeFzfz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tcs50a7OMVYeFzfz .marker.cross{stroke:#333333;}#mermaid-svg-tcs50a7OMVYeFzfz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tcs50a7OMVYeFzfz p{margin:0;}#mermaid-svg-tcs50a7OMVYeFzfz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tcs50a7OMVYeFzfz .cluster-label text{fill:#333;}#mermaid-svg-tcs50a7OMVYeFzfz .cluster-label span{color:#333;}#mermaid-svg-tcs50a7OMVYeFzfz .cluster-label span p{background-color:transparent;}#mermaid-svg-tcs50a7OMVYeFzfz .label text,#mermaid-svg-tcs50a7OMVYeFzfz span{fill:#333;color:#333;}#mermaid-svg-tcs50a7OMVYeFzfz .node rect,#mermaid-svg-tcs50a7OMVYeFzfz .node circle,#mermaid-svg-tcs50a7OMVYeFzfz .node ellipse,#mermaid-svg-tcs50a7OMVYeFzfz .node polygon,#mermaid-svg-tcs50a7OMVYeFzfz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tcs50a7OMVYeFzfz .rough-node .label text,#mermaid-svg-tcs50a7OMVYeFzfz .node .label text,#mermaid-svg-tcs50a7OMVYeFzfz .image-shape .label,#mermaid-svg-tcs50a7OMVYeFzfz .icon-shape .label{text-anchor:middle;}#mermaid-svg-tcs50a7OMVYeFzfz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tcs50a7OMVYeFzfz .rough-node .label,#mermaid-svg-tcs50a7OMVYeFzfz .node .label,#mermaid-svg-tcs50a7OMVYeFzfz .image-shape .label,#mermaid-svg-tcs50a7OMVYeFzfz .icon-shape .label{text-align:center;}#mermaid-svg-tcs50a7OMVYeFzfz .node.clickable{cursor:pointer;}#mermaid-svg-tcs50a7OMVYeFzfz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tcs50a7OMVYeFzfz .arrowheadPath{fill:#333333;}#mermaid-svg-tcs50a7OMVYeFzfz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tcs50a7OMVYeFzfz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tcs50a7OMVYeFzfz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tcs50a7OMVYeFzfz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tcs50a7OMVYeFzfz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tcs50a7OMVYeFzfz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tcs50a7OMVYeFzfz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tcs50a7OMVYeFzfz .cluster text{fill:#333;}#mermaid-svg-tcs50a7OMVYeFzfz .cluster span{color:#333;}#mermaid-svg-tcs50a7OMVYeFzfz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tcs50a7OMVYeFzfz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tcs50a7OMVYeFzfz rect.text{fill:none;stroke-width:0;}#mermaid-svg-tcs50a7OMVYeFzfz .icon-shape,#mermaid-svg-tcs50a7OMVYeFzfz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tcs50a7OMVYeFzfz .icon-shape p,#mermaid-svg-tcs50a7OMVYeFzfz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tcs50a7OMVYeFzfz .icon-shape .label rect,#mermaid-svg-tcs50a7OMVYeFzfz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tcs50a7OMVYeFzfz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tcs50a7OMVYeFzfz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tcs50a7OMVYeFzfz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} PA10 检测到低电平起始位
USART 按波特率采样数据位
完整字节进入接收数据寄存器 RDR
RXNE 置 1
程序发现 RXNE 为 1
调用 USART_ReceiveData 读取 DR
RXNE 清 0
等待下一个字节

必须形成条件反射:

text 复制代码
发送:写 DR,等 TXE。
接收:看 RXNE,读 DR。

5. 必须理解的寄存器

第一层不直接写这些寄存器,但要知道标准库最终改了什么。

寄存器 本次关键位/字段 简单作用 对应代码
USART_SR TXETCRXNE 报告发送和接收状态 USART_GetFlagStatus()
USART_DR DR[8:0] 写入时发送,读取时取接收数据 USART_SendData()USART_ReceiveData()
USART_BRR 整数和小数分频字段 根据外设时钟产生目标波特率 USART_InitStructure.USART_BaudRate
USART_CR1 UETEREMPCEPSRXNEIE 总使能、收发、字长、校验和接收中断 USART_Init()USART_Cmd()USART_ITConfig()
USART_CR2 STOP 选择停止位数量 USART_StopBits_1
USART_CR3 RTSECTSEDMATDMAR 硬件流控与 DMA 本次选择无流控,不使用 DMA

5.1 USART_SR 中最需要认识的标志

标志 含义 第一层如何处理
TXE 发送数据寄存器空 每发一个字节后等待它置 1
TC 整帧发送完成 认识即可;最后必须真正发完时使用
RXNE 接收数据寄存器非空 置 1 后立即读取 DR
ORE 接收溢出 前一字节未及时读取,新字节又来了;当前先会判断原因
FE 帧错误 常见于波特率、停止位或线路异常
NE 噪声错误 常见于干扰或接线质量差
PE 奇偶校验错误 两端校验设置不一致或数据错误

5.2 库函数如何落到寄存器

#mermaid-svg-bvSCKPeoplPgyAUN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bvSCKPeoplPgyAUN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bvSCKPeoplPgyAUN .error-icon{fill:#552222;}#mermaid-svg-bvSCKPeoplPgyAUN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bvSCKPeoplPgyAUN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bvSCKPeoplPgyAUN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bvSCKPeoplPgyAUN .marker.cross{stroke:#333333;}#mermaid-svg-bvSCKPeoplPgyAUN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bvSCKPeoplPgyAUN p{margin:0;}#mermaid-svg-bvSCKPeoplPgyAUN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bvSCKPeoplPgyAUN .cluster-label text{fill:#333;}#mermaid-svg-bvSCKPeoplPgyAUN .cluster-label span{color:#333;}#mermaid-svg-bvSCKPeoplPgyAUN .cluster-label span p{background-color:transparent;}#mermaid-svg-bvSCKPeoplPgyAUN .label text,#mermaid-svg-bvSCKPeoplPgyAUN span{fill:#333;color:#333;}#mermaid-svg-bvSCKPeoplPgyAUN .node rect,#mermaid-svg-bvSCKPeoplPgyAUN .node circle,#mermaid-svg-bvSCKPeoplPgyAUN .node ellipse,#mermaid-svg-bvSCKPeoplPgyAUN .node polygon,#mermaid-svg-bvSCKPeoplPgyAUN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bvSCKPeoplPgyAUN .rough-node .label text,#mermaid-svg-bvSCKPeoplPgyAUN .node .label text,#mermaid-svg-bvSCKPeoplPgyAUN .image-shape .label,#mermaid-svg-bvSCKPeoplPgyAUN .icon-shape .label{text-anchor:middle;}#mermaid-svg-bvSCKPeoplPgyAUN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bvSCKPeoplPgyAUN .rough-node .label,#mermaid-svg-bvSCKPeoplPgyAUN .node .label,#mermaid-svg-bvSCKPeoplPgyAUN .image-shape .label,#mermaid-svg-bvSCKPeoplPgyAUN .icon-shape .label{text-align:center;}#mermaid-svg-bvSCKPeoplPgyAUN .node.clickable{cursor:pointer;}#mermaid-svg-bvSCKPeoplPgyAUN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bvSCKPeoplPgyAUN .arrowheadPath{fill:#333333;}#mermaid-svg-bvSCKPeoplPgyAUN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bvSCKPeoplPgyAUN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bvSCKPeoplPgyAUN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bvSCKPeoplPgyAUN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bvSCKPeoplPgyAUN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bvSCKPeoplPgyAUN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bvSCKPeoplPgyAUN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bvSCKPeoplPgyAUN .cluster text{fill:#333;}#mermaid-svg-bvSCKPeoplPgyAUN .cluster span{color:#333;}#mermaid-svg-bvSCKPeoplPgyAUN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bvSCKPeoplPgyAUN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bvSCKPeoplPgyAUN rect.text{fill:none;stroke-width:0;}#mermaid-svg-bvSCKPeoplPgyAUN .icon-shape,#mermaid-svg-bvSCKPeoplPgyAUN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bvSCKPeoplPgyAUN .icon-shape p,#mermaid-svg-bvSCKPeoplPgyAUN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bvSCKPeoplPgyAUN .icon-shape .label rect,#mermaid-svg-bvSCKPeoplPgyAUN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bvSCKPeoplPgyAUN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bvSCKPeoplPgyAUN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bvSCKPeoplPgyAUN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 填写 USART_InitTypeDef
USART_Init
配置 BRR 波特率
配置 CR1 字长/校验/收发
配置 CR2 停止位
配置 CR3 硬件流控
USART_Cmd ENABLE
置 CR1.UE 使能外设

注意:USART_Init() 完成参数配置,但最后仍要调用 USART_Cmd(USART1, ENABLE) 打开 USART。


6. 必须练习的标准库函数

函数 作用 本次必须会到什么程度
RCC_APB2PeriphClockCmd() 开启 GPIOA 和 USART1 时钟 能写出两个外设按位或后一起使能
GPIO_Init() 配置 PA9、PA10 能区分 TX 的 AF_PP 与 RX 的输入模式
USART_Init() 按结构体参数初始化 USART 能独立填写 9600 8N1、无流控、收发模式
USART_Cmd() 使能或关闭 USART 知道应在配置完成后调用
USART_SendData() DR 写一个待发送数据 会写单字节发送函数
USART_GetFlagStatus() 查询状态标志 会查询 TXERXNE,会解释 TC
USART_ReceiveData() DR 读取接收数据 会在 RXNE 置位后读取,并转为 uint8_t

本次只认识、不要求默写:

  • USART_StructInit():给初始化结构体填写默认值;
  • USART_ITConfig():开启或关闭 USART 中断源,例如 RXNE 中断;
  • USART_GetITStatus():在中断服务函数中判断是哪一个中断源;
  • USART_ClearITPendingBit():清除部分中断挂起位;对于 RXNE,正常读取 DR 已会清除 RXNE,不要机械地重复清除;
  • USART_ClearFlag():清除允许由软件清除的状态标志,不能把所有标志都当作同一种清除方式;
  • USART_DeInit():恢复外设寄存器到复位状态,普通上电初始化不需要先调用。

7. 初始化模板:按六步记忆

text 复制代码
1. 开 GPIOA 和 USART1 时钟
2. PA9 配置为复用推挽输出
3. PA10 配置为上拉输入
4. 填写 USART_InitTypeDef:9600 8N1、无流控、收发
5. USART_Init 把配置写入寄存器
6. USART_Cmd 使能 USART1

在课程标准工程中,启动文件会在进入 main() 之前调用 SystemInit(),因此本例不在 main() 中重复调用。若以后换了工程模板,应先确认系统时钟是否正确;系统时钟错误会让 USART_Init() 计算出的实际波特率偏离目标,常见现象就是乱码。

7.1 为什么 USART1 和 GPIOA 都在 APB2

本芯片上 USART1 与 GPIOA 都挂在 APB2,因此写:

c 复制代码
RCC_APB2PeriphClockCmd(
    RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,
    ENABLE
);

如果以后迁移到 USART2,要改为 PA2/PA3,并用 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE) 开 USART2 时钟;GPIOA 时钟仍由 APB2 开启。这个迁移题可以检验 RCC 是否真正理解。

7.2 为什么 PA9 是 GPIO_Mode_AF_PP

PA9 的电平由 USART1 外设控制,而不是由普通 GPIO 输出寄存器直接控制,所以使用"复用功能";串口 TX 需要主动输出高、低电平,所以使用推挽输出。

7.3 为什么 PA10 使用输入模式

PA10 接收外部 USB 转串口模块送来的电平,必须配置为输入。课程例程使用 GPIO_Mode_IPU,本复习代码保持一致。输入模式下 GPIO_Speed 不决定输入速度,结构体中给它赋值只是避免成员遗留旧值。


8. 第一层完整默写代码:轮询收发回显

使用前提:工程已经包含课程 OLED 驱动;串口助手选择 USART1 对应的 USB 转串口端口,参数为 9600 8N1;发送模式选择 HEX,并发送 55

c 复制代码
#include "stm32f10x.h"                  // STM32F10x 标准外设库总头文件
#include "OLED.h"                       // 课程 OLED 显示驱动

#define UART_TEST_BYTE  0x55U            // 本次规定的测试字节

static void UART1_Init(void);            // USART1 初始化函数声明
static void UART1_SendByte(uint8_t data); // 发送一个字节函数声明
static void UART1_SendString(const char *str); // 发送字符串函数声明

int main(void)
{
    uint8_t rx_data;                     // 保存最近收到的一个字节

    OLED_Init();                         // 初始化 OLED,供观察结果
    UART1_Init();                        // 初始化 PA9、PA10 和 USART1

    OLED_ShowString(1, 1, "UART1 9600"); // 第1行显示串口参数
    OLED_ShowString(2, 1, "RX:00");      // 第2行预留接收值
    OLED_ShowString(3, 1, "EXP:55");     // 第3行显示期望字节
    OLED_ShowString(4, 1, "STATE:WAIT"); // 尚未收到数据

    UART1_SendString("UART READY\r\n"); // 上电后向电脑发送启动提示

    while (1)
    {
        // RXNE=1 表示接收数据寄存器中已有一个未读取字节
        if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
        {
            // 读取 DR 取走数据;正常读取后 RXNE 会被清除
            rx_data = (uint8_t)USART_ReceiveData(USART1);

            // 把收到的数据原样发回电脑,构成单字节回显
            UART1_SendByte(rx_data);

            // 在 OLED 上用两位十六进制显示本次接收值
            OLED_ShowHexNum(2, 4, rx_data, 2);

            // 收到规定测试字节 0x55 才判定本轮通过
            if (rx_data == UART_TEST_BYTE)
            {
                OLED_ShowString(4, 1, "STATE:PASS");
            }
            else
            {
                OLED_ShowString(4, 1, "STATE:FAIL");
            }
        }
    }
}

static void UART1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // GPIO 配置结构体
    USART_InitTypeDef USART_InitStructure; // USART 配置结构体

    // GPIOA 与 USART1 都挂在 APB2,总线时钟必须先开启
    RCC_APB2PeriphClockCmd(
        RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,
        ENABLE
    );

    // PA9 是 USART1_TX,由外设控制并主动输出高低电平
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // PA10 是 USART1_RX,课程例程采用内部上拉输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 9600 8N1、无硬件流控,同时开启发送和接收
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl =
        USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);

    // 最后置 CR1.UE,真正使能 USART1
    USART_Cmd(USART1, ENABLE);
}

static void UART1_SendByte(uint8_t data)
{
    // 把一个字节写入 USART1 数据寄存器
    USART_SendData(USART1, data);

    // 等待发送数据寄存器变空,之后才能安全交付下一个字节
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
        // 硬件发送期间在此等待
    }
}

static void UART1_SendString(const char *str)
{
    // C 字符串以 '\0' 结尾,逐字节调用发送函数
    while (*str != '\0')
    {
        UART1_SendByte((uint8_t)*str);
        str++;
    }
}

9. 逐段讲解:每行代码为什么存在

9.1 头文件、宏和函数声明

代码 含义
#include "stm32f10x.h" 获得 RCC、GPIO、USART 类型、常量和库函数声明
#include "OLED.h" 获得 OLED 初始化与显示函数声明
#define UART_TEST_BYTE 0x55U 把测试值集中定义;以后改成 0xA5U 只改一处
static void UART1_Init(void); 声明当前文件内部使用的初始化函数
static void UART1_SendByte(...) 声明最小发送单位:一个字节
static void UART1_SendString(...) 声明字符串发送函数,它会重复调用单字节发送

9.2 主函数

代码 必须能说出的解释
uint8_t rx_data; 一个串口数据位宽为 8 位,所以用 8 位无符号变量保存
OLED_Init(); 初始化观察工具;不是 USART 必需步骤
UART1_Init(); 一次完成时钟、引脚、参数和 USART 使能
UART1_SendString("UART READY\r\n"); 上电提示;\r\n 让多数串口终端换到下一行
while (1) 裸机程序持续运行,不从 main 返回
USART_GetFlagStatus(...RXNE) 轮询判断硬件是否收到新字节,不读取时不处理
USART_ReceiveData(USART1) 从 DR 取数据;函数返回类型较宽,显式转成 uint8_t
UART1_SendByte(rx_data) 原样回发,使电脑能验证接收路径和发送路径都工作
OLED_ShowHexNum(...) 显示真正收到的十六进制值,便于判断乱码或配置错误
rx_data == UART_TEST_BYTE 软件比较实际值与期望值,输出明确 PASS/FAIL

9.3 初始化函数

代码/配置 必须能说出的解释
RCC_APB2Periph_GPIOA 没有 GPIOA 时钟,PA9/PA10 配置不会生效
RCC_APB2Periph_USART1 没有 USART1 时钟,USART 寄存器和收发硬件不能工作
PA9 + GPIO_Mode_AF_PP USART1_TX 的复用推挽输出
PA10 + GPIO_Mode_IPU USART1_RX 的上拉输入
USART_BaudRate = 9600 库函数根据 USART1 的外设时钟计算 BRR
USART_WordLength_8b 一帧包含 8 个有效数据位;本次不使用校验
USART_StopBits_1 使用 1 位停止位
USART_Parity_No 不添加奇偶校验位
USART_HardwareFlowControl_None 不使用 RTS/CTS,两根数据线即可
`USART_Mode_Tx USART_Mode_Rx`
USART_Init(...) 把结构体内容转换为 BRR、CR1、CR2、CR3 配置
USART_Cmd(...ENABLE) 最后使能 USART;漏写会导致完全不能收发

9.4 发送函数

代码 必须能说出的解释
USART_SendData(USART1, data) 将数据写入 DR/TDR,硬件开始安排发送
while (...TXE == RESET) DR 尚未空时等待,防止过快写入覆盖数据
查询 TXE 而不是 RXNE TXE 属于发送路径,RXNE 属于接收路径

9.5 字符串发送函数

代码 必须能说出的解释
while (*str != '\0') 当前字符不是字符串结束符时继续发送
UART1_SendByte((uint8_t)*str) 发送当前字符
str++ 指针移动到下一个字符;漏写会无限发送同一字符

10. 结构体六个成员的背诵模板

不要背散乱单词,按"速、长、停、校、流、向"记忆:

c 复制代码
USART_InitStructure.USART_BaudRate = 9600;                    // 速:波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;   // 长:字长
USART_InitStructure.USART_StopBits = USART_StopBits_1;        // 停:停止位
USART_InitStructure.USART_Parity = USART_Parity_No;            // 校:校验
USART_InitStructure.USART_HardwareFlowControl =
    USART_HardwareFlowControl_None;                            // 流:流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;// 向:收发方向

口令:

text 复制代码
九千六,八位长,一位停,无校验,无流控,收加发。

11. 完整测试方法

11.1 测试准备

  • USB 转串口模块使用 3.3 V TTL 电平;
  • PA9 接模块 RXD,PA10 接模块 TXD,GND 接 GND;
  • 串口助手选择正确 COM 口;
  • 参数选择 9600、8 数据位、无校验、1 停止位;
  • 为了发送 0x55,串口助手选择 HEX 发送,而不是文本发送。

文本发送 55 实际发送两个 ASCII 字节 0x35 0x35;HEX 发送 55 才是一个字节 0x55

11.2 正常测试流程

#mermaid-svg-mXhzFnY8mIV6Zlcc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mXhzFnY8mIV6Zlcc .error-icon{fill:#552222;}#mermaid-svg-mXhzFnY8mIV6Zlcc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mXhzFnY8mIV6Zlcc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .marker.cross{stroke:#333333;}#mermaid-svg-mXhzFnY8mIV6Zlcc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mXhzFnY8mIV6Zlcc p{margin:0;}#mermaid-svg-mXhzFnY8mIV6Zlcc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster-label text{fill:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster-label span{color:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster-label span p{background-color:transparent;}#mermaid-svg-mXhzFnY8mIV6Zlcc .label text,#mermaid-svg-mXhzFnY8mIV6Zlcc span{fill:#333;color:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .node rect,#mermaid-svg-mXhzFnY8mIV6Zlcc .node circle,#mermaid-svg-mXhzFnY8mIV6Zlcc .node ellipse,#mermaid-svg-mXhzFnY8mIV6Zlcc .node polygon,#mermaid-svg-mXhzFnY8mIV6Zlcc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .rough-node .label text,#mermaid-svg-mXhzFnY8mIV6Zlcc .node .label text,#mermaid-svg-mXhzFnY8mIV6Zlcc .image-shape .label,#mermaid-svg-mXhzFnY8mIV6Zlcc .icon-shape .label{text-anchor:middle;}#mermaid-svg-mXhzFnY8mIV6Zlcc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .rough-node .label,#mermaid-svg-mXhzFnY8mIV6Zlcc .node .label,#mermaid-svg-mXhzFnY8mIV6Zlcc .image-shape .label,#mermaid-svg-mXhzFnY8mIV6Zlcc .icon-shape .label{text-align:center;}#mermaid-svg-mXhzFnY8mIV6Zlcc .node.clickable{cursor:pointer;}#mermaid-svg-mXhzFnY8mIV6Zlcc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .arrowheadPath{fill:#333333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mXhzFnY8mIV6Zlcc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mXhzFnY8mIV6Zlcc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mXhzFnY8mIV6Zlcc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster text{fill:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc .cluster span{color:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mXhzFnY8mIV6Zlcc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mXhzFnY8mIV6Zlcc rect.text{fill:none;stroke-width:0;}#mermaid-svg-mXhzFnY8mIV6Zlcc .icon-shape,#mermaid-svg-mXhzFnY8mIV6Zlcc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mXhzFnY8mIV6Zlcc .icon-shape p,#mermaid-svg-mXhzFnY8mIV6Zlcc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mXhzFnY8mIV6Zlcc .icon-shape .label rect,#mermaid-svg-mXhzFnY8mIV6Zlcc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mXhzFnY8mIV6Zlcc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mXhzFnY8mIV6Zlcc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mXhzFnY8mIV6Zlcc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 下载程序并复位
电脑收到 UART READY
串口助手以 HEX 发送 55
STM32 RXNE 置位
程序读到 0x55
STM32 回发 0x55
电脑接收区显示 55
OLED 显示 RX:55
OLED 显示 STATE:PASS

一次通过必须同时看到:

  1. 电脑上电后收到 UART READY
  2. 电脑发送 HEX 55 后,又收到 HEX 55
  3. OLED 显示 RX:55
  4. OLED 显示 STATE:PASS

这四项分别验证:初始化与发送、接收与回显、实际数据观察、软件比较。

11.3 反向测试

电脑再发送 HEX A5

  • 电脑应收到回显 A5,证明通信仍正常;
  • OLED 应显示 RX:A5
  • 因为期望值仍为 0x55,状态应显示 FAIL

这个 FAIL 是正确结果,它证明比较逻辑不是永远显示 PASS。


12. "20% 看、80% 调"的重复复习安排

每轮不要重新看完整视频。先写、先接、先观察,再针对错误查资料。

第 1 轮:开卷抄写并跑通

目标:认识完整链路,不追求背诵。

  1. 对照本笔记输入代码;
  2. 在每一段旁边说出"时钟、TX 引脚、RX 引脚、参数、使能、发送、接收";
  3. 完成 55 → 回显 55 → PASS
  4. 主动发送 A5,看到 FAIL

第 2 轮:只看六步提示默写

只允许看以下提示:

text 复制代码
时钟 → PA9 → PA10 → USART结构体 → USART_Init → USART_Cmd
发送:SendData → 等TXE
接收:看RXNE → ReceiveData

写完再与完整代码比较,记录漏项,不要边写边翻原例程。

第 3 轮:完全脱离原代码

允许查官方手册和函数声明,但不看 9-19-2 原例程,也不看本笔记的完整代码。要求在 30~45 分钟内完成接线、编码、下载与验证。

第 4 轮:改参数,证明不是死记

  1. 把测试值改为 0xA5U
  2. 把波特率改为 115200
  3. 同步修改串口助手参数;
  4. 完成 A5 → 回显 A5 → PASS
  5. 故意让电脑仍保持 9600,观察乱码或通信失败,再恢复一致。

第 5 轮:故障注入与定位

每次只制造一个错误,然后依据现象定位:

人为错误 可能现象 应想到的原因
拔掉 GND 不稳定、乱码或完全不通 两端没有共同电平参考
TX 与 TX、RX 与 RX 相接 电脑收不到或不能回显 TX/RX 未交叉
串口助手改成错误波特率 乱码 两端位时间不一致
注释掉 USART1 时钟 完全不能收发 外设无时钟
PA9 改为普通输入 电脑收不到 STM32 发送 TX 引脚模式错误
PA10 改为输出 STM32 收不到,且可能产生电气冲突 RX 引脚方向错误
漏掉 USART_Cmd() 完全不能收发 CR1.UE 未使能
发送后不等 TXE 并快速连续写 字符可能丢失 写 DR 节奏错误

每修复一个问题,要用一句话记录:

text 复制代码
现象 → 我检查了什么 → 根因是什么 → 改哪一行恢复

13. 第一层通过标准

满足以下条件后,可以认为 UART 第一层的"第一步"通过:

  • 不看课程原例程,能独立写出 USART1 初始化;
  • 能正确写出 PA9 AF_PP、PA10 输入模式;
  • 能写出 9600 8N1、无流控、收发模式六项参数;
  • 能写出 USART_SendData() 加等待 TXE 的单字节发送函数;
  • 能用 RXNE 判断收到数据,并调用 USART_ReceiveData()
  • 能完成上电字符串、单字节接收、回显和 OLED PASS/FAIL;
  • 能解释 TXE、TC、RXNE 的区别;
  • 能解释标准库配置最终落到 SR、DR、BRR、CR1、CR2、CR3;
  • 遇到无数据或乱码时,会按"接线 → 共地 → 参数 → 时钟 → GPIO → USART 使能"顺序排查;
  • 能把测试值和波特率改掉后重新跑通,而不是只能复现固定答案。

如果只能背出初始化、实际不能回显和定位问题,还不能算通过。第一层要求的是:独立写、调、改、查资料和定位问题。


14. 通过后的小升级:先认识中断,不急着背

轮询代码必须由 CPU 反复查看 RXNE。通过本节测试后,可以再看课程 9-2 串口发送+接收 的 RXNE 中断版本:
#mermaid-svg-bVss7G6wSYN5fx1A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bVss7G6wSYN5fx1A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bVss7G6wSYN5fx1A .error-icon{fill:#552222;}#mermaid-svg-bVss7G6wSYN5fx1A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bVss7G6wSYN5fx1A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bVss7G6wSYN5fx1A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bVss7G6wSYN5fx1A .marker.cross{stroke:#333333;}#mermaid-svg-bVss7G6wSYN5fx1A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bVss7G6wSYN5fx1A p{margin:0;}#mermaid-svg-bVss7G6wSYN5fx1A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bVss7G6wSYN5fx1A .cluster-label text{fill:#333;}#mermaid-svg-bVss7G6wSYN5fx1A .cluster-label span{color:#333;}#mermaid-svg-bVss7G6wSYN5fx1A .cluster-label span p{background-color:transparent;}#mermaid-svg-bVss7G6wSYN5fx1A .label text,#mermaid-svg-bVss7G6wSYN5fx1A span{fill:#333;color:#333;}#mermaid-svg-bVss7G6wSYN5fx1A .node rect,#mermaid-svg-bVss7G6wSYN5fx1A .node circle,#mermaid-svg-bVss7G6wSYN5fx1A .node ellipse,#mermaid-svg-bVss7G6wSYN5fx1A .node polygon,#mermaid-svg-bVss7G6wSYN5fx1A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bVss7G6wSYN5fx1A .rough-node .label text,#mermaid-svg-bVss7G6wSYN5fx1A .node .label text,#mermaid-svg-bVss7G6wSYN5fx1A .image-shape .label,#mermaid-svg-bVss7G6wSYN5fx1A .icon-shape .label{text-anchor:middle;}#mermaid-svg-bVss7G6wSYN5fx1A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bVss7G6wSYN5fx1A .rough-node .label,#mermaid-svg-bVss7G6wSYN5fx1A .node .label,#mermaid-svg-bVss7G6wSYN5fx1A .image-shape .label,#mermaid-svg-bVss7G6wSYN5fx1A .icon-shape .label{text-align:center;}#mermaid-svg-bVss7G6wSYN5fx1A .node.clickable{cursor:pointer;}#mermaid-svg-bVss7G6wSYN5fx1A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bVss7G6wSYN5fx1A .arrowheadPath{fill:#333333;}#mermaid-svg-bVss7G6wSYN5fx1A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bVss7G6wSYN5fx1A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bVss7G6wSYN5fx1A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bVss7G6wSYN5fx1A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bVss7G6wSYN5fx1A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bVss7G6wSYN5fx1A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bVss7G6wSYN5fx1A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bVss7G6wSYN5fx1A .cluster text{fill:#333;}#mermaid-svg-bVss7G6wSYN5fx1A .cluster span{color:#333;}#mermaid-svg-bVss7G6wSYN5fx1A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bVss7G6wSYN5fx1A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bVss7G6wSYN5fx1A rect.text{fill:none;stroke-width:0;}#mermaid-svg-bVss7G6wSYN5fx1A .icon-shape,#mermaid-svg-bVss7G6wSYN5fx1A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bVss7G6wSYN5fx1A .icon-shape p,#mermaid-svg-bVss7G6wSYN5fx1A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bVss7G6wSYN5fx1A .icon-shape .label rect,#mermaid-svg-bVss7G6wSYN5fx1A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bVss7G6wSYN5fx1A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bVss7G6wSYN5fx1A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bVss7G6wSYN5fx1A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} USART_ITConfig 开启 RXNE 中断
NVIC_Init 允许 USART1_IRQn
收到字节后硬件置 RXNE
CPU 进入 USART1_IRQHandler
USART_GetITStatus 判断来源
USART_ReceiveData 读取 DR
保存数据并置软件标志
主循环读取软件标志并处理

当前只要能讲出流程即可,不把中断代码加入本次闭卷默写,避免 UART 第一步与 NVIC、共享变量、缓冲区问题混在一起。


15. 常见问题速查

现象 优先检查
电脑完全收不到 UART READY COM 口、共地、PA9→RXD、GPIOA/USART1 时钟、PA9 模式、USART_Cmd
能收到启动信息,但发 55 没回显 PA10←TXD、PA10 输入模式、USART 是否包含 Rx、是否检查 RXNE
收到乱码 两端波特率/数据位/校验/停止位、系统时钟是否正确、电平标准
OLED 显示 35 而不是 55 串口助手用了文本发送;字符 '5' 的 ASCII 值是 0x35
只收到一次,之后收不到 是否读取 DR 清 RXNE,是否发生 ORE,代码是否长期阻塞
回显正确但 OLED 显示 FAIL 检查期望宏、HEX/文本发送方式和比较值
字符串不换行 终端换行设置,或是否发送 \r\n

推荐排查顺序:
#mermaid-svg-jDyRctDFk6wSAMgz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jDyRctDFk6wSAMgz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jDyRctDFk6wSAMgz .error-icon{fill:#552222;}#mermaid-svg-jDyRctDFk6wSAMgz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jDyRctDFk6wSAMgz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jDyRctDFk6wSAMgz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jDyRctDFk6wSAMgz .marker.cross{stroke:#333333;}#mermaid-svg-jDyRctDFk6wSAMgz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jDyRctDFk6wSAMgz p{margin:0;}#mermaid-svg-jDyRctDFk6wSAMgz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jDyRctDFk6wSAMgz .cluster-label text{fill:#333;}#mermaid-svg-jDyRctDFk6wSAMgz .cluster-label span{color:#333;}#mermaid-svg-jDyRctDFk6wSAMgz .cluster-label span p{background-color:transparent;}#mermaid-svg-jDyRctDFk6wSAMgz .label text,#mermaid-svg-jDyRctDFk6wSAMgz span{fill:#333;color:#333;}#mermaid-svg-jDyRctDFk6wSAMgz .node rect,#mermaid-svg-jDyRctDFk6wSAMgz .node circle,#mermaid-svg-jDyRctDFk6wSAMgz .node ellipse,#mermaid-svg-jDyRctDFk6wSAMgz .node polygon,#mermaid-svg-jDyRctDFk6wSAMgz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jDyRctDFk6wSAMgz .rough-node .label text,#mermaid-svg-jDyRctDFk6wSAMgz .node .label text,#mermaid-svg-jDyRctDFk6wSAMgz .image-shape .label,#mermaid-svg-jDyRctDFk6wSAMgz .icon-shape .label{text-anchor:middle;}#mermaid-svg-jDyRctDFk6wSAMgz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jDyRctDFk6wSAMgz .rough-node .label,#mermaid-svg-jDyRctDFk6wSAMgz .node .label,#mermaid-svg-jDyRctDFk6wSAMgz .image-shape .label,#mermaid-svg-jDyRctDFk6wSAMgz .icon-shape .label{text-align:center;}#mermaid-svg-jDyRctDFk6wSAMgz .node.clickable{cursor:pointer;}#mermaid-svg-jDyRctDFk6wSAMgz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jDyRctDFk6wSAMgz .arrowheadPath{fill:#333333;}#mermaid-svg-jDyRctDFk6wSAMgz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jDyRctDFk6wSAMgz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jDyRctDFk6wSAMgz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jDyRctDFk6wSAMgz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jDyRctDFk6wSAMgz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jDyRctDFk6wSAMgz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jDyRctDFk6wSAMgz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jDyRctDFk6wSAMgz .cluster text{fill:#333;}#mermaid-svg-jDyRctDFk6wSAMgz .cluster span{color:#333;}#mermaid-svg-jDyRctDFk6wSAMgz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jDyRctDFk6wSAMgz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jDyRctDFk6wSAMgz rect.text{fill:none;stroke-width:0;}#mermaid-svg-jDyRctDFk6wSAMgz .icon-shape,#mermaid-svg-jDyRctDFk6wSAMgz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jDyRctDFk6wSAMgz .icon-shape p,#mermaid-svg-jDyRctDFk6wSAMgz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jDyRctDFk6wSAMgz .icon-shape .label rect,#mermaid-svg-jDyRctDFk6wSAMgz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jDyRctDFk6wSAMgz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jDyRctDFk6wSAMgz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jDyRctDFk6wSAMgz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 确认串口助手和 COM 口
确认 9600 8N1
确认共地和 TX/RX 交叉
确认 GPIOA/USART1 时钟
确认 PA9/PA10 模式
确认 USART_Init 六项
确认 USART_Cmd 已使能
观察 TXE/RXNE 和实际接收值


16. 官方手册定位与具体页码

以下页码均指本地 PDF 阅读器显示的 PDF 页码,不是纸质文档页脚编号。

16.1 《STM32F10xxx参考手册(中文)》

要查的内容 PDF 页码 本节用处
USART 章节、主要特性和基本结构 516~523 理解异步收发器、发送器、接收器和数据帧
波特率产生与计算 525 理解外设时钟与波特率关系
USART 中断请求 538 通过轮询测试后学习 RXNE 中断时查阅
USART_SR 状态寄存器 540~541 查 TXE、TC、RXNE、ORE、FE、NE、PE
USART_DR 数据寄存器 541~542 理解发送写 DR、接收读 DR
USART_BRR 波特率寄存器 542 理解 USART_Init() 如何生成波特率
USART_CR1 控制寄存器 1 542~544 查 UE、M、PCE、PS、TE、RE、RXNEIE
USART_CR2 控制寄存器 2 544~545 查 STOP 停止位字段
USART_CR3 控制寄存器 3 545~546 查 RTS/CTS、DMA 和错误中断配置

16.2 《STM32F103x8B数据手册(中文)》

要查的内容 PDF 页码 本节用处
LQFP48 引脚图和引脚定义表 17~20 核对 PA9/USART1_TX、PA10/USART1_RX 复用功能

16.3 《STM32F103xx固件函数库用户手册》

要查的内容 PDF 页码 本节用处
USART 函数总览 344~345 快速确认库中有哪些 USART 函数
USART_Init()USART_InitTypeDef 346~348 查初始化函数和结构体成员合法值
USART_StructInit()USART_Cmd() 349 查默认配置和外设使能函数
USART_ITConfig() 350 后续开启 RXNE 中断时使用
USART_SendData()USART_ReceiveData() 354 查单字节发送、接收函数原型和作用
USART_GetFlagStatus() 359 查 TXE、TC、RXNE 等状态标志
USART_GetITStatus() 360~361 后续在中断函数中判断中断来源

推荐查阅顺序不是从头读完,而是:

text 复制代码
数据手册查引脚 → 参考手册查硬件和寄存器 → 库手册查函数 → 回到代码验证

17. 与课程原例程的对应关系

本笔记内容 课程代码位置 本笔记做的取舍
USART1 初始化和发送 9-1 串口发送/Hardware/Serial.c 保留 USART1、PA9、9600 和 TXE 等待
USART1 收发参数 9-2 串口发送+接收/Hardware/Serial.c 保留 PA10、`Tx
接收数据并回显 9-2 串口发送+接收/User/main.c 改成轮询 RXNE,暂不引入 NVIC 和 ISR
OLED 显示十六进制接收值 9-2 串口发送+接收/User/main.c 增加固定测试值比较和 PASS/FAIL

课程 9-2 使用中断接收,本笔记先使用轮询,是为了单独验证 USART 本身。先把"收到字节 → 读 DR → 回显"练熟,再加入中断,问题更容易定位。


18. 最小背诵卡

text 复制代码
USART1:PA9发,PA10收,都在GPIOA;USART1挂APB2。
接线:TX接RX,RX接TX,GND接GND。
参数:9600,8位,1停止,无校验,无流控,收发。
发送:USART_SendData,等待TXE。
接收:RXNE置位,USART_ReceiveData读DR。
初始化最后:USART_Cmd使能。

一句话心智模型:

RCC 给 USART1 和 GPIOA 时钟,GPIO 把 PA9/PA10 接到外设,USART_Init 配好帧格式和波特率,发送时写 DR 并等 TXE,接收时看 RXNE 再读 DR,最后用回显和实际值比较证明整个链路工作。

相关推荐
保安大队王队长1 小时前
单片机知识
单片机·嵌入式硬件
linx2952 小时前
单元五 · 对称认知·下:编译与链接
linux·c语言·开发语言·c++·嵌入式硬件
西城微科方案开发2 小时前
雾化器方案开发:低功耗精密雾化技术的全场景落地
单片机·嵌入式硬件
Jason_zhao_MR2 小时前
新国标下DTUFTU设计最优解——米尔基于全志T153核心板_排版优化
linux·单片机·架构·t113i·双处理器·mcu+linux·电力采集
老当益壮梁奶奶2 小时前
51单片机入门总结(一):基本概念、最小系统、流水灯与按键实验(附完整代码)
笔记·stm32·单片机·嵌入式硬件·51单片机
M78佐菲2 小时前
51单片机学习笔记(2)
linux·笔记·嵌入式硬件·学习·51单片机
ouynagda3 小时前
51 单片机 LED 流水灯 + 数码管动态扫描学习笔记(STC89C52)
笔记·单片机·学习
祖力553 小时前
51单片机(中断、定时器、PWM)
单片机·嵌入式硬件·51单片机
扎陵半导体3 小时前
电子系统中的隔离芯片:关键作用与性能指标
单片机·嵌入式硬件·国产芯片·隔离器·隔离芯片·光隔