理解USART真实收发过程
- [1.USART框图 及简化图](#1.USART框图 及简化图)
- [2. 理解CPU读写TDR和RDR](#2. 理解CPU读写TDR和RDR)
-
- [2.1 TDR和RDR](#2.1 TDR和RDR)
- [3. STM32 USART 数据帧发送详细过程](#3. STM32 USART 数据帧发送详细过程)
-
- [3.1 USART发送标志位介绍](#3.1 USART发送标志位介绍)
-
- [3.11 从问题引入标志位](#3.11 从问题引入标志位)
- [4. STM32 USART 接收详细过程](#4. STM32 USART 接收详细过程)
-
- [4.1 USART接收标志位介绍](#4.1 USART接收标志位介绍)
- [4.2 .阻塞模式](#4.2 .阻塞模式)
1.USART框图 及简化图
通过查找参考手册得到USART框图如下

- 图中 ① 标识区域是 USART 相关的管脚;
- 图中 ② 标识区域是 USART 波特率控制相关;
- 图中 ③ 标识区域是 USART 控制寄存器相关;
- 图中 ④ 标识区域是 USART 状态寄存器相关;
- 图中 ⑤ 标识区域是 USART 数据收、发相关核⼼功能框图;
- 图中 ⑥ 标识区域在 IrDA ( 红外模式 ) 和智能卡模式下才会使用
而我们目前只需要关系最核心的USART收发部分,即⑤ 标识的区域

简化成为

对与USART1 对应的就是APB2(高速外设总线).
2. 理解CPU读写TDR和RDR
这两个寄存器属于 USART 模块内部,⽽其中 STM32F103ZET6 有 5 个串⼝模块,每⼀个都有⼀套独⽴的寄存器结构,我们以 USART1 为例。
查看数据手册得到

而我们知道片上外设的寄存器是直接被映射到CPU地址空间中的,被统一编址了。所以我们可以直接使用地址来访问TDR和RDR,从而对USART单元中的发送和接收寄存器进行数据读写,然后再有USART模块进行自主收发。
我们查询数据手册可以得到 寄存器映像图
如下

上图可知, USART1 的地址范围是: 0x4001 3800 - 0x4001 3BFF 。通过计算可得 这个空间大小为 1024字节也就是 1KB.
注意:虽然CPU内核只为 USART1 分配了 1KB 的地址空间,但实际使⽤的只有最开头的很少⼀部
分。后续的地址是保留的,访问它们可能产⽣不可预知的⾏为.
USART1 中,寄存器⼀共有 7 个,其中每⼀个寄存器都有⼀个偏移量地址,最终访问任何⼀个寄存器,访问⽅式都是:0x4001 3800 +寄存器偏移。(底层逻辑)

2.1 TDR和RDR


**得到USART_DR这个寄存器包含了 两个寄存器 TDR 和 RDR ,即分别用于发送数据 和 接收数据 **。
- 在物理上 ,USART_DR寄存器有两个,⼀个是TDR,⼀个是RDR分别让⽤⼾来发和收数据,
- 这两个寄存器被映射到了同⼀个物理地址,但是官⽅没有披露具体是怎么做到访问同⼀个地址,从⽽做到访问不同寄存器,我们可以可以推测通过操作类型(rw)来区分要访问哪⼀个寄存器。
3.虽然 USART_DR 寄存器是 32 位的,但是实际使⽤的只有 9 位,因为 USART 可编程数据位最多是 9 位
3. STM32 USART 数据帧发送详细过程
为了⽅便表述,我们以实际中最常⽤的场景来进⾏阐述。
假设要发送的数据帧是: 1 起始位 + 8 数据位 + 1 校验位 + 1 停⽌位 = 11 位。
校验方式为odd ,即奇校验。
我们依旧以发送 0x55 为例,⼆进制是 0101 0101 ,采⽤奇校验,那么对应的数据位总共是9位:
0101 0101 + 1 位校验位。
❓ 注意:
校验位本⾝和数据的⼆进制中1的个数是有关的,需要和数据⼀起,发送给对⽅,那么校验位
就应该作为数据的⼀部分发送给接收⽅。
3.1 USART发送标志位介绍

当我们发送数据 0x55时,即 01 01 01 01,根据 奇校验 可得校验位 为1,得到 1 01 01 01 01

如图,数据从TDR被自主平移到发送移位寄存器 (又硬件电路完成)。然后在时钟的控制下,数据通过TX、而TX通过复用GPIO,从而输出 高低电平+。

复用GPIO的流程图


起始位的0和停止位的1 我们会理解为 低电平和 高电平,主要是和数据位区分,区分硬件电气特性和真实传递的数据。
3.11 从问题引入标志位
上述的发送数据过程,只是发送一个数据。可我们想想,是不是存在 这样的情况。
*即我们数据还在发送移位寄存器时,还没完全发送完。可此时我们又写入数据,或者发送数据寄存器已经有数据,而我们又向发送数据寄存器写入数据。这是就会导致数据覆盖和丢失。那么怎么解决呢?
我们怎么知道数据是否被及时传出去呢?
所以, USART 在⾃⼰的收发过程中,必须要提供⾃⼰收发状态的信息,这部分信息,叫做 USART 的状态寄存器( USART_SR :USART Status Register),可以预⾔,该寄存器内部,⼀定有标志位来表明
⽤⼾是否可以写⼊ TDR 的寄存器

USART 发送状态信息,由这 10 个标志位标识。对于发送数据的情况。我们关系 位 6和 位 7。

TXE : 表明如果 TXE是1,则TDR为空,如果TXE为0,则 TDR不为空。
TC:表明发送移位寄存器操作完成,如果TC为 1,发送操作未完成,则为 0;
那么什么情况表示用户把数据都发送完毕了呢?
当TXE ==1 && TC == 1,这种情况就表示没有数据要发送了。
接下来演示发送多个数据的过程。
比如依次发送 0x0 , 0x FF, 0x 55
如图,为未开始发送数据时

TXE和TC都== 1
接下来写入 0x0

此时 TXE不为空 ,即TXE == 0,此时如果用户还想写数据,由于TXE== 0,所以不能写入,如果执意写入,就是用户的问题了。

紧接着,由于数据已经写入,要开始发送到发送移位寄存器了,所以发送还没完成,所以TC也为 0.
紧接着

当数据到发送移位寄存器中了之后(由硬件自动完成)TEX == 1;

对于用户的视角来看,TXE == 1,表明可以写入数据了,此时继续写入0x FF。如下

此时 TXE 和 TC 都为 0,表明TDR已经有数据了,如果我们还是执意写数据就会导致数据被覆盖,所以**我们可以检测TXE,知道 TXE == 1 ,再写入数据,这种方式就叫做阻塞式写入,**当0x0,被发送出去后,TX会被拉成高电平,等待下个数据按照帧格式发送。以此类推。
4. STM32 USART 接收详细过程
有了之前 USART 发送数据的所有详细过程,那么其实我们后续学习数据接收⼀定会容易很多。
所谓的数据帧,本质也全部都是 01 ⽐特位,只不过被 USART 模块包装或者解析,接收的时候,把数据帧中数据部分提供给 RDR ,发送的时候把 TDR 的数据,包装成为数据帧。
类比发送过程中的问题,我们知道接收也一定会存在标志位的引入
接下来简单介绍单个数据的接收过程,然后结合引入标志位讲解多个数据的接收过程
以 0x55 为例,二进制为 01 01 01 01,
站在发送⽅⻆度:

接收控制器 接收到 一个 低电平,根据约定好的帧格式,知道要准备接收数据了,

依次接收一个bit位,接收到 1 后整体 右移,继续接收0 ,然后整体右移,最后得到 1 01 01 01 01,第一位为校验位,然后再整体给RDR最后被CPU读取,这个数据就是我们发送的0x55.这样就完成了单次数据的接收。
4.1 USART接收标志位介绍
上述接收数据的流程,我们忽略了重要的一点,那就是从用户的角度,我们怎么知道 数据从接收移位寄存器成功的被USART模块的硬件电路 移到 了 RDR呢,我们用户·怎么知道什么时候可以读取数据呢,所以就引出来了标志位。
USART 需要有⽅式,能表⽰ RDR 寄存器的状态,类
似发送,接收的时候,也是状态寄存器 USART_SR 来标识接收状态,其中, == RXNE == 标志位就是完成
该项⼯作的。


RXNE:读数据寄存器非空 (Read data register not empty)
• 当 RDR 寄存器中没有数据的时候,RXNE标志位被设置为0
• 当 RDR 寄存器中有数据的时候, RXNE 标志位被设置为1
• RXNE: Read data register not empty
所以,当 USART 在接受数据期间,那么⽤⼾就应该⼀直检测 RXNE 标志位,只要该标志位⼀直是
0 ,那么⽤⼾就应该⼀直阻塞在检测的位置,直到 RXNE == 1 表⽰有数据了,才能读取
所以 总的读取流程如下

当没有数据读取时,RXNE == 0;
接着来数据,按照帧格式 接收


RDR接收数据成功,RXNE被置为1.这时数据才可以被用户读取。
4.2 .阻塞模式
如果使⽤阻塞模式进⾏数据接收,程序需要轮询判断如 下图 所⽰的①②③的 RXNE 标志,主要逻辑
如下:
- RXNE 标志被置 0 ,表⽰暂时没有数据,要求⽤⼾轮询检测该标志位,标志位为0,就有⼀直阻塞
在这⾥。 - 收到数据, RXNE 标志被置 1 ,表⽰接收到 1 字节数据,⽤⼾将读到的数据,保存到⾃⼰定义内存区域,读取的时候,会⾃动触发清除 RXNE 标志 ,然后继续检测 RXNE ,等待接收下⼀个数
据。 - 达到期望接收的数据个数或等待数据超时,退出本次阻塞模式接收流程。
