嵌入式:深刻理解UART与USART串口通信的流程和原理结构

📅 发布时间:2026/8/23 18:43:13
嵌入式:深刻理解UART与USART串口通信的流程和原理结构 前言文章合集嵌入式系列https://blog.csdn.net/2401_88433210/category_13196870.html?fromshareblogcolumnsharetypeblogcolumnsharerId13196870sharereferPCsharesource2401_88433210sharefromfrom_link文章以STM32F103ZET6芯片为例来介绍建议先看一下这一篇博客了解UART与USART串口通信的波特率与帧格式嵌入式深刻理解UART与USART串口通信的波特率与帧格式-CSDN博客本文以STM32F103ZET6为例详细解析UART/USART串口通信原理详细介绍了波特率USART帧格式之间的关系https://blog.csdn.net/2401_88433210/article/details/163637426?spm1011.2415.3001.10575sharefrommp_manage_link一、USART 简化原理结构图前面若干章讨论的都是 USART 的通信协议特性下面把重点放在 STM32 单片机中关于 USART 的功能结构中即重点放在 USART 硬件功能构成和如何发出 USART 数据帧上。STM32 的 USART 完全兼容之前讲解的 UART 的全部特性。除此之外它还支持同步单向通信和半双工单线通信也支持 LIN局部互连网智能卡协议和 IrDA红外数据组织SIR‑ENDEC 规范以及调制解调器CTS / RTS操作它还允许多处理器通信的能力。总之 STM32 的 USART 有丰富的扩展功能。如果我们要看到 USART 功能框图在《STM32F10xxx 参考手册》通用同步异步收发器 (USART) 章节可以看到。如上图所示是 STM32 的 USART 的功能框图其中各部分的主要功能如下图中 ① 标识区域是 USART 相关的管脚图中 ② 标识区域是 USART 波特率控制相关图中 ③ 标识区域是 USART 控制寄存器相关图中 ④ 标识区域是 USART 状态寄存器相关图中 ⑤ 标识区域是 USART 数据收、发相关核心功能框图图中 ⑥ 标识区域在 IrDA红外模式和智能卡模式下才会使用。该图所示的功能模块对于萌新而言太过庞杂。对于仅使用 USART 标准通信功能而言最核心的就是图中 ⑤ 标识的区域部分我们只把 ⑤ 标识的区域部分拿出来进行简化。简化结构图当用户将待发送的字节数据写入到数据寄存器USART_DR / TDR中USART 控制器会首先把 TDR 的数据平移至发送移位寄存器然后 USART 的发送控制器就会将发送移位寄存器中的数据自动按照数据位通过 Tx 管脚依次发送出去。USART 控制器会通过 Rx 管脚依次接收收到的数据位到接收移位寄存器当接收完一个数据段8 / 9 位时会自动将接收移位寄存器中的数据平移拷贝到数据寄存器USART_DR / RDR中。后续用户从数据寄存器USART_DR / RDR读取数据就能得到最近一次接收到的数据字节。在这里我们正式认识两个 USART 寄存器分别是发送寄存器 TDRTransmit Data Register接收寄存器 RDRReceive Data Register其中发送和接收移位寄存器在 USART 硬件单元内部对用户不可见。❓注意 这里除了 TDR和 RDR我们把 USART 的其他模块当成黑盒的整个拷贝移动移位发送和移位接收都是 USART 模块自己完成的二、理解 CPU 读写 TDR 和 RDR这两个寄存器属于 USART 模块内部而其中 STM32F103ZET6 有 5 个串口模块每一个都有一套独立的寄存器结构我们以 USART1 为例。在 STM32F103ZET6 当中片上外设寄存器全部映射至 CPU 内存地址空间、统一编址。 CPU 可以直接操作地址读写 TDR 发送寄存器、RDR 接收寄存器之后由 USART 硬件自主完成收发工作。上图可知USART1 的地址范围是0x4001 3800 − 0x4001 3BFF该地址范围是 0x4001 3800 到 0x4001 3BFF。USART1 拥有的范围大小结束地址 − 起始地址 10x4001 3BFF − 0x4001 3800 1 0x3FF 1 0x400十六进制将 0x400 转换为十进制1024 字节。所以这个地址空间一共是 1024 字节也就是 1KB。注意虽然 CPU 内核只为 USART1 分配了 1KB 的地址空间但实际使用的只有最开头的很少一部分。后续的地址是保留的访问它们可能产生不可预知的行为。而后续 USART1 中寄存器一共有 7 个 (暂时不管是什么我们也不需要全部熟悉需要的时候查就行了)其中每一个寄存器都有一个偏移量地址最终访问任何一个寄存器访问方式都是 0x4001 3800 寄存器偏移。这样每个寄存器的地址清单就是寄存器偏移量 (Offset)地址计算过程最终地址USART_SR0x000x4001 3800 0x000x4001 3800USART_DR0x040x4001 3800 0x040x4001 3804USART_BRR0x080x4001 3800 0x080x4001 3808USART_CR10x0C0x4001 3800 0x0C0x4001 380CUSART_CR20x100x4001 3800 0x100x4001 3810USART_CR30x140x4001 3800 0x140x4001 3814USART_GTPR0x180x4001 3800 0x180x4001 3818有了这些地址CPU 就可以直接访问任意一个寄存器包括我们的数据寄存器 DR。而的 STM32F103ZET6 系列单片机内部包含 5 个串口模块每一个都有自己的地址范围串口模块详细地址清单外设所在总线起始地址结束地址地址空间大小类型USART1APB20x4001 38000x4001 3BFF1 KB高级同步 / 异步串行接口USART2APB10x4000 44000x4000 47FF1 KB通用同步 / 异步串行接口USART3APB10x4000 48000x4000 4BFF1 KB通用同步 / 异步串行接口UART4APB10x4000 4C000x4000 4FFF1 KB通用异步串行接口UART5APB10x4000 50000x4000 53FF1 KB通用异步串行接口主要差别APB2高速外设总线USART1 挂载于此通常运行在最高 72MHzAPB1低速外设总线其余串口挂载于此最高频率 36MHz有的是 USART支持同步、异步有的是 UART仅异步注意区分TDR 与 RDROK现在我们理清了 USART 寄存器方面的思路知道 CPU 核心可以直接通过物理地址访问任意一个 USART 寄存器。⚠️注意CPU 能访问 USART 内部的寄存器那么是谁让 CPU 访问这些寄存器的呢答案是CPU 执行的是你未来写的代码你的代码写了要访问寄存器的指令那么 CPU 才去访问的换句话说CPU 访问 USART 寄存器就是程序员让 CPU 访问的CPU 控制 USART人控制 CPU编程的本质之一就是指导 CPU 工作。在物理上USART_DR 寄存器有两个一个是 TDR一个是 RDR 分别让用户来发和收数据这两个寄存器被映射到了同一个物理地址但是官方没有披露具体是怎么做到访问同一个地址从而做到访问不同寄存器我们可以推测通过操作类型 (rw) 来区分要访问哪一个寄存器。rw : 寄存器中特定的比特位具有 read 和 write 权限地址偏移结合上面的内容该字段很容易理解。虽然 USART_DR 寄存器是 32 位的但是实际使用的只有 9 位因为 USART 可编程数据位最多是 9 位。三、USART发送标志位介绍当发送方要发送数据主要过程分为用户把数据拷贝到 TDR然后你就别管了USART 自己移动到移位寄存器然后再时钟的驱使下开始进行发送也就是 USART 发送对用户来讲是黑盒的可是 USART 发送不是一蹴而就的而是一步一步发的那么万一在发送期间用户又往 TDR 写数据了会发生什么问题场景 1只要 TDR 有数据USART 就要移动到移位寄存器如果没发完数据覆盖错误场景 2USART 把自己的数据发完 TDR 还有数据USART 再移动到移位寄存器再发。USART 真实采用的是这种情况。但是潜台词是用户的数据会因为 USART 在忙而暂时保存在 TDR 中可是这个过程对用户来讲都是透明的用户又不知道用户写完到 TDR如果再写就自己把自己的数据覆盖了。可是无论是场景 1还是场景 2用户不管啊用户又不知道 USART 有没有发完如果覆盖了这个锅谁背啊肯定是 USART要是 TDR 我不能写USART 你得告诉我啊。 所以USART 在自己的收发过程中必须要提供自己收发状态的信息这部分信息叫做 USART 的状态寄存器 (USART_SRUSART Status Register),可以预言该寄存器内部一定有标志位来表明用户是否可以写入 TDR 的寄存器。USART 发送状态信息由这 10 个标志位标识《STM32F103xx 参考手册》看到所有标志位信息。但是现在没必要需要再查现在我们只需要关心的是两个标志位这两个标志位与发送有关。TXE (Transmit data registerempty) 目前需要关注的是当 TDR 寄存器中的数据被 USART 硬件模块转移到移位寄存器的时候该为被硬件设置为 1潜台词就是用户需要检测这个比特位当 TXE 是 1 的时候表明 TDR 空了用户才可以写。这样 USART 数据覆盖的锅甩给了用户从此丰俭由人。 对 USART_DR 进行写入TXE 会自动清 0。这句话的潜台词就是用户发现 TXE 是 1表明 TDR 空了用户可以写用户写入TXE 清零表明 TDR 正在被占用请勿在写。TC (Transmissioncomplete) 目前需要关注的是当包含有数据的一帧发送完成之后并且 TXE 1TDR 为空USART 硬件模块会自动将该位设置为 1。rc: 通常代表 Read‑Clear。这表示是一个 “读取并清除” 的操作wz: 代表 Write Zero。这表示向某个寄存器写入 0。向该位写 0 来清除标志写 1 则无影响这是 STM32 的标准做法r: 代表 Read。这表示一个读取操作阻塞模式发送之前我们讲述的发送过程就是要求用户发送数据的时候必须对 TXE 进行检测如果TXE0表示 TDR 数据并没有平移到发送移位寄存器那么用户就必须阻塞在检测 TXE 标志位的位置处进行等待这种模式就叫做阻塞式发送。在用户角度如果使用阻塞模式进行数据发送一个或者多个数据之后怎么知道 USART 彻底把数据发送出去发送移位寄存器和 TDR 都为空如下图中 ③ 标识的区域是 TC 标志被置 1 时表示要发送的数据已全部发送完成这时如果还有待发送的数据就可以进行发送。四、USART接收标志位介绍当接收方要接收数据主要过程分为在时钟的驱使下 USART 自己识别起始位接受数据移动数据到移位寄存器识别结束位判定接受一个数据帧结束自动校验校验成功自动将数据位平移到 RDR 寄存器用户只需要读取 RDR 寄存器中的数据即可注意根据之前的内容我们知道用户是可以直接用物理地址读取 RDR 的所以读取 RDR 并不困难寄存器偏移量 (Offset)地址计算过程最终地址USART_SR0x000x4001 3800 0x000x4001 3800USART_DR0x040x4001 3800 0x040x4001 3804USART_BRR0x080x4001 3800 0x080x4001 3808USART_CR10x0C0x4001 3800 0x0C0x4001 380CUSART_CR20x100x4001 3800 0x100x4001 3810USART_CR30x140x4001 3800 0x140x4001 3814USART_GTPR0x180x4001 3800 0x180x4001 3818可是用户怎么知道 RDR 内部已经有数据了呢 USART 需要有方式能表示 RDR 寄存器的状态类似发送接收的时候也是状态寄存器 USART_SR 来标识接收状态其中RXNE 标志位就是完成该项工作的。在 UART 数据接收过程中状态寄存器 (USART_SR)当 RDR 寄存器中没有数据的时候RXNE 标志位被设置为 0当 RDR 寄存器中有数据的时候RXNE 标志位被设置为 1RXNE: Read data register not empty如下图中 ①②③ 标识的区域是 RXNE 标志表示读数据寄存器非空 (Read data register not empty)。当接收移位寄存器中的数据被转移到 USART_DR 寄存器中该位被硬件自动置位。对 USART_DR 寄存器的读操作可以将该标志位清零。所以当 USART 在接受数据期间那么用户就应该一直检测 RXNE 标志位只要该标志位一直是 0那么用户就应该一直阻塞在检测的位置直到 RXNE 1 表示有数据了才能读取。阻塞模式接收如果使用阻塞模式进行数据接收程序需要轮询判断如下图所示的 ①②③ 的 RXNE 标志主要逻辑如下RXNE 标志被置 0表示暂时没有数据要求用户轮训检测该标志位标志位为 0就有一直阻塞在这里。收到数据RXNE 标志被置 1表示接收到 1 字节数据用户将读到的数据保存到自己定义内存区域读取的时候会自动触发清除 RXNE 标志然后继续检测 RXNE 等待接收下一个数据。达到期望接收的数据个数或等待数据超时退出本次阻塞模式接收流程。