STM32 USART 详解(四):数据帧及标志位的收发机制与寄存器深度剖析

目录

  • 前言
  • 一、USART模块地址空间
    • [1.1 STM32统一编址机制](#1.1 STM32统一编址机制)
    • [1.2 USART1地址范围详解](#1.2 USART1地址范围详解)
    • [1.3 各串口模块地址清单](#1.3 各串口模块地址清单)
  • 二、USART寄存器结构
    • [2.1 寄存器列表与偏移量](#2.1 寄存器列表与偏移量)
    • [2.2 寄存器权限标识说明](#2.2 寄存器权限标识说明)
  • [三、数据寄存器 USART_DR](#三、数据寄存器 USART_DR)
    • [3.1 TDR与RDR的双重角色](#3.1 TDR与RDR的双重角色)
    • [3.2 DR寄存器的位结构](#3.2 DR寄存器的位结构)
  • 四、数据帧格式
    • [4.1 数据帧结构组成](#4.1 数据帧结构组成)
    • [4.2 以发送0x55为例的波形分析](#4.2 以发送0x55为例的波形分析)
    • [4.3 起始位与停止位的电平本质](#4.3 起始位与停止位的电平本质)
  • 五、USART发送机制
    • [5.1 从TDR到发送移位寄存器的数据流转](#5.1 从TDR到发送移位寄存器的数据流转)
    • [5.2 数据覆盖问题------为什么不能盲目连续写入](#5.2 数据覆盖问题——为什么不能盲目连续写入)
    • [5.3 TXE与TC------衡量发送状态的两个核心标志位](#5.3 TXE与TC——衡量发送状态的两个核心标志位)
      • [5.3.1 TXE(Transmit Data Register Empty,发送数据寄存器空)](#5.3.1 TXE(Transmit Data Register Empty,发送数据寄存器空))
      • [5.3.2 TC(Transmission Complete,发送完成)](#5.3.2 TC(Transmission Complete,发送完成))
      • [5.3.3 TXE与TC的区别](#5.3.3 TXE与TC的区别)
    • [5.4 USART_SR状态寄存器全景](#5.4 USART_SR状态寄存器全景)
  • 六、USART带标志位的数据发送原理
    • [6.1 用户视角:什么时候可以写入数据](#6.1 用户视角:什么时候可以写入数据)
    • [6.2 USART硬件视角:TXE标志的翻转时机](#6.2 USART硬件视角:TXE标志的翻转时机)
  • [七、三字节完整发送流程剖析(0x00 → 0xFF → 0x55)](#七、三字节完整发送流程剖析(0x00 → 0xFF → 0x55))
    • [7.1 第一阶段:发送 0x00](#7.1 第一阶段:发送 0x00)
    • [7.2 第二阶段:发送 0xFF](#7.2 第二阶段:发送 0xFF)
    • [7.3 第三阶段:发送 0x55](#7.3 第三阶段:发送 0x55)
    • [7.4 发送完毕:TC标志位的翻转](#7.4 发送完毕:TC标志位的翻转)
  • 八、阻塞式发送模式
  • 九、时钟域的并行操作
  • [十、USART 详细接收过程](#十、USART 详细接收过程)
    • [10.1 数据帧格式回顾](#10.1 数据帧格式回顾)
    • [10.2 接收过程的逐步拆解](#10.2 接收过程的逐步拆解)
      • [10.2.1 第一阶段:检测起始位](#10.2.1 第一阶段:检测起始位)
      • [10.2.2 第二阶段:逐位接收数据位](#10.2.2 第二阶段:逐位接收数据位)
      • [10.2.3 第三阶段:接收校验位](#10.2.3 第三阶段:接收校验位)
      • [10.2.4 第四阶段:检测停止位](#10.2.4 第四阶段:检测停止位)
      • [10.2.5 第五阶段:校验与数据平移](#10.2.5 第五阶段:校验与数据平移)
    • [10.3 RXNE 标志位------接收就绪的信号](#10.3 RXNE 标志位——接收就绪的信号)
      • [10.3.1 RXNE 位的定义](#10.3.1 RXNE 位的定义)
      • [10.3.2 RXNE 的硬件置位机制](#10.3.2 RXNE 的硬件置位机制)
      • [10.3.3 RXNE 的清除机制](#10.3.3 RXNE 的清除机制)
    • [10.4 阻塞式读取机制](#10.4 阻塞式读取机制)
      • [10.4.1 轮询检测 RXNE](#10.4.1 轮询检测 RXNE)
      • [10.4.2 形象比喻](#10.4.2 形象比喻)
      • [10.4.3 责任边界](#10.4.3 责任边界)
      • [10.4.4 读取后自动清零](#10.4.4 读取后自动清零)
    • [10.5 连续接收的时序关系](#10.5 连续接收的时序关系)
  • 结语

🎬 云泽Q个人主页
🔥 专栏传送入口 : 《C语言》《数据结构》《C++》《Linux》《蓝桥杯系列》《笔试算法》《AI赋能》《STM32》《Python

⛺️遇见安然遇见你,不负代码不负卿~


前言

大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~

一、USART模块地址空间

1.1 STM32统一编址机制

在STM32F103ZET6这款MCU内部,所有片上外设------包括SRAM、Flash以及各类外设模块------都处于CPU的统一编址空间之下,完成地址映射。换句话说,每一个外设、每一个寄存器,最终都对应着一个明确的物理地址。CPU通过对这些物理地址的读写操作,来实现对外设的控制和数据交互。

具体到USART模块,STM32F103ZET6内部总共包含了5个串口接口:USART1、USART2、USART3、UART4、UART5。每一个串口都是一个独立的硬件单元,拥有自己专属的地址空间。只要搞清楚其中一个串口的硬件结构和寄存器组,其余所有串口的原理完全一致,可以直接举一反三。

1.2 USART1地址范围详解

以USART1为例,它的物理地址范围是:

0x4001 3800 ~ 0x4001 3BFF

这个地址空间的大小可以通过公式计算:

复制代码
结束地址 - 起始地址 + 1 = 0x4001 3BFF - 0x4001 3800 + 1 = 0x3FF + 1 = 0x400(十六进制)

将0x400转换为十进制:1024字节,即1KB

也就是说,CPU内核为USART1分配了1KB的地址空间。但实际使用中,只有最开头的很少一部分地址被真正使用到了,后续的大部分地址是保留的,访问它们可能产生不可预知的行为。

USART1中一共有7个寄存器,每一个寄存器都有一个偏移量地址。访问任何一个寄存器的方式都是:

复制代码
USART1基地址(0x4001 3800) + 寄存器偏移量

1.3 各串口模块地址清单

外设 所在总线 起始地址 结束地址 地址空间大小 类型
USART1 APB2 0x4001 3800 0x4001 3BFF 1 KB 高级同步/异步串行接口
USART2 APB1 0x4000 4400 0x4000 47FF 1 KB 通用同步/异步串行接口
USART3 APB1 0x4000 4800 0x4000 4BFF 1 KB 通用同步/异步串行接口
UART4 APB1 0x4000 4C00 0x4000 4FFF 1 KB 通用异步串行接口
UART5 APB1 0x4000 5000 0x4000 53FF 1 KB 通用异步串行接口

可以看到,USART1挂载在APB2总线上,而其余串口均挂载在APB1总线上。这也说明USART1的性能和时钟频率与其他串口有所不同。

二、USART寄存器结构

2.1 寄存器列表与偏移量

USART1的7个寄存器及其偏移量如下:

寄存器 偏移量(Offset) 地址计算过程 最终地址
USART_SR 0x00 0x4001 3800 + 0x00 0x4001 3800
USART_DR 0x04 0x4001 3800 + 0x04 0x4001 3804
USART_BRR 0x08 0x4001 3800 + 0x08 0x4001 3808
USART_CR1 0x0C 0x4001 3800 + 0x0C 0x4001 380C
USART_CR2 0x10 0x4001 3800 + 0x10 0x4001 3810
USART_CR3 0x14 0x4001 3800 + 0x14 0x4001 3814
USART_GTPR 0x18 0x4001 3800 + 0x18 0x4001 3818

这里我们重点关注前几个核心寄存器:

  • USART_SR(状态寄存器):偏移量0x00,用于存放各种状态标志位,包括我们后面重点讲解的TXE和TC。
  • USART_DR(数据寄存器):偏移量0x04,是发送和接收数据的核心寄存器。

2.2 寄存器权限标识说明

在参考手册的寄存器位描述中,你会看到类似rcw0r这样的标识,这些代表了每一位的读写权限:

  • r(Read Only,只读):该位只能读取,不能写入。从编程角度,你可以直接读取寄存器的值来获取状态。
  • rc(Read Clear,读后清零):该标志位由硬件自动置位,当你在软件中读取该寄存器(或对应位)后,硬件会自动将该位清零。这是一个典型的"读即清"机制。
  • w0(Write 0 to Clear,写0清零):该位可以通过软件写0来清零。写入1通常不影响该位的状态。

这些权限标识反映了硬件对各个标志位的管理方式。很多情况下,标准库或HAL库已经帮我们处理了这些底层的读写操作,不需要我们手动去操作。但了解这些底层机制,有助于在遇到异常时进行深度调试。

三、数据寄存器 USART_DR

3.1 TDR与RDR的双重角色

USART_DR是串口通信中最核心的寄存器之一,它的偏移量为0x04,对于USART1来说,其物理地址为0x4001 3804

从数据手册的描述来看,USART_DR被标注为一个寄存器,但实际上它由两个逻辑寄存器组成:

  • TDR(Transmit Data Register,发送数据寄存器):用于发送数据。当CPU向USART_DR写入数据时,数据被写入TDR。
  • RDR(Receive Data Register,接收数据寄存器):用于接收数据。当CPU从USART_DR读取数据时,数据来自RDR。

TDR和RDR共享同一个物理地址(0x4001 3804),通过总线控制信号中的读写方向来区分:

  • 写操作 → 访问TDR(发送方向)
  • 读操作 → 访问RDR(接收方向)

TDR寄存器提供了内部总线(APBx)和输出移位寄存器 之间的并行接口;RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。

3.2 DR寄存器的位结构

USART_DR是一个32位寄存器,但实际只使用了低9位:

位段 名称 说明
位31:9 保留位 硬件强制为0
位8:0 DR8:0 数据值(Data value),共9位

DR8:0共9位,意味着USART最多支持9位数据的传输。

  • 如果配置为9位数据位,则无法启用奇偶校验功能。
  • 工程中更常见的配置是8位数据 + 1位奇偶校验(如8N1、8E1、8O1)。

当使能校验位(USART_CR1中PCE位被置位)进行发送时,写到MSB的值(根据数据长度不同,MSB是第7位或第8位)会被后来的校验位 所取代。也就是说,硬件会自动用计算出的校验位覆盖最高数据位,用户无需手动计算校验值。

四、数据帧格式

4.1 数据帧结构组成

串口通信的数据是以**帧(Frame)**为单位进行传输的。一个完整的数据帧由以下部分组成:

复制代码
[起始位] + [数据位] + [校验位(可选)] + [停止位]

以最常见的配置为例:

  • 起始位:1位,固定为低电平(0),用于通知接收方"数据开始传输"
  • 数据位:8位(或9位),实际要传输的数据,LSB(最低有效位)先发
  • 校验位:1位(奇校验或偶校验),由硬件自动生成
  • 停止位:1位(或1.5位、2位),固定为高电平(1),用于标识一帧结束

所以一帧完整的帧包含:1 + 8 + 1 + 1 = 11位

4.2 以发送0x55为例的波形分析

以发送数据0x55为例来直观理解数据帧的传输过程:

复制代码
0x55 的二进制 = 0101 0101

由于串口通信是LSB先发(最低有效位优先),所以实际发送顺序为:

复制代码
起始位 → 数据位(LSB→MSB) → 校验位 → 停止位
  0    →  1 0 1 0 1 0 1 0  →  奇校验位 →  1

完整帧为:0(起始)+ 10101010(数据,LSB先发)+ 1(奇校验)+ 1(停止)= 11位

波形图上各阶段的含义:

阶段 名称 电平 说明
空闲状态 高电平 无数据传输时,TX线保持高电平
起始位 低电平 拉低电平,触发接收方开始采样
数据位 高低交替 8位数据逐位发送,LSB先发
校验位 由数据决定 奇校验位,硬件自动填充
停止位 高电平 拉高电平,标识一帧结束,回到空闲状态

4.3 起始位与停止位的电平本质

起始位和停止位虽然可以用逻辑0和逻辑1来理解,但更好的理解方式是从电平角度

  • 起始位:本质上就是USART硬件发现"有数据要发送"时,主动拉低TX引脚的电平,形成低电平触发信号,通知接收端"准备接收数据"。
  • 停止位:本质上就是USART硬件发现"数据发送完成"时,主动拉高TX引脚的电平,形成高电平恢复信号,表示"这一帧结束了,回到空闲状态"。

接收端收到的是一串高低电平交替的方波 ,最终形成的波形就是我们在示波器上看到的样子。起始位可以理解为逻辑0,但更好的方式是理解成低电平 ;停止位可以理解为逻辑1,但更好的方式是理解成高电平

五、USART发送机制

5.1 从TDR到发送移位寄存器的数据流转

整个发送过程涉及两个关键的寄存器层次:

复制代码
CPU(通过APB总线)→ 写入 → TDR(发送数据寄存器)→ 硬件转移 → 发送移位寄存器 → 逐位输出到TX引脚

具体流程如下:

  1. 用户程序将要发送的数据写入USART_DR(实际写入TDR)。
  2. USART硬件检测到TDR中有数据后,将TDR中的数据一次性并行转移到发送移位寄存器中。
  3. 发送移位寄存器在USART时钟驱动下,将数据逐位串行输出到TX引脚,LSB先发。
  4. 硬件自动在数据帧前后添加起始位和停止位,并根据配置自动填充校验位。

注意:发送移位寄存器对用户是不可见的,用户只能通过TDR来操作发送数据。

5.2 数据覆盖问题------为什么不能盲目连续写入

假设USART底层正在发送数据,发送移位寄存器中还有数据未发完。此时如果用户再次向TDR写入新数据,会发生什么?

c 复制代码
while(cnt)
{
    TDR = cnt;
    cnt--;
}

如果第一次写入时USART正在忙,数据暂存在TDR中等待转移到移位寄存器。如果在USART还没完成转移和发送之前,用户第二次又往TDR写入数据,那么新数据会直接覆盖TDR中尚未发送的旧数据,导致数据丢失。

这就好比你一边在说话,别人一边往你嘴里塞新的台词------你根本来不及把之前的话说完。

因此,在发送数据之前,必须确认TDR是否为空,即上一次的数据是否已经被转移到移位寄存器中。这正是TXE标志位存在的意义。

5.3 TXE与TC------衡量发送状态的两个核心标志位

USART_SR状态寄存器中有两个极其重要的标志位,专门用来衡量发送过程的状态:

5.3.1 TXE(Transmit Data Register Empty,发送数据寄存器空)

  • 位置 :USART_SR的位7
  • 含义:当TDR中的数据被硬件转移到发送移位寄存器后,该位被硬件置1。
  • 取值说明
    • 0:数据还没有被转移到移位寄存器,TDR非空,此时不能写入新数据。
    • 1:数据已经被转移到移位寄存器,TDR已空,可以写入下一帧数据。
  • 清零方式 :对USART_DR进行写操作时,该位自动清零(因为写入新数据后TDR不再为空)。
  • 应用场景 :主要用于单缓冲器传输中,判断是否可以写入下一字节数据。

5.3.2 TC(Transmission Complete,发送完成)

  • 位置 :USART_SR的位6
  • 含义 :当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置1。
  • 取值说明
    • 0:发送还未完成。
    • 1:发送已完成,整个数据帧(包括停止位)已全部从TX引脚发出。
  • 清零方式
    • 软件序列清除:先读USART_SR,然后写入USART_DR。
    • 或者直接写入'0'来清除(仅在多缓冲器通讯中推荐)。
  • 应用场景 :用于判断整帧数据是否彻底发送完毕

5.3.3 TXE与TC的区别

这两个标志位经常被混淆,它们的本质区别在于衡量的阶段不同

标志位 衡量的是什么 何时置1
TXE TDR寄存器是否为空 数据从TDR转移到移位寄存器后立即置1
TC 整帧数据是否发送完毕 移位寄存器中最后一位(含停止位)发完后置1

简单来说:

  • TXE=1 意味着:TDR空了,你可以写下一字节了,但当前这一帧可能还在移位寄存器中慢慢发。
  • TC=1 意味着:不仅TDR空了,移位寄存器也空了,整个数据帧已经全部从TX引脚发出去了。

5.4 USART_SR状态寄存器全景

USART_SR(状态寄存器)位于偏移量0x00处,复位值为0x00C0。其关键位段如下:

名称 权限 说明
位7 TXE r 发送数据寄存器空
位6 TC rc w0 发送完成
位5 RXNE rc w0 读数据寄存器非空(接收数据就绪)
位4 IDLE rc w0 空闲线检测
位3 ORE r 溢出错误
位2 NE r 噪声错误标志
位1 FE r 帧错误
位0 PE r 校验错误

其中我们当前阶段重点关注的是**TXE(位7)TC(位6)**这两个发送相关的标志位。后续进入接收阶段后,RXNE(位5)将成为核心关注点。

六、USART带标志位的数据发送原理

当我们把两个核心标志位------TXE和TC------引入到USART的发送流程中后,串口发送就进入了真正意义上的实战阶段。在用户代码层面进行数据帧发送时,真实情况下的每一次发送都是要携带标志位来判断状态的。

我们要发送三个字节的数据,分别是 0x000xFF0x55。这一次不只是一个数据,而是连续三个。数据帧的格式设定为:1位起始位 + 8位数据位 + 1位奇校验位 + 1位停止位,总共11位。这个帧格式是我们之前一直沿用的,此处不再赘述。

6.1 用户视角:什么时候可以写入数据

站在用户的角度,理解TXE和TC的状态变化逻辑至关重要:

  • TXE == 1 时,说明TDR是空的。此时如果用户还有数据要发送,就可以放心地继续写入下一个字节。
  • 如果用户的数据已经全部写完了,那就什么都不用做,静等USART硬件把剩余数据发完。当TC变成1时,意味着 TXE == 1 && TC == 1,表示本轮数据全部发送完毕。
  • 如果数据没发完,只要TXE == 1,用户就可以继续往TDR里写新数据。

用户判断逻辑就是:TXE == 1 && 自己还有数据要发,那么就继续发送。

6.2 USART硬件视角:TXE标志的翻转时机

从USART硬件模块的角度来看,它的运作逻辑是这样的:

  1. USART必须先把当前移位寄存器里的数据全部串行发送完毕。
  2. 发送完成后,USART才会把TDR寄存器中的数据平移到发送移位寄存器。
  3. 只有TDR中的数据成功平移到发送移位寄存器之后,USART才会将TXE设置为1,表示TDR已空,允许用户再次写入。

这就是TXE的本质------USART硬件模块用来指导用户写入数据的指挥棒。它告诉用户:现在TDR空了,你可以写了;或者TDR还被占着,你必须等。

如果用户无视TXE标志位,在TXE == 0(TDR不空)时强行写入数据,就会导致自己覆盖了自己的数据。这时候锅要用户自己背,因为USART已经通过TXE标志告诉你TDR不为空了,你还要往里写。

所以,用户要写TDR,必须先对TXE进行判定,只有TXE == 1,用户才能再写入。

七、三字节完整发送流程剖析(0x00 → 0xFF → 0x55)

下面我们以发送 0x000xFF0x55 这三个字节为例,从时序角度逐步拆解整个发送过程。

7.1 第一阶段:发送 0x00

初始状态下,TDR为空,TXE = 1,TC = 1。

用户将第一个数据 0x00 写入TDR。此时:

  • TDR被占用,TXE被USART自动设置为0。
  • TC也被设置为0(因为发送尚未完成)。
  • USART硬件自动将TDR中的数据(1-0-0-0-0-0-0-0-0,含起始位和校验位)平移到发送移位寄存器。
  • TDR重新变为空,TXE恢复为1。
  • 发送移位寄存器开始按位串行输出数据到TX引脚。

此时TC仍为0,因为移位寄存器中还有数据正在发送。

7.2 第二阶段:发送 0xFF

USART硬件在自身时钟驱动下,继续从移位寄存器逐位输出 0x00 的数据帧。

同时,由于上一阶段TDR已经变空(TXE = 1),用户代码检测到TXE == 1后,将第二个数据 0xFF 写入TDR。此时:

  • TDR再次被占用,TXE被设置为0。
  • 注意:如果此时USART硬件中上一次 0x00 的数据还没有从移位寄存器发送完毕,那么TDR内部的 0xFF 就无法被平移到移位寄存器。
  • 因此TDR一直被占用,TXE保持为0。

用户必须等待TXE变回1,才能写入下一个数据。

当USART把 0x00 的所有位(11位)全部发送完毕后,硬件会将TDR中的 0xFF 平移到移位寄存器。平移完成后:

  • TDR重新变空,TXE被USART设置为1。
  • 移位寄存器开始串行输出 0xFF(加上奇校验位后为 1-1-1-1-1-1-1-1-1)。

7.3 第三阶段:发送 0x55

此时TXE = 1,用户检测到后,将第三个数据 0x55 写入TDR。

  • TDR被占用,TXE被设置为0。
  • USART继续从移位寄存器输出 0xFF 的数据帧。

0xFF 的数据帧全部输出完毕后:

  • USART将TDR中的 0x55 平移到移位寄存器。
  • TDR变空,TXE被设置为1。
  • 移位寄存器开始输出 0x55 的数据帧。

此时用户已经没有更多数据要发送了。TDR保持为空(TXE = 1)。

7.4 发送完毕:TC标志位的翻转

当最后一个数据 0x55 的所有位也从移位寄存器全部串行输出到TX引脚后:

  • TDR为空(TXE = 1)
  • 移位寄存器也为空

两个条件同时满足,USART硬件将 TC标志位置为1,宣告本次多字节数据发送全部完成。

此时 TXE == 1 && TC == 1,整个发送流程结束。

八、阻塞式发送模式

在实际编程中,用户发送数据时必须对TXE标志位进行检测:

  • 如果 TXE == 0 ,表示TDR中的数据还没有被平移到发送移位寄存器(TDR被占用)。此时用户必须阻塞在检测TXE标志位的位置进行等待,直到TXE变为1。

这种模式的写入方式就叫做阻塞式发送

在时序图上可以清晰地看到:

  • 数据寄存器TDR中依次装入数据1、数据2、数据3。
  • 每当一个数据从TDR平移到发送移位寄存器时,TXE标志从低电平跳变为高电平(标记为时刻①、②)。
  • 用户只有在TXE变高的时刻才能写入下一个数据。
  • 当最后一个数据全部发送完毕,TDR和发送移位寄存器都为空时,TC标志被置为1(标记为时刻③)。

所以,如果使用阻塞模式进行数据发送(一个或多个数据之后),要知道USART是否彻底把数据全部发送出去了,就看TC标志位。当TC == 1时,表示要发送的数据已全部发送完成。

九、时钟域的并行操作

需要特别注意的是,CPU和USART模块是在各自的时钟域下独立运行的:

  • CPU通过APBx总线时钟向TDR写入数据。
  • USART模块通过自身的波特率时钟从移位寄存器逐位串行输出数据。

这意味着,在时间维度上,用户向TDR写入下一个数据USART从移位寄存器发送当前数据 是可以并行进行的。只要TDR是空的(TXE == 1),用户就可以提前把下一个数据写好放进去,等USART发完当前数据后,硬件会自动把TDR中的新数据搬运到移位寄存器继续发送。

这种硬件层面的自动平移机制,使得串口发送在效率上远高于CPU逐位模拟的方式。

十、USART 详细接收过程

前面我们完成了 STM32 USART 发送的详细过程,数据帧格式和标志位都已经搞定了。接下来进入下一个话题------USART 详细的接收过程

之前我们聊接收的时候,只是站在 8 位数据位的角度,并没有谈任何数据帧格式。所以这一次,我们要带着完整的帧格式来理解接收的全貌。

10.1 数据帧格式回顾

以发送端发送 0x55 为例,对应的二进制为 0101 0101

我们约定的帧格式为:

组成部分 位数 说明
起始位 1 位 低电平(拉低),标记一帧数据的开始
数据位 8 位 实际有效数据
校验位 1 位 奇校验位
停止位 1 位 高电平(拉高),标记一帧数据的结束

总共 11 位比特位构成一帧完整的数据。

需要特别注意的是:发送端是从低位向高位逐位发送的0x55 的二进制 0101 0101,我们人眼阅读时是从高位到低位读的,但在物理线路上,发送端先发最低位的 1,再发 010......依此类推。所以线路上实际传输的比特流顺序为:

复制代码
起始位(0) → 1 → 0 → 1 → 0 → 1 → 0 → 1 → 0 → 校验位(1) → 停止位(1)

接收端按这个顺序依次接收到自己的接收移位寄存器中。

10.2 接收过程的逐步拆解

10.2.1 第一阶段:检测起始位

接收端的 RX 引脚平时处于空闲的高电平状态。当接收控制器检测到一个拉低的电平(低电平)时,就知道对方开始发送数据了。

这个低电平仅仅用于 USART 内部判断"对方开始发了",不需要保存,更不需要被用户读取。起始位由硬件自动识别和处理。

收到这个拉低的电平后,接收移位寄存器准备好接收对面的数据,第一个进入接收移位寄存器的就是起始位。

10.2.2 第二阶段:逐位接收数据位

起始位之后,发送端开始逐位发送 8 位数据。接收端按照约定的波特率(时钟节拍),一位一位地把数据从 RX 引脚读入接收移位寄存器中。

0x55 为例,实际进入接收移位寄存器的顺序为:

复制代码
第1位进入:1
第2位进入:0
第3位进入:1
第4位进入:0
第5位进入:1
第6位进入:0
第7位进入:1
第8位进入:0

数据在接收移位寄存器中逐位右移填充,最终填满 8 个有效数据位。

10.2.3 第三阶段:接收校验位

8 位数据位之后,接下来进入的是 1 位校验位。在我们的奇校验配置下,0x55 的二进制 0101 0101 中"1"的个数为 4 个(偶数),为了满足奇校验(总"1"个数为奇数),校验位为 1

这个校验位同样被接收移位寄存器接收进来。

10.2.4 第四阶段:检测停止位

在收到约定的 9 位数据(8 位数据位 + 1 位校验位)之后,接收端继续检测线路电平。当读到拉高的电平时,就说明对方发完了,这就是停止位。

这个高电平同样仅仅是 USART 内部判断"对方发完了"的信号,不需要保存,更不需要被用户读取。停止位由硬件自动识别。

10.2.5 第五阶段:校验与数据平移

当 11 位完整帧全部接收完毕后,USART 模块自己进行校验:

  • 校验通过 → 有效数据(8 位)从接收移位寄存器平移到接收数据寄存器(RDR)。
  • 校验不通过 → 数据无效,可能触发错误标志位。

在这个过程中,起始位和停止位已经被硬件自动丢弃,它们只起到帧边界的标记作用,不会进入 RDR。

10.3 RXNE 标志位------接收就绪的信号

数据从接收移位寄存器平移到 RDR 的过程中,状态寄存器(USART_SR)中的 RXNE 位会被硬件自动置 1。

10.3.1 RXNE 位的定义

RXNE 全称为 Read Data Register Not Empty (读数据寄存器非空),位于 USART_SR 状态寄存器的位 5

位编号 名称 含义
位 5 RXNE 读数据寄存器非空
  • RXNE = 0:数据没有收到,RDR 为空,不可读取。
  • RXNE = 1 :收到数据,RDR 非空,可以读出。

10.3.2 RXNE 的硬件置位机制

当 RDR 移位寄存器中的数据被转移到 USART_DR 寄存器中时,RXNE 位被硬件自动置位

如果 USART_CR1 寄存器中的 RXNEIE(接收中断使能位)为 1,则同时会产生中断。

10.3.3 RXNE 的清除机制

  • 正常读取清除:对 USART_DR(即 RDR)执行读操作,RXNE 位会被硬件自动清零。
  • 手动清除:RXNE 位也可以通过写入 0 来清除,但只有在多缓存通讯中才推荐这种清除方式。

10.4 阻塞式读取机制

有了 RXNE 标志位之后,用户就可以安全地读取数据了。具体做法是:

10.4.1 轮询检测 RXNE

在读取 RDR 之前,必须检测 RXNE 标志位:

c 复制代码
while ((USART_SR & 0x0020) == 0);  // 轮询等待 RXNE 置 1
// RXNE 为 1 后,安全读取数据
uint8_t received_data = USART_DR;  // 读取数据,同时硬件清零 RXNE

标志位为 0 表示没有数据,程序通过 while 循环不断轮询检测。只要标志位一直为 0,程序就卡在那里等待

10.4.2 形象比喻

这个等待过程就像去食堂打饭:阿姨还没把饭菜端上来的时候,你只能站在点菜的位置上等待;阿姨把菜放上来了(RXNE 变 1),你这个时候才能拿到菜。

10.4.3 责任边界

这种机制明确了硬件和软件之间的责任边界:

  • USART 模块的责任:负责接收数据、校验数据、将有效数据放入 RDR,并置位 RXNE 通知用户"数据准备好了"。
  • 用户的责任:在 RXNE 置 1 之后去读取数据。只要标志位为 1,用户读数据读出错了就和 USART 模块没关系了------"我把我该做的工作做了,要后面读数据出错,这个锅我不背。"

10.4.4 读取后自动清零

只要用户把数据读走了,RXNE 标志位就会被 USART 硬件自动清零,回到 0 状态,准备接收下一帧数据。

10.5 连续接收的时序关系

当连续接收多帧数据时,时序关系如下:

每一帧数据接收完成并校验通过后,RXNE 被置 1(图中①②③标记处),用户读取后 RXNE 自动清零,等待下一帧。


结语

相关推荐
linx2952 小时前
单元四 · 对称认知·上:内存与指针
c语言·开发语言·数据结构·嵌入式硬件·算法
国科安芯2 小时前
ASM9048S(4 路高速 LVDS 接收器)在商业航天等场景中的应用研究
嵌入式硬件·电源模块·卫星通信·抗干扰·抗辐射
HUI-4743 小时前
EG11752|ESOP‑8 内置 200V‑2A 异步降压 DC‑DC,10‑200V 超宽压小功率辅助电源优选
嵌入式硬件·硬件工程
HRTOS3 小时前
HRTOS 4.0 驱动库实例:LCD1602显示屏使用示例
c语言·单片机·嵌入式硬件·51单片机
EleganceJiaBao3 小时前
【嵌入式】STM32 状态机设计:枚举、位掩码、结构体、变量与宏定义的合理选择
stm32·单片机·嵌入式硬件·枚举·状态机·位掩码
一条破秋裤3 小时前
STM32F103 UART 第一层复习:USART1 收发、回显与默写测试
stm32·单片机·嵌入式硬件
保安大队王队长3 小时前
单片机知识
单片机·嵌入式硬件
linx2954 小时前
单元五 · 对称认知·下:编译与链接
linux·c语言·开发语言·c++·嵌入式硬件
西城微科方案开发4 小时前
雾化器方案开发:低功耗精密雾化技术的全场景落地
单片机·嵌入式硬件