当前位置: 首页 > news >正文

UART寄存器详解:从RHR/THR到中断控制,构建稳定串口通信

1. UART寄存器:从硬件接口到软件控制的桥梁

在嵌入式开发和通信接口调试中,UART(通用异步收发传输器)是我们最常打交道的模块之一。无论是通过串口打印调试信息,还是与传感器、蓝牙模块通信,UART都扮演着核心角色。很多开发者习惯使用操作系统或库函数提供的封装好的API,比如printfreadwrite,这确实方便,但一旦遇到通信不稳定、数据丢失或者需要极致优化性能的场景,仅仅停留在API层面就显得力不从心了。这时,深入寄存器层面,理解每一个控制位的含义,就成了解决问题的关键。这就像开车,会踩油门刹车能上路,但懂发动机原理和变速箱逻辑才能玩转性能改装和故障排查。

UART通信的本质,是CPU通过一组特定的内存地址(即寄存器)与一个专用的硬件模块对话。这个模块内部有移位寄存器负责串行数据的收发,有FIFO(先进先出队列)缓冲数据,还有一套复杂的状态机和中断逻辑来协调整个流程。我们写的每一行配置代码,最终都转化为对特定寄存器比特位的读写操作。RHR(接收保持寄存器)和THR(发送保持寄存器)是数据进出的门户,IER(中断使能寄存器)和IIR(中断标识寄存器)则是整个系统的“神经系统”,负责及时通知CPU有事件需要处理。而FCR(FIFO控制寄存器)、LCR(线路控制寄存器)等则像是一系列旋钮和开关,精细地调整着通信的波特率、数据格式和缓冲策略。本文将基于一份详实的芯片手册(以TI某款支持UART/IrDA/CIR的多模式芯片为例),拆解这些关键寄存器的每一个比特,并结合实际驱动开发中的场景,分享如何配置它们来构建稳定、高效的串口通信。无论你是正在调试一个棘手的通信丢包问题,还是希望为自己的产品设计一个健壮的串口驱动,这些寄存器级的细节都将为你提供坚实的底层支撑。

2. 核心数据通道:RHR与THR寄存器详解

2.1 接收保持寄存器(RHR):数据抵达的第一站

RHR,全称Receiver Holding Register,是CPU从串口读取接收数据的唯一窗口。它的工作原理背后,隐藏着UART接收路径的精巧设计。接收数据从RX引脚进入,首先由一个接收移位寄存器(Receiver Shift Register)进行串并转换。这个移位寄存器像是一个小型的传送带,每一位数据(起始位、数据位、校验位、停止位)随着波特率时钟依次移入。当一整帧数据(例如8个数据位)接收完毕,且校验(如果使能)通过后,这整个字节才会被并行地“搬运”到RHR中,等待CPU读取。

手册中指出,RHR实际上是一个64字节的FIFO。这是一个至关重要的优化。如果没有FIFO,RHR就只是一个单字节的存储单元。这意味着CPU必须在下一个字节被接收并覆盖当前值之前,及时读走数据,否则就会发生数据覆盖(Overrun)。而64字节的FIFO提供了缓冲能力,允许CPU在一定时间内不处理数据,而硬件可以持续接收多达64个字节,极大地减轻了CPU的中断响应压力。当FIFO被禁用时(通过FCR寄存器),这个FIFO的“0号位置”就被当作一个单字节的RHR来使用。

注意:手册特别强调了一点——“If an overflow occurs, the data in the RHR is not overwritten.” 这句话需要正确理解。这里的“overflow”指的是接收移位寄存器中的数据已经准备好移入RHR FIFO,但FIFO已满的情况。此时,移位寄存器中的新数据会丢失(这就是Overrun错误),但FIFO中已存的数据是安全的,不会被新数据冲掉。这保证了已接收数据的完整性,但代价是丢失了最新的数据。对应的错误状态会在LSR(线路状态寄存器)的RXOE位标记。

从编程角度看,RHR是一个只读寄存器。你无法向它写入数据,只能从中读取。它的位域非常简单,低8位(Bit 7-0)就是接收到的数据字节,高8位(Bit 15-8)保留。读取RHR的操作会同时做两件事:一是将数据返回给CPU,二是使FIFO的读指针前进一位(如果FIFO使能),或者清空单字节缓冲区。因此,在中断服务程序中,我们通常通过循环读取RHR来清空FIFO,直到LSR寄存器显示RX FIFO为空(RXFIFOE位为0)。

2.2 发送保持寄存器(THR):数据出发的起点

与RHR相对应,THR(Transmit Holding Register)是CPU向串口写入待发送数据的入口。其工作流程是:CPU将需要发送的数据字节写入THR。如果FIFO功能使能,数据会先进入64字节的发送FIFO中排队。然后,UART模块内部的发送移位寄存器(Transmit Shift Register)会从发送FIFO中取出数据,将其从并行格式转换为串行比特流,加上起始位、校验位和停止位,最终通过TX引脚一位一位地发送出去。

THR也是一个FIFO,这同样是为了提升效率。CPU可以一次性写入多个字节到THR(即发送FIFO),而不必等待每个字节发送完毕。UART硬件会自主地、连续地从FIFO中取出数据发送,从而解放了CPU。当FIFO被禁用时,THR同样退化为一个单字节的寄存器。

从寄存器描述看,THR的低8位(Bit 7-0)是有效数据位,高8位保留。关键点在于,THR是一个只写寄存器(对CPU而言)。这意味着你向这个地址写入数据,操作的是发送保持器;但你从这个地址读取,读回来的值是不确定的(手册标注为W-unknown),并非当前FIFO中等待发送的数据。要了解发送FIFO的状态,需要查询LSR(线路状态寄存器)TXFIFOE(发送FIFO空)和TXSRE(发送移位寄存器空)位。

实操心得:THR写入与流控制在实际编程中,向THR写入数据前,一个良好的习惯是检查LSR的TXFIFOE位。如果该位为1,表示发送FIFO已空,可以安全写入。如果使用FIFO且未使能硬件流控,盲目连续写入超过FIFO深度的数据会导致数据丢失。更稳健的做法是结合IER中的THRIT(发送保持寄存器中断)。当发送FIFO中的数据量低于某个阈值(例如变空)时,会触发中断,在中断服务程序中再填充新的数据,这样可以实现无缝的连续发送。

3. 中断系统的指挥官:IER与IIR寄存器解析

中断是提高CPU效率、实现异步事件处理的关键机制。UART的中断系统主要由IER和IIR这一对寄存器协同管理。

3.1 中断使能寄存器(IER):决定谁可以“打报告”

IER(Interrupt Enable Register)就像一个总开关板,决定哪些UART内部事件可以产生中断请求(IRQ)。手册中展示了三种模式下的IER:UART模式、IrDA模式和CIR模式。我们以最常用的UART模式为例进行深度解析。

UART模式的IER寄存器(图24-30)低8位每一位控制一个中断源的使能:

  • Bit 0 - RHRIT:接收保持寄存器中断使能。当RHR(接收FIFO)中的数据达到触发阈值(由FCR或TLR设置),或发生接收超时(如果支持)时,此中断被触发。这是最常用的数据接收中断。
  • Bit 1 - THRIT:发送保持寄存器中断使能。当发送FIFO中的数据量低于触发阈值(通常为空时),此中断被触发,通知CPU可以发送更多数据。
  • Bit 2 - LINESTSIT:接收线路状态中断使能。当发生接收错误(如溢出OE、奇偶校验错PE、帧错误FE、线路间断BI)时触发。这是一个错误处理中断,优先级通常最高。
  • Bit 3 - MODEMSTSIT:调制解调器状态中断使能。当CTS、RTS、DSR等调制解调器控制线的状态发生变化时触发。用于硬件流控制。
  • Bit 4 - SLEEPMODE:睡眠模式使能。此位用于在UART空闲时停止波特率时钟以节能。
  • Bit 5 - XOFFIT:XOFF/特殊字符中断使能。当接收到XOFF流控字符或特定字符时触发。
  • Bit 6 - RTSIT:RTS中断使能。当RTS引脚状态变化时触发。
  • Bit 7 - CTSIT:CTS中断使能。当CTS引脚状态变化时触发。

关键点:Bit 5, 6, 7 (XOFFIT, RTSIT, CTSIT) 和 Bit 4 (SLEEPMODE) 的写入有一个前提条件:必须当EFR[4](增强功能寄存器第4位)为1时才可写。这是一个硬件保护机制,防止意外修改这些高级功能位。在初始化时,如果需要使用这些功能,必须先解锁EFR。

配置策略: 对于大多数简单应用,通常使能RHRIT(接收中断)和LINESTSIT(线路错误中断)即可。如果需要高效的连续发送(如打印大量日志),可以同时使能THRIT(发送中断)。如果设备连接了调制解调器或需要硬件流控,则需要使能MODEMSTSIT、CTSIT等。初始化代码通常如下所示(假设寄存器地址映射到uart_base):

// 假设已设置好波特率、数据格式(LCR) // 1. 如果需要设置高级中断(如CTSIT),先解锁EFR(如果支持) // *(uart_base + EFR_OFFSET) |= (1 << 4); // 解锁,具体地址取决于硬件 // 2. 配置IER:使能接收中断和线路状态中断 *(uart_base + IER_OFFSET) = (1 << 0) | (1 << 2); // 使能 RHRIT 和 LINESTSIT // 如果需要发送中断 // *(uart_base + IER_OFFSET) |= (1 << 1); // 使能 THRIT

3.2 中断标识寄存器(IIR):识别是谁“打了报告”

当CPU接收到UART中断请求时,第一个动作就是读取IIR(Interrupt Identification Register)。这是一个只读寄存器,它的核心作用是告诉CPU,当前所有已使能的中断源中,优先级最高的是哪一个。IIR的读取本身不会清除中断,但提供了识别中断源所需的信息。

UART模式下的IIR(图24-33)关键字段如下:

  • Bit 0 - IT_PENDING:中断挂起标志。这是你首先要看的位。
    • 0:有中断待处理。
    • 1:无中断待处理。注意:这个逻辑是反的,0表示有中断,1表示没有。这是历史原因,为了兼容早期16550 UART芯片。
  • Bit 5-1 - IT_TYPE:中断类型字段。这是一个5位字段,其值直接对应最高优先级的中断源。手册表24-15给出了详细的映射:
    • 0:Modem状态中断(优先级4)。由CTS、RTS、DSR等变化引起。
    • 1h(1):THR中断(优先级3)。发送FIFO空或低于阈值。
    • 2h(2):RHR中断(优先级2)。接收FIFO达到触发阈值。
    • 3h(3):接收线路状态错误(优先级1)。包括OE、PE、FE、BI。这是最高优先级的可屏蔽中断
    • 6h(6):接收超时中断(优先级2)。当接收FIFO非空,但在一段时间内没有收到新字符也没有被读空时触发。
    • 8h(8):XOFF/特殊字符中断(优先级5)。
    • 10h(16):CTS/RTS从低到高变化中断(优先级6)。
  • Bit 7-6 - FCR_MIRROR:FCR[0]的镜像。反映了FIFO是否使能。

中断处理流程与优先级: 中断优先级是固定的,由硬件决定。线路状态错误(优先级1)最高,因为它表示通信链路出了问题,需要立即处理。其次是接收数据就绪(RHR中断和超时中断,优先级2),确保数据不被覆盖。然后是发送就绪(THR中断,优先级3),最后是其他状态中断。在中断服务程序(ISR)中,标准的处理模式是一个循环,因为一次中断可能对应多个事件(尤其是读取RHR后FIFO中仍有数据),或者处理完一个高优先级中断后,低优先级中断依然存在。伪代码如下:

void UART_ISR(void) { uint16_t iir_value; do { iir_value = *(uart_base + IIR_OFFSET); // 检查是否有中断挂起(Bit 0为0表示有) if (iir_value & 0x01) { break; // 无中断挂起,退出循环 } // 根据中断类型字段(Bit 5-1)处理不同中断 switch ((iir_value >> 1) & 0x1F) { // 提取IT_TYPE字段 case 0x03: // 011b,线路状态错误(优先级1) handle_line_status_error(); break; case 0x02: // 010b,接收数据就绪(优先级2) case 0x06: // 110b,接收超时(优先级2) handle_receive_data(); break; case 0x01: // 001b,发送保持寄存器空(优先级3) handle_transmit_ready(); break; case 0x00: // 000b,Modem状态变化(优先级4) handle_modem_status(); break; // ... 处理其他中断类型 default: // 未知中断类型,可能是错误 break; } // 某些中断(如读LSR清除错误、读RHR减少数据)会改变中断状态 // 循环检查是否还有其他挂起的中断 } while (1); }

重要提示:手册在IIR描述的开头有一个关键注释:“An interrupt source can be flagged only if enabled in the IER register.” 这意味着,即使硬件发生了某个事件(如接收FIFO满),如果IER中没有使能对应的中断位,这个事件也不会在IIR中标识出来,更不会向CPU发起中断请求。IIR只反映那些“已使能且已发生”的中断源中优先级最高的一个。因此,IER和IIR必须配合理解。

4. 数据缓冲与流程控制:FCR、TCR与TLR寄存器

4.1 FIFO控制寄存器(FCR):缓冲区的管理核心

FCR(FIFO Control Register)是管理64字节收发FIFO的核心。它是一个只写寄存器,这意味着你无法通过读FCR来确认当前设置,其设置会反映在IIR的FCR_MIRROR位上。

  • Bit 0 - FIFO_EN:FIFO总使能位。此位只能在波特率时钟停止时(即DLL和DLH分频器为0时)更改。这通常意味着需要在UART初始化早期、设置波特率之前配置它。置1启用64字节FIFO,置0则禁用FIFO,使THR和RHR退化为单字节寄存器。
  • Bit 1 - RX_FIFO_CLEAR:接收FIFO清除位。写1会立即清空接收FIFO并重置其内部计数器。该位会在操作完成后自动清零。在通信开始前或发生错误后清空FIFO是个好习惯。
  • Bit 2 - TX_FIFO_CLEAR:发送FIFO清除位。写1会立即清空发送FIFO并重置其内部计数器。同样会自动清零。
  • Bit 3 - DMA_MODE:DMA模式选择。此位也需在波特率时钟停止时更改。如果SCR[0]=0,此位有效。0为DMA模式0(无DMA),1为DMA模式1(使用特定的DMA请求信号)。启用DMA可以进一步解放CPU,让数据在内存和UART FIFO之间直接搬运。
  • Bit 5-4 - TX_FIFO_TRIG:发送FIFO触发水平。仅在EFR[4]=1时可写。它定义了在DMA模式或中断模式下,发送FIFO在什么情况下产生DMA请求或THR中断(当FIFO数据量低于此阈值时)。具体阈值取决于SCR[6]和TLR[3:0]的配置,是一个多层选择逻辑(详见表24-29)。
  • Bit 7-6 - RX_FIFO_TRIG:接收FIFO触发水平。定义了接收FIFO在达到多少字节时产生RHR中断或DMA请求。其配置逻辑与TX_FIFO_TRIG类似,取决于SCR[7]和TLR[7:4](详见表24-28)。

FIFO触发水平配置逻辑详解: 手册表24-28和24-29的描述初看复杂,实则是一个灵活的优先级配���系统。以接收FIFO触发水平(RX_FIFO_TRIG)为例:

  1. 如果SCR[7] = 0 且 TLR[7:4] ≠ 0000:触发水平由TLR[7:4]单独决定,范围为4到60字节,步进为4字节。此时FCR[7:6]被忽略。
  2. 如果SCR[7] = 1:触发水平由TLR[7:4]和FCR[7:6]拼接成一个6位的值决定(TLR[7:4]为高4位,FCR[7:6]为低2位),范围为1到63字节,步进为1字节。这提供了最精细的控制。
  3. 如果SCR[7] = 0 且 TLR[7:4] = 0000:触发水平由FCR[7:6]决定,有四个固定档位:00b对应8字符,01b对应16字符,10b对应56字符,11b对应60字符。

这种设计允许开发者根据系统中断响应时间、数据包大小和CPU负载,在灵活性(1字节步进)和配置简便性(4个预设档位)之间做出选择。对于发送FIFO触发水平(TX_FIFO_TRIG),逻辑完全对称,只是相关的控制位是SCR[6]和TLR[3:0]。

4.2 触发水平寄存器(TLR)与传输控制寄存器(TCR)

TLR(Trigger Level Register)和TCR(Transmission Control Register)提供了更高级的FIFO和流控制功能。

TLR寄存器(图24-45)直接存储了用于DMA和中断生成的收发FIFO触发水平值。它分为高4位(RX_FIFO_TRIG_DMA)和低4位(TX_FIFO_TRIG_DMA),分别对应接收和发送。如前所述,它们的实际作用与SCR寄存器的设置紧密相关。TLR的价值在于,当SCR相应位为1时,它与FCR中的2位组合,能实现1字节步进的精细控制;当SCR为0且TLR非零时,它能提供4字节步进的中等粒度控制。

TCR寄存器(图24-43)专门用于硬件流控制(如自动RTS/CTS)。它定义了接收FIFO的“水位线”:

  • Bit 3-0 - RXFIFOTRIGHALT:接收FIFO触发水平(用于停止传输)。当接收FIFO中的数据量达到或超过此阈值时,如果使能了自动RTS,UART会拉高RTS信号(变为无效),通知对端停止发送。
  • Bit 7-4 - RXFIFOTRIGSTART:接收FIFO触发水平(用于恢复传输)。当接收FIFO中的数据被CPU读走,存量低于此阈值时,UART会拉低RTS信号(变为有效),通知对端可以恢复发送。

手册中的关键警告:必须确保TCR[3:0] > TCR[7:4],即停止传输的水位线必须高于恢复传输的水位线,形成一个“滞回区间”。这是为了防止RTS信号在临界点附近频繁跳变,导致通信不稳定。例如,设置RXFIFOTRIGHALT=48(当FIFO数据>=48字节时请求暂停),RXFIFOTRIGSTART=16(当FIFO数据<=16字节时恢复)。这样,只有当FIFO从48字节以上被消耗到16字节以下时,才会恢复通信,避免了在48字节附近震荡。

5. 通信参数与状态监控:LCR、LSR与MSR寄存器

5.1 线路控制寄存器(LCR):定义通信协议

LCR(Line Control Register)决定了UART通信的“语言规则”,即一帧数据的具体格式。所有通信双方必须使用相同的LCR设置。

  • Bit 1-0 - CHAR_LENGTH:字符长度。00=5位,01=6位,10=7位,11=8位。最常用的是8位数据(11)。
  • Bit 2 - NB_STOP:停止位数量。0=1个停止位(适用于5-8位字长)。1:如果字长为5位,则为1.5个停止位;如果字长为6、7、8位,则为2个停止位。绝大多数应用使用1个停止位(0)。
  • Bit 3 - PARITY_EN:奇偶校验使能。0=无校验,1=使能校验位生成和检查。
  • Bit 4 - PARITY_TYPE1Bit 5 - PARITY_TYPE2:共同定义校验类型。当PARITY_EN=1时:
    • 如果PARITY_TYPE2=0,则PARITY_TYPE1选择奇偶性:0=奇校验,1=偶校验。
    • 如果PARITY_TYPE2=1,则为强制校验模式:PARITY_TYPE1=0则强制校验位为1,PARITY_TYPE1=1则强制校验位为0。此模式较少使用。
  • Bit 6 - BREAK_EN:间断控制位。这是一个需要谨慎使用的功能。当此位置1时,TX线路会被强制拉低(逻辑0),并持续保持,直到此位被清零。这用于向对端发送一个“间断”信号,通常表示通信中断或作为特定协议的帧起始/结束标志。手册特别用Note强调:“As soon as LCR[6] is set to 1, the TX line is forced to 0 and remains in this state as long as LCR[6] = 1.” 编程时务必控制好置位时间,通常是一个字符帧的时间长度。
  • Bit 7 - DIV_EN:分频器锁存使能位。这是一个特殊功能位。当需要设置波特率时,我们必须先写LCR,将DIV_EN置1,这样才能访问DLL(波特率低分频锁存器)和DLH(波特率高分频锁存器)进行波特率设置。设置完成后,通常需要将DIV_EN清零,以恢复正常操作,访问RHR、THR等数据寄存器。

LCR配置示例(8位数据,1位停止,无校验):

// 设置通信格式:8位数据,1停止位,无校验 *(uart_base + LCR_OFFSET) = 0x03; // 二进制 0000 0011, CHAR_LENGTH=11, 其他位为0 // 如果需要设置波特率,先置位DIV_EN // *(uart_base + LCR_OFFSET) |= (1 << 7); // 设置DIV_EN=1 // ... 然后写入DLL和DLH ... // *(uart_base + LCR_OFFSET) &= ~(1 << 7); // 清除DIV_EN,恢复正常模式

5.2 线路状态寄存器(LSR):实时通信健康仪表盘

LSR(Line Status Register)是一个只读寄存器,提供了数据收发状态和错误信息的实时快照。它是诊断通信问题最重要的工具。UART模式的LSR(图24-39)各位含义如下:

  • Bit 0 - RXFIFOE:接收FIFO空。0=FIFO中有数据,1=FIFO空。这是轮询方式接收数据时最常查询的位。
  • Bit 1 - RXOE:接收溢出错误。1表示发生溢出。当接收移位寄存器中的数据已准备好,但接收FIFO已满,无法存入时,此位置1,并且移位寄存器中的数据会丢失。此位在读LSR时被清除
  • Bit 2 - RXPE:接收奇偶校验错误。1表示当前位于RX FIFO顶部的字符(即下一个将被RHR读出的字符)存在奇偶校验错误。
  • Bit 3 - RXFE:接收帧错误。1表示当前位于RX FIFO顶部的字符存在帧错误(如缺少有效的停止位)。
  • Bit 4 - RXBI:接收间断指示。1表示检测到线路间断(RX线被拉低超过一个完整字符帧的时间)。
  • Bit 5 - TXFIFOE:发送FIFO空。0=发送FIFO非空,1=发送FIFO空。注意:此位为1仅表示FIFO空,但发送移位寄存器可能还在发送最后一个字节
  • Bit 6 - TXSRE:发送移位寄存器空。0=发送移位寄存器非空,1=发送移位寄存器和发送FIFO都为空。此位为1才表示所有数据已物理发送完毕。
  • Bit 7 - RXFIFOSTS:接收FIFO错误状态。1表示接收FIFO中至少存在一个带有错误(PE、FE或BI)的字符。只有当FIFO中所有错误字符都被读取后,此位才会清零。

LSR使用要点

  1. 错误位关联性:Bit 2, 3, 4 (RXPE, RXFE, RXBI) 反映的是下一次通过RHR读取的那个字符的错误状态。读取RHR后,这些错误状态会更新为FIFO中下一个字符的状态。
  2. 错误清除:读取LSR寄存器会清除Bit 1 (RXOE)。而Bit 2,3,4的错误状态在读取对应的错误字符(通过RHR)后更新。Bit 7 (RXFIFOSTS) 在FIFO中所有错误字符被读走后清零。
  3. 发送完成判断:如果需要确保所有数据(包括在移位寄存器中的)都已发出,应查询TXSRE位(Bit 6),而不是TXFIFOE位(Bit 5)。

5.3 调制解调器状态寄存器(MSR)

MSR(Modem Status Register)用于监控和响应UART与外部设备(如传统调制解调器)之间的硬件控制信号(DCD, RI, DSR, CTS)。在现代嵌入式系统中,这些引脚常被复用为硬件流控制(RTS/CTS)或通用IO。

  • Bit 0 - CTS_STS:CTS状态变化。1表示CTS输入引脚的状态发生了变化(从高到低或从低到高)。读MSR后清零。
  • Bit 1 - DSR_STS:DSR状态变化。
  • Bit 2 - RI_STS:RI状态变化(从低到高,即上升沿)。
  • Bit 3 - DCD_STS:DCD状态变化。
  • Bit 4 - NCTS_STS:CTS输入信号的反相值。即NCTS_STS = !CTS
  • Bit 5 - NDSR_STS:DSR输入信号的反相值。
  • Bit 6 - NRI_STS:RI输入信号的反相值。
  • Bit 7 - NCD_STS:DCD输入信号的反相值。

Bit 4-7提供了信号的瞬时电平,而Bit 0-3提供了信号的变化事件。在硬件流控制中,我们通常更关心CTS的瞬时电平(Bit 4)来判断是否允许发送,同时也可以通过使能IER中的CTSIT中断,在CTS变化时得到通知。在环回测试模式(MCR[4]=1)下,这些位反映的是MCR[3:0]循环回来的值,用于自检。

6. 模式配置与高级功能:MDR1、MDR2及其他寄存器

6.1 模式定义寄存器(MDR1与MDR2)

MDR1(Mode Definition Register 1)是决定UART工作模式的核心寄存器。其最低3位MODESELECT(Bit 2-0)必须在初始化时配置,且在正常操作中不应更改。

  • 0: UART 16x模式(标准模式,使用16倍波特率时钟采样)。
  • 1: SIR模式(IrDA,最高115.2kbps)。
  • 2h: UART 16x自动波特率检测模式。
  • 3h: UART 13x模式(某些老式设备兼容)。
  • 4h: MIR模式(IrDA,0.576-1.152Mbps)。
  • 5h: FIR模式(IrDA,最高4Mbps)。
  • 6h: CIR模式(消费电子红外遥控)。
  • 7h: 禁用模块(默认状态)。注意:手册提到,即使模块被禁用,如果IER中使能了中断,UART模式的中断仍然可能产生。这需要在软件设计中考虑。

MDR1的其他位用于IrDA/CIR模式下的特定功能,如帧结束模式、SIP(串行红外脉冲)模式、红外睡眠模式等。

MDR2(Mode Definition Register 2)提供了一些额外的配置:

  • Bit 0 - IRTXUNDERRUN:IrDA发送欠载状态位。当发生TX状态中断(IIR[5])时,读取此位可判断是正常发送完成(0)还是发生了欠载错误(1)。
  • Bit 2-1 - STSFIFOTRIG:仅IrDA模式有效,设置帧状态FIFO的触发阈值。
  • Bit 6 - IRRXINVERT:红外接收引脚反相控制。因为大多数红外收发器会对信号反相,此位默认0(执行反相)以确保模块级逻辑正确。

6.2 其他关键寄存器

  • SCR(Scratchpad Register):这是一个通用的8位读/写寄存器,不控制任何硬件功能。驱动程序可以用它来存储临时变量或作为软件标志,在需要与UART硬件紧密耦合的代码中提供便利。
  • MCR(Modem Control Register):用于控制输出到调制解调器的信号(DTR, RTS)以及启用环回测试模式(LOOPBACKEN)。环回模式对于驱动自检和硬件调试极其有用,它将TX输出内部连接到RX输入,并将MCR的输出信号循环到MSR的输入状态位。
  • DLL/DLH(Divisor Latch):波特率分频器。波特率 = 输入时钟频率 / (16 * 分频值)。分频值 = DLH << 8 | DLL。设置它们前,必须将LCR的DIV_EN位置1。

7. 寄存器编程实战与避坑指南

7.1 UART初始化标准流程

一个健壮的UART初始化应遵循以下步骤,特别是对于支持FIFO和多种模式的复杂UART:

  1. 关闭中断:向IER寄存器写入0,禁用所有中断源。
  2. 复位并清空FIFO:向FCR寄存器写入0x07(Bit2,1,0为1),这将清空TX和RX FIFO,并暂时禁用FIFO(如果之前使能了)。注意,FIFO_EN的最终设置可能要在后面。
  3. 设置波特率: a. 写LCR,将DIV_EN位置1,解锁DLL/DLH。 b. 根据输入时钟和期望波特率计算分频值,写入DLL和DLH。 c. 写LCR,清除DIV_EN位,恢复对数据/控制寄存器的访问。
  4. 设置通信格式:写LCR,配置数据位、停止位、校验位。
  5. 配置FIFO和触发水平: a. 如果需要使用高级功能(如可编程触发水平、DMA模式),可能需要先写EFR解锁(如果芯片支持)。 b. 根据SCR、TLR、FCR的联动关系,配置所需的RX/TX FIFO触发水平。 c. 向FCR写入最终值,使能FIFO(Bit 0 = 1)并设置好触发水平位。
  6. 设置工作模式:向MDR1写入目标模式值(如0x00 for UART 16x)。
  7. 配置调制解调器控制:向MCR写入所需值,如使能RTS(如果用于硬件流控)。
  8. 使能中断:最后,向IER写入需要的中断使能位。这确保了在硬件完全初始化好之前,不会产生意外中断。

7.2 常见问题排查与调试技巧

  1. 收不到数据(中断方式)

    • 检查IER:确认RHRIT(Bit 0)是否已使能。
    • 检查IIR:在中断服务程序中,首先读取IIR,确认IT_PENDING位为0且有中断挂起,并检查IT_TYPE字段是否为2(RHR中断)或6(超时中断)。
    • 检查LSR:读取LSR,确认RXFIFOE位为0(有数据),并检查RXOE、RXPE、RXFE、RXBI等错误位。
    • 检查FIFO触发水平:如果一直不中断,可能是触发水平设置过高(例如设置为56),而发送方每次只发几个字节。可以尝试降低RX_FIFO_TRIG水平,或使用接收超时中断。
  2. 发送数据卡住或丢失

    • 检查LSR:发送前检查TXFIFOE位,确保FIFO未满。发送完成后检查TXSRE位,确认所有数据已移出。
    • 检查硬件流控:如果使用了CTS/RTS,检查MSR的NCTS_STS位,确认CTS信号是否有效(低电平允许发送)。检查MCR的RTS位输出是否正确。
    • 检查THR写入时机:在中断驱动发送中,确保只在THR中断(THRIT)触发,或明确查询到TXFIFOE为空时,才写入THR。盲目写入会导致数据覆盖。
  3. 通信数据错误(乱码)

    • 核对LCR:确保通信双方的数据位、停止位、校验位设置完全一致。这是最常见的原因。
    • 检查波特率:计算分频值是否正确,输入时钟频率是否准确。可以使用示波器测量TX引脚上一个位的实际时长来反推实际波特率。
    • 检查LSR错误位:定期读取LSR,检查RXPE、RXFE、RXBI位。奇偶校验错或帧错误直接指向物理层问题(干扰、电平不匹配、波特率偏差)。
    • 启用环回测试:将MCR的LOOPBACKEN位置1,然后自发自收。如果环回模式下数据正确,则问题很可能在外部线路或对端设备上。
  4. 中断无法触发或触发过于频繁

    • 确认IIR和IER的匹配:记住,IIR只反映IER中已使能的中断源。如果一个中断在IER中未使能,即使硬件事件发生,IIR也不会显示,CPU也不会收到中断请求。
    • 理解中断清除机制
      • RHR中断:读取RHR数据,当FIFO数据量低于触发水平时,中断条件消失。
      • THR中断:向THR写入数据,当FIFO数据量超过触发水平时,中断条件消失。
      • 线路状态中断:读取LSR寄存器会自动清除OE错误位,但PE、FE、BI错误位在对应的错误字符被从RHR读出后才更新。
      • Modem状态中断:读取MSR寄存器会清除Bit 0-3的变化标志位。
    • 中断风暴:如果接收FIFO触发水平设置为1,且数据持续高速涌入,可能会造成频繁中断。可以考虑提高触发水平,或使用DMA进行数据搬运。

寄存器操作原子性:在对多位寄存器(如LCR、IER)进行部分位修改时,应采用“读-修改-写”操作,避免影响其他位。例如,要使能RHR中断而不影响其他位:

uint8_t ier_value = *(uart_base + IER_OFFSET); ier_value |= (1 << 0); // 设置Bit 0 (RHRIT) 为1 *(uart_base + IER_OFFSET) = ier_value;

深入理解UART寄存器,意味着你掌握了与这个硬件模块直接对话的能力。从配置通信格式、管理数据缓冲,到处理各种异步事件和错误,每一个细节都体现在对这些寄存器的精准操控上。这份手册提供的位域描述是通用的蓝图,具体到不同的芯片平台,寄存器的内存映射地址、某些特殊功能位的支持情况可能会有所不同,但核心��想和处理流程是相通的。在实际项目中,结合具体的芯片参考手册,灵活运用这些寄存器知识,是构建稳定、高效串口通信底层驱动的基石。

http://www.jsqmd.com/news/1240826/

相关文章:

  • Spring Boot整合JPA实现高效数据持久化开发
  • Grok 4.5登顶编程基准 模型竞赛进入新阶段
  • 北海三区一县黄金回收门店盘点本地旧金变现渠道选择与交易避坑完整指南 - 不晚生活号
  • 【PTrade】PTrade回测如何设置手续费和滑点?避免策略收益虚高完整教程
  • 2026年重庆一体化净水设备怎么选?本地用户真实避坑经验+3家靠谱品牌深度对比 - 金澜达水处理
  • 触摸一体机标的IP65防水,到底能防什么
  • Vue3+Vite+Cesium三维地理场景开发实战
  • CentOS 7 搭建 Samba 文件共享并配置用户、部门权限与 SELinux
  • HTTP 404错误解析与优化实践指南
  • SEO+GEO 双渠道全域获客全解:2026 白帽规范、选型评判标准与国内 15 大正规服务商完整测评 - 热点速览
  • AI推理芯片技术解析与Kimi K3算力需求实战指南
  • 2026年扭力计优质厂家不止看参数,广州安妙的服务体系才是隐藏王牌 - 品牌推荐大师1
  • 从多场景实测看代理IP产品:一份可复现的六方横向测评
  • AI写专著必备指南:AI工具加持,20万字专著高效产出,查重不用愁
  • 毕业生必看!档案存放 +管理全指南 - 慧办好
  • TI TM4C1292NCZAD ARM Cortex-M4F MCU:工业网关与实时控制开发实战
  • AI Agent开发指南:从原理到实践应用
  • iPhone查找功能全攻略:从设置到应急响应
  • 2026铜仁万山区防水补漏哪家靠谱?免砸砖精准测漏一站式解决全屋漏水 - 宅安选房屋修缮
  • 程序员必备专业英语词汇指南与学习方法
  • AI专著写作必备:精选工具一键生成20万字专著,查重低至个位数
  • 新手必看!2026深圳黄金回收完整变现流程,零套路落地 - 二奢分享官
  • 绝区零游戏卡顿优化:显存管理与帧生成技术实战
  • 济南伯爵中国大陆**售后服务网点|**网站**公示(2026年7月最新) - 伯爵官方售后服务中心
  • 7月长沙新手黄金回收指南:零基础也能省心变现不踩坑 - 逸程奢侈品回收中心
  • 私有云存储速度到底能跑多快?
  • AI开始“偷懒”,制造业却笑了:真正能省钱的不是聊天机器人
  • 行业观察|深圳 LED 显示屏厂家推荐:小间距 LED 成趋势,采购参数如何选择(附 LED 测评 + LED 行业协会联合发布) - 资讯速览
  • 单体生物科普┃FITC-转铁蛋白(人)是什么?荧光素标记转铁蛋白在细胞研究中如何应用?
  • TI ISS ISP中断与DMA机制解析:嵌入式视觉系统核心驱动开发指南