3. UART硬件架构:发送器、接收器、波特率发生器、FIFO缓冲区、引脚定义(TX、RX、GND)
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是嵌入式系统中最基础也最常用的串行通信外设。与SPI、I2C等同步通信协议不同,UART在硬件层面不需要共享时钟线,而是依靠双方预先约定好的波特率(Baud Rate)在各自独立的时钟域中完成数据采样与恢复。理解UART的硬件架构,是进行串口驱动开发、低功耗设计、多机通信组网以及排查通信故障的基石。本章将深入拆解UART内部五大核心模块——发送器、接收器、波特率发生器、FIFO缓冲区以及外部引脚定义,并结合实际工程场景分析其工作机制与设计要点。
上图展示了UART模块在MCU内部的组成结构及其与外部设备的连接关系。从图中可以看到,UART并非一个单一功能块,而是由发送通道、接收通道、时钟产生与缓冲管理组成的协同系统。下面我们将逐一剖析每个模块的工作原理与工程实现要点。
3.1 发送器(Transmitter)
3.1.1 核心原理:并串转换与帧格式生成
发送器的核心任务是将CPU或DMA写入的并行数据(通常为8位或9位)转换为符合UART协议的串行比特流,并通过TX引脚逐位输出。其内部结构主要包括:发送保持寄存器(THR)、发送移位寄存器(TSR)以及帧控制逻辑。当软件向THR写入数据后,如果TSR空闲,数据会在下一个波特率时钟沿被装载到TSR中,然后按照起始位(1位低电平)→ 数据位(LSB先行)→ 校验位(可选)→ 停止位(1或2位高电平)的顺序移位输出。
一个典型的8-N-1帧格式(8数据位、无校验、1停止位)在TX引脚上的波形时序如下:
空闲(高) | 起始位(低) | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | 停止位(高) | 空闲(高)
|<--------- 1位时间 = 1/波特率 --------->|
发送器必须保证在停止位结束后,TX引脚恢复为高电平(空闲态),以便接收器正确识别下一个起始位的下降沿。
3.1.2 操作流程与判断方法
在实际驱动开发中,判断发送器是否就绪通常依赖状态寄存器中的发送保持寄存器空(THRE)标志或发送移位寄存器空(TSRE)标志。THRE表示THR已空,可以写入下一个字节;TSRE表示整个发送移位过程完成,线路已空闲。若使用FIFO模式,则需关注FIFO的剩余深度。发送流程如下:
- 检查UART状态寄存器中的THRE位或TX FIFO满标志。
- 若允许写入,将数据写入THR或TX FIFO。
- 硬件自动完成并串转换与帧格式封装。
- 若使能发送中断,当THR空或FIFO低于阈值时触发中断。
3.1.3 案例拆解:发送器丢字节问题
背景:某物联网网关设备使用STM32F407的USART1以921600bps波特率向外挂的4G模块发送AT指令,发现偶发性的第一个字节丢失。
分析过程:通过逻辑分析仪抓取TX引脚波形,发现丢失字节时TX引脚在使能发送后并未立即拉低产生起始位。进一步检查代码,发现初始化时先配置了GPIO,再使能UART,但GPIO的复用功能(AF)配置在UART使能之后完成,导致TX引脚在初始时刻处于浮空状态,而非默认高电平。
解决步骤:
- 调整初始化顺序:先配置GPIO复用功能为AF7(USART1),再使能USART外设时钟和USART本身。
- 在发送第一个字节前,增加一个微小延时(如10μs),确保线路稳定为高电平。
- 开启UART的发送完成中断(TC),在TC中断中再发送下一包数据,避免连续写入过快导致帧间隔不足。
结果:修改后连续发送10000帧数据,未再出现丢字节现象。
3.1.4 常见误区与总结
- 误区1:认为TX引脚在空闲时必须为低电平。实际上UART空闲态为高电平,起始位是拉低。
- 误区2:忽略停止位长度。两个设备必须配置相同的停止位位数(1或2),否则接收端会因采样点偏移而出现帧错误。
- 误区3:在关闭UART前未等待TSRE标志。直接关闭外设时钟可能导致正在发送的最后一个字节被截断。
3.2 接收器(Receiver)
3.2.1 核心原理:起始位检测与过采样
接收器的难点在于异步恢复数据。由于没有时钟线,接收器必须持续监测RX引脚的电平变化。当检测到高电平到低电平的跳变(即起始位前沿)时,接收器启动内部波特率计数器,并在每个位周期的中点进行采样,以避开信号边沿的抖动区域。为了提高抗干扰能力,现代UART普遍采用16倍过采样技术:即内部采样时钟频率为波特率的16倍,每个位周期采样16次,取中间3次(第7、8、9次)进行多数表决,以滤除毛刺。
接收器内部结构包括:接收移位寄存器(RSR)、接收缓冲寄存器(RBR)以及错误检测逻辑(帧错误、奇偶校验错误、溢出错误)。
3.2.2 判断方法与错误标志
接收数据时,软件需检查以下状态位:
| 状态标志 | 含义 | 常见原因 |
|---|---|---|
| RXNE (RX Not Empty) | 接收数据寄存器非空,可读取 | 正常接收完成 |
| FE (Frame Error) | 帧错误,停止位无效(收到低电平) | 波特率不匹配、线路干扰、双方帧格式不一致 |
| PE (Parity Error) | 奇偶校验错误 | 数据位翻转、校验位配置不一致 |
| ORE (Overrun Error) | 溢出错误,RBR未及时读取导致新数据覆盖 | CPU响应不及时,未开启FIFO或DMA |
接收流程:检测到起始位 → 过采样确认 → 逐位采样数据位 → 校验停止位 → 将数据装入RBR或RX FIFO → 置位RXNE并触发中断(若使能)。
3.2.3 实战场景:多机通信中的接收冲突
场景描述:在一个RS-485总线上挂载了1个主机和3个从机,采用UART + 方向控制引脚(DE/RE)进行半双工通信。从机A在接收到主机命令后,需要立即回复数据。但调试中发现,从机A回复的数据偶尔会被主机判定为帧错误。
关键参数:波特率9600bps,帧格式8-E-1(偶校验),总线长度约50米。
分析过程:使用示波器观察从机A的TX引脚和RS-485总线A/B差分信号,发现从机A在发送起始位时,总线电平从空闲态(A高B低)切换为驱动态(A低B高)的过程中存在约2μs的建立时间。而主机在检测到起始位下降沿后,立即开始16倍过采样,由于建立时间导致第一个位周期的采样点偏早,采样到了非稳定电平。
解决措施:
- 在从机A的UART发送使能(DE引脚拉高)与数据发送之间增加一个小的延时(约1个位时间的一半,即52μs @9600bps),确保总线完全驱动稳定后再发送起始位。
- 将主机的接收滤波器(如果硬件支持)设置为更保守的模式,增加数字滤波采样次数。
- 检查从机A的DE控制逻辑,确保在发送完成后及时拉低DE,释放总线。
复盘:该问题的根源在于RS-485收发器的使能时间(通常为μs级)与UART起始位边沿之间的竞争。在低速下影响较小,但在高速或长线缆场景下必须考虑驱动芯片的开启延迟。
3.2.4 常见误区与总结
- 误区1:认为接收器在起始位下降沿立即采样第一个数据位。实际上需要等待1.5个位时间(起始位中点+数据位中点)后才采样D0。
- 误区2:忽略过采样率的影响。16倍过采样是标准配置,但部分低功耗MCU为了省电会降低过采样率,这会降低抗噪能力。
- 误区3:在中断服务函数中执行耗时操作(如打印日志),导致RBR溢出。应尽快读取数据存入内存缓冲区。
3.3 波特率发生器(Baud Rate Generator)
3.3.1 核心原理:分频计算
波特率发生器本质上是一个可编程分频计数器。它从系统时钟(或专用外设时钟)获得输入频率,通过分频系数产生发送和接收所需的位时钟。以常见的16倍过采样为例,波特率计算公式为:
波特率 = 外设时钟频率 / (16 × USARTDIV)
其中USARTDIV是一个20位的分频值,包含整数部分和小数部分(通常为12位整数 + 4位小数)。例如,STM32的USART使用PCLK1(通常为36MHz或45MHz),若要产生115200bps,则USARTDIV = 36,000,000 / (16 × 115200) ≈ 19.53125,即整数部分为19,小数部分为0.53125 × 16 = 8.5,取整为8或9(取决于舍入方式)。
3.3.2 误差分析与判断方法
波特率误差是异步通信的大敌。当发送端与接收端的波特率存在偏差时,随着数据位数的增加,采样点会逐渐偏移。对于8位数据帧,允许的最大误差约为±4.5%(理论值),但工程上建议控制在±2%以内。判断波特率是否可接受,可通过以下公式计算:
误差% = (实际波特率 - 理想波特率) / 理想波特率 × 100%
例如,使用14.7456MHz晶振产生115200bps,分频系数为14.7456M / (16 × 115200) = 8.0,误差为0%。而使用12MHz晶振,分频系数为12M / (16 × 115200) = 6.51,取整为6.5,实际波特率 = 12M / (16 × 6.5) = 115384.6,误差为+0.16%,完全可接受。
3.3.3 案例拆解:GPS模块波特率自适应失败
背景:某车载终端使用UBX-G7020 GPS模块,默认波特率为9600。设计需求是让MCU自动检测GPS模块的当前波特率并重新配置为115200。
初始现象:MCU发送UBX配置指令后,GPS模块无响应,但使用PC串口工具手动配置可以成功。
分析过程:检查MCU的波特率寄存器配置,发现系统时钟为72MHz,计算115200的分频系数为72M / (16 × 115200) = 39.0625,取整为39,实际波特率 = 72M / (16 × 39) = 115384.6,误差+0.16%。而9600的分频系数为72M / (16 × 9600) = 468.75,取整为468,实际波特率 = 72M / (16 × 468) = 9615.38,误差+0.16%。理论上均无问题。
关键发现:进一步排查发现,MCU在发送配置指令前,先发送了0x00和0x01两个字节用于“唤醒”GPS模块。但GPS模块在9600波特率下接收时,由于MCU的UART在初始化后TX引脚默认输出高电平,而GPS模块的RX引脚内部有上拉电阻,导致MCU发送的0x00字节(起始位+8个0+停止位)被GPS模块误判为噪声。真正的问题在于MCU发送完唤醒字节后,没有等待GPS模块处理完成(通常需要100ms),立即发送了配置指令,导致GPS模块的接收缓冲区溢出。
解决步骤:
- 在发送唤醒字节后,增加200ms延时。
- 将配置指令拆分为两条:先发送UBX-CFG-PRT(设置波特率),等待ACK,再发送UBX-CFG-SAVE(保存配置)。
- 在MCU端增加超时重试机制,若3秒内未收到ACK,则重新尝试。
结果:修改后,GPS模块在3秒内完成波特率切换,成功率100%。
3.3.4 常见误区与总结
- 误区1:认为波特率设置是“写一个寄存器”那么简单。必须考虑时钟源选择(HSI/HSE/PLL)和分频精度。
- 误区2:忽略小数分频的舍入误差。某些MCU的USARTDIV小数部分只有3位或4位,高波特率下误差会放大。
- 误区3:在运行中动态修改波特率时,未先清空发送和接收FIFO,导致残留数据以旧波特率发送。
3.4 FIFO缓冲区(发送/接收FIFO)
3.4.1 核心原理:硬件环形队列
FIFO(First In First Out)是UART内部的一块RAM,用于暂存待发送或已接收的数据。它的引入解决了两个问题:一是降低CPU中断频率,二是吸收突发数据。以接收FIFO为例,当RX引脚收到一个字节时,硬件自动将其压入FIFO,当FIFO中的数据达到预设阈值(如FIFO深度的一半)时,才触发一次中断。这样CPU可以在一次中断中连续读取多个字节,而不是每个字节都触发一次中断。
典型FIFO深度为16字节或32字节(如STM32的USART具有16字节的TX/RX FIFO,部分高端MCU如i.MX RT系列具有64字节)。FIFO的读写操作由硬件指针管理,软件只需通过数据寄存器访问队头/队尾。
3.4.2 操作流程与配置要点
配置FIFO时需关注以下参数:
| 参数 | 说明 | 推荐值 |
|---|---|---|
| FIFO深度 | 硬件固定,不可配置 | 16/32/64字节 |
| 触发阈值 | 当FIFO中数据量达到该值时触发中断 | 接收:深度/2;发送:深度/2(表示空余空间) |
| DMA请求 | FIFO达到阈值时向DMA控制器发出请求 | 使能,配合DMA实现零拷贝传输 |
| 溢出行为 | FIFO满时新数据是否覆盖旧数据 | 通常选择丢弃新数据并置ORE标志 |
发送FIFO的写入操作:软件向发送数据寄存器写入数据,硬件将其压入FIFO。当FIFO未满时,TXE(发送寄存器空)标志为1。若FIFO已满,继续写入会导致数据丢失(部分MCU会置位溢出标志)。
3.4.3 实战场景:高吞吐数据采集中的FIFO配置
背景:某工业数据采集器通过UART以3Mbps波特率接收来自ADC模块的连续数据流,每帧包含64字节。MCU主频为168MHz,需要将数据实时转发到以太网。
约束条件:CPU中断响应时间约为2μs,以太网DMA传输每包需要约10μs。若每个字节触发一次中断,CPU将完全被中断淹没。
方案设计:
- 启用UART的32字节RX FIFO,设置触发阈值为16字节。
- 配置DMA控制器,将UART RX FIFO的数据直接搬运到内存缓冲区,DMA传输完成(传输64字节)后触发一次中断。
- 在DMA中断中,将缓冲区数据封装为以太网帧并交给MAC发送。
关键参数:DMA传输模式为循环模式,缓冲区大小256字节,每次传输64字节后产生传输半满/全满中断。
结果:CPU中断频率从3Mbps/8bit=375kHz降低到3Mbps/(64×8)=5.86kHz,CPU占用率从约80%降至15%。
风险与代价:DMA缓冲区需要精心管理,防止数据覆盖。若ADC模块发送的帧间隔不稳定,可能导致DMA缓冲区错位。解决方案是使用双缓冲区(Ping-Pong),在DMA传输半满和全满时交替切换。
3.4.4 常见误区与总结
- 误区1:认为FIFO越大越好。过大的FIFO会增加数据延迟,不适合实时性要求高的控制指令。
- 误区2:忽略FIFO的复位操作。在修改UART配置(如波特率、帧格式)前,必须先复位FIFO,否则残留数据会导致后续通信错乱。
- 误区3:在FIFO模式下仍使用查询单个字节的RXNE标志。应使用FIFO阈值中断或DMA,否则FIFO形同虚设。
3.5 引脚定义:TX、RX、GND
3.5.1 核心原理:信号方向与电平标准
UART的物理连接非常简单,但引脚定义的正确性直接决定通信成败。三个基本引脚的功能如下:
- TX(Transmit Data):发送数据输出引脚。空闲时为高电平,发送时输出串行比特流。该引脚应连接到对端设备的RX引脚。
- RX(Receive Data):接收数据输入引脚。检测外部输入的串行信号。该引脚应连接到对端设备的TX引脚。
- GND(Ground):信号地。两个设备必须共地,否则无法保证逻辑电平的参考一致,可能导致通信失败甚至损坏芯片。
值得注意的是,UART的TX/RX引脚通常为TTL电平(0~3.3V或0~5V)。当与PC通信时,需要使用RS-232电平转换芯片(如MAX3232)或USB转TTL工具。RS-232电平为±12V,与TTL不兼容。
3.5.2 判断方法与连接检查
在硬件调试中,检查引脚连接是否正确,可使用以下方法:
- 万用表通断测试:确认设备A的TX与设备B的RX之间导通,设备A的RX与设备B的TX之间导通,双方GND相连。
- 示波器测量:在设备A发送数据时,用示波器探头测量设备A的TX引脚,应能看到明显的电平跳变(从高到低再回到高)。若TX引脚始终为高或低,说明发送器未工作或配置错误。
- 回环测试:将设备自身的TX与RX短接,发送数据后检查是否能收到相同数据。这是验证UART硬件通路是否完好的最简方法。
3.5.3 案例拆解:RS-485总线中的引脚接反
背景:某工厂部署了一套基于RS-485的传感器网络,共32个节点。调试时发现所有节点均无法通信,但单独测试每个节点与主机的点对点通信正常。
现象:主机发送命令后,总线上无任何响应。
分析过程:使用示波器测量主机端的A/B差分信号,发现主机发送时A/B之间有正常的差分电压(约2V)。但测量远端节点时,发现A/B线序接反——部分节点将A线接到了自己的B端,B线接到了A端。由于RS-485是差分信号,A/B接反会导致逻辑电平完全反转,接收端无法正确解析数据。
解决步骤:
- 使用万用表逐一测量每个节点的A/B线序,标记错误节点。
- 统一所有节点的A/B接线标准:A接A,B接B。
- 在主机端增加终端电阻(120Ω),消除反射。
结果:重新上电后,32个节点全部通信正常。