深入解析UART状态寄存器:从LSR、MSR到硬件流控的嵌入式实战

📅 2026/7/21 5:41:20
深入解析UART状态寄存器:从LSR、MSR到硬件流控的嵌入式实战
1. 项目概述与核心价值在嵌入式开发领域UART通用异步收发传输器几乎是每个工程师都会打交道的“老朋友”。无论是调试信息输出、固件升级还是与各类传感器、模块通信UART都扮演着不可或缺的角色。然而很多开发者对UART的认知往往停留在“配置波特率、数据位、停止位、奇偶校验”的层面一旦通信出现异常比如数据丢失、乱码或者通信中断排查起来就非常棘手只能反复尝试修改配置或重启设备效率低下。问题的根源在于我们仅仅是在“使用”UART而没有真正“理解”它。UART硬件内部是一个精密的数字状态机其运行状态、错误信息、缓冲区情况都通过一系列寄存器实时反映出来。这些寄存器特别是线路状态寄存器LSR和调制解调器状态寄存器MSR就像是UART模块的“仪表盘”和“故障诊断仪”。不读懂它们就等于蒙着眼睛开车出了问题自然无从下手。本文将以德州仪器TIAM62L Sitara™处理器的UART模块为例深入剖析LSR、MSR、MDR等关键寄存器的每一个比特位。我的目标不是简单地翻译数据手册而是结合我十多年在工业控制和通信设备开发中积累的实战经验带你理解这些寄存器位在真实场景下的含义、如何通过编程访问它们、以及如何利用它们的信息来构建健壮、可维护的串口驱动和高效的调试手段。无论你是正在学习嵌入式的新手还是希望优化现有通信代码的资深工程师这篇文章都将提供从原理到实操的完整视角。2. UART寄存器全景与访问基础在深入每个寄存器细节之前我们有必要建立一个全局视图。AM62L的UART模块是高度集成和可配置的其寄存器映射在芯片的存储器地址空间中。根据你提供的资料我们可以看到UART0到UART6以及WKUP_UART0的寄存器组它们具有相同的结构但位于不同的物理地址基址上。例如UART0的LSR寄存器地址是0x0280 0014h而UART1的则是0x0281 0014h。这种规律性的偏移使得我们可以用“基址偏移量”的方式来统一访问所有UART通道这在编写驱动时非常方便。2.1 寄存器访问的编程模型在C语言中我们通常通过指针来访问这些内存映射寄存器。首先我们需要定义每个寄存器的基址。对于AM62L这些地址通常在芯片的数据手册或头文件如hw_uart.h中定义。// 假设这是从SDK或数据手册中获取的UART0基址 #define UART0_BASE (0x02800000UL) // 寄存器偏移量定义 #define UART_LSR_OFFSET (0x14) #define UART_MSR_OFFSET (0x18) #define UART_MDR1_OFFSET (0x20) // 将基址转换为易用的指针 volatile uint32_t *uart_lsr (volatile uint32_t *)(UART0_BASE UART_LSR_OFFSET); volatile uint32_t *uart_msr (volatile uint32_t *)(UART0_BASE UART_MSR_OFFSET);这里使用volatile关键字至关重要。它告诉编译器这个指针指向的内容可能被硬件UART模块在任何时刻改变因此编译器不能对这个变量的读写做任何优化比如缓存到寄存器必须每次都从内存地址真正读取。缺少volatile是嵌入式编程中一个非常隐蔽的Bug来源。2.2 关键寄存器分类与作用根据功能我们可以将UART寄存器大致分为几类控制与配置寄存器用于设置UART的工作模式、参数。例如我们熟知的波特率分频器DLL/DLH、线路控制寄存器LCR就在此类。你提供的资料中MDR1模式选择寄存器1是这类寄存器的核心它决定了UART是工作在标准的UART 16x模式、自动波特率模式还是IrDA红外模式。状态寄存器用于反映UART模块的实时运行状态。这是本文的重点主要包括LSR线路状态寄存器反映数据收发链路本身的状态如接收FIFO是否有数据、发送器是否空闲、是否发生了奇偶校验错、帧错误等。MSR调制解调器状态寄存器反映与UART相连的外部设备传统上是Modem控制线的状态变化如CTS清除发送、DSR数据设备就绪等信号。在现代嵌入式系统中这些引脚常被复用为流控或通用IO。数据寄存器即THR发送保持寄存器和RHR接收保持寄存器用于读写实际要传输或接收到的字节数据。FIFO与流量控制寄存器用于管理内部缓冲区FIFO和硬件流控。例如TCR传输控制寄存器和TLR触发水平寄存器它们可以设置FIFO的触发深度以产生DMA请求或中断。特殊功能寄存器用于支持特定协议如IrDA模式下的帧长度寄存器TXFLL/TXFLH, RXFLL/RXFLH、状态FIFO寄存器SFLSR, SFREGL/SFREGH以及自动波特率状态寄存器UASR。理解这个分类有助于我们在编程时快速定位问题。如果通信数据出错首先应该查LSR如果流控不工作可能需要同时关注MSR和MCR调制解调器控制寄存器如果根本收不到数据则需要检查MDR1是否配置到了正确的模式。注意在访问任何UART寄存器尤其是配置类寄存器如MDR1之前必须确保UART模块处于复位或禁用状态或者严格按照数据手册规定的顺序操作。例如资料中明确提到“MDR1[2:0] must be programmed on start-up after configuration of the configuration registers (DLL, DLH, LCR). The value of MDR1[2:0] must not be changed again during normal operation.” 这意味着模式选择应在波特率等参数配置完成后进行且运行时不可更改否则可能导致通信异常。3. 线路状态寄存器LSR深度解析与实战应用LSR寄存器是我们诊断UART通信链路健康状态最直接的工具。它提供了从物理引脚上检测到的信号状态到内部FIFO缓冲区的完整信息链。我们逐位分析其功能和应用场景。3.1 接收状态位组Bit 0, 1, 2, 3, 4, 7这部分比特位主要与接收RX路径相关。Bit 0 - RX_FIFO_E (Receive FIFO Not Empty)这是最常用的状态位之一。当它为1时表示接收FIFO中至少有一个字符字节的数据可供读取。在查询Polling方式编程中我们通过循环检查此位来判断是否有数据到达。// 查询方式等待接收一个字符 while ((*uart_lsr 0x01) 0) { // 可以在此处加入超时机制防止死循环 } char received_data *(volatile uint8_t *)(UART0_BASE RHR_OFFSET); // 读取数据实操心得单纯依赖此位进行大数据量接收效率较低因为CPU需要不断轮询。更好的做法是结合接收FIFO触发水平通过TLR寄存器设置和中断或DMA当FIFO中数据达到一定量时再通知CPU批量处理。Bit 1 - RX_OE (Overrun Error)溢出错。这是UART通信中一个严重的错误。当CPU或DMA来不及从接收FIFO中取走数据而新的字符已经从移位寄存器移入时就会发生溢出。此时旧的未被读取的数据会被新数据覆盖而丢失。LSR[1]被置1。为什么会出现波特率设置过高、CPU被高优先级任务阻塞、中断服务程序ISR处理太慢、或者没有正确使能/处理接收中断。如何处理一旦检测到溢出错if (lsr_value 0x02)首先应该读取一次RHR寄存器即使你不关心丢失的数据这个读取操作会清除相应的错误状态。然后必须检查你的通信协议是否有重传机制并评估是否需要降低波特率或优化接收代码。Bit 2 - RX_PE (Parity Error)与Bit 3 - RX_FE (Framing Error)奇偶校验错和帧错误。这两个错误都指示了物理线路上的信号质量问题。PEBit 2接收方计算的奇偶校验位与发送方附加的校验位不匹配。可能原因包括线路噪声、波特率微小偏差累积误差、或通信双方奇偶校验设置不一致。FEBit 3在预期的停止位位置检测到的不是逻辑‘1’高电平而是‘0’。这是最典型的帧错误通常意味着波特率严重不匹配或者线路受到强烈干扰导致接收方完全无法同步到正确的数据帧。排查技巧如果频繁出现PE或FE首先用示波器或逻辑分析仪抓取TX和RX信号对比波特率是否精确一致。检查硬件连接如电平转换芯片是否正常。在软件上确保通信双方的数据位、停止位、奇偶校验设置完全一致。Bit 4 - RX_BI (Break Interrupt)间断条件指示。当RX引脚检测到持续的低电平逻辑‘0’时间超过一个完整字符传输时间包括起始位、数据位、停止位时此位置1。这通常不是错误而是一种特殊的通信信号。在一些古老的协议或现代的一些调试器中会主动发送一个Break信号拉低RX线一段时间来复位或唤醒对方设备。应用场景在某些Bootloader协议中PC端工具通过发送一个Break信号通知设备端的Bootloader进入固件升级模式。Bit 7 - RX_FIFO_STS (RX FIFO Error Status)这是一个错误汇总位。当接收FIFO中任何位置的字符存在奇偶校验错、帧错误或间断条件时此位被置1。只有当FIFO中所有错误字符都被读取并清除后此位才会清零。与Bit 1-4的区别Bit 1-4反映的是当前正从FIFO中读取的那个字符的错误状态。而Bit 7是一个全局标志告诉你FIFO里“有脏数据”。在读取数据时更可靠的做法是先检查Bit 7如果为1则意味着本次读取的数据可能伴随错误需要进一步检查Bit 1-4来确定具体错误类型。3.2 发送状态位组Bit 5, 6这部分比特位与发送TX路径相关用于判断发送器是否准备就绪。Bit 5 - TX_FIFO_E (Transmit FIFO Empty)当发送保持寄存器THR或发送FIFO完全空时此位置1。注意资料中特别说明“The transmission is not necessarily completed.” 这意味着FIFO为空但移位寄存器可能还在发送最后一个字节的剩余位。此位常用于判断是否可以安全写入下一个待发送字符以避免覆盖。// 查询方式发送一个字符 while ((*uart_lsr 0x20) 0) { // 等待THR/FIFO空 // 超时处理 } *(volatile uint8_t *)(UART0_BASE THR_OFFSET) data_to_send; // 写入数据Bit 6 - TX_SR_E (Transmitter Shift Register Empty)当发送移位寄存器为空时此位置1。移位寄存器是直接驱动TX引脚的最后一级。当Bit 5和Bit 6同时为1时才能确定最后一个比特位也已经从TX引脚发送完毕。这个状态在需要精确控制时序的场景下非常有用例如在发送完一串数据后需要立即切换引脚方向如在半双工RS-485通信中。// 等待所有数据包括移位寄存器中的发送完毕 while (((*uart_lsr 0x60) ! 0x60)) { // 等待Bit6和Bit5都为1 // 等待 } // 此时可以安全地切换RS-485的方向控制引脚为接收模式LSR使用总结表位名称值含义典型应用与排查0RX_FIFO_E1接收FIFO有数据查询接收、判断数据到达1RX_OE1数据溢出错误检查CPU处理速度、中断响应、波特率是否过高2RX_PE1奇偶校验错误检查双方奇偶校验设置、线路噪声3RX_FE1帧错误停止位不符首要怀疑波特率不匹配检查硬件连接4RX_BI1检测到间断信号检查是否有设备发送Break可能是协议的一部分5TX_FIFO_E1发送FIFO空判断是否可以写入下一个发送字符6TX_SR_E1发送移位寄存器空判断一帧数据是否完全发出用于时序控制7RX_FIFO_STS1FIFO中存在错误读取数据前检查提示需要处理错误4. 调制解调器状态寄存器MSR与硬件流控实战MSR寄存器在现代嵌入式开发中其重要性不亚于LSR尤其是在需要可靠、高速串行通信的场合。它管理着UART的硬件流控引脚RTS/CTS, DTR/DSR这些引脚最初用于连接调制解调器Modem故名“调制解调器状态寄存器”。4.1 当前状态位与变化指示位MSR的8个比特位分为两组理解这个分组是正确使用MSR的关键高4位Bit 7-4 - “N”状态位这些是当前状态取反位。它们直接反映了对应引脚当前的电平状态但逻辑是反相的。NCTS_STS(Bit 4): CTS引脚当前状态的反。CTS为低电平时NCTS_STS为1。NDSR_STS(Bit 5): DSR*引脚当前状态的反。NRI_STS(Bit 6): RI*引脚当前状态的反。NCD_STS(Bit 7): DCD引脚当前状态的反。为什么是反的这是历史沿袭和信号命名习惯。引脚名后的“”通常表示低电平有效。所以当有效信号到来低电平对应的“N”状态位读出来就是1更符合编程直觉“有信号”1。低4位Bit 3-0 - “变化”状态位这些是边沿检测位。当对应的引脚状态发生改变时硬件会自动将其置1。读取MSR寄存器的操作会将这些位清零Cleared on a read。CTS_STS(Bit 0): CTS*引脚状态发生变化。DSR_STS(Bit 1): DSR*引脚状态发生变化。RI_STS(Bit 2): RI*引脚状态从低到高跳变上升沿。DCD_STS(Bit 3): DCD*引脚状态发生变化。4.2 硬件流控RTS/CTS原理与实现硬件流控是保证高速、大数据量串行通信不丢数据的核心机制。其基本原理是“握手”发送方我方通过RTSRequest To Send引脚输出信号告知接收方“我准备发送数据了”。接收方对方如果其接收缓冲区FIFO有空间则通过CTSClear To Send引脚回应低电平意思是“你可以发送”。发送方持续监测自己的CTS引脚即对方的RTS信号。只有当CTS为低NCTS_STS为1时才将数据放入发送FIFO。如果CTS*变高则暂停发送。在AM62L的UART中RTS信号是由调制解调器控制寄存器MCR的Bit 1 (RTS)控制的而CTS状态则由MSR的Bit 4 (NCTS_STS)反映。一个典型的带硬件流控的发送函数伪代码如下bool uart_send_with_flowcontrol(uint8_t *data, uint32_t len) { for (uint32_t i 0; i len; i) { // 1. 检查CTS状态等待对方允许发送 uint32_t timeout MAX_CTS_TIMEOUT; while (((*uart_msr 4) 0x01) 0) { // 检查NCTS_STS (Bit4)是否为1 if (--timeout 0) { return false; // 超时对方未准备好 } // 此处可以加入任务延时或让出CPU } // 2. 检查发送FIFO是否有空间通过LSR[5]或FIFO计数寄存器 while (uart_txfifo_full()) { // 假设有函数检查TX FIFO满 // 等待空间 } // 3. CTS有效且FIFO有空间写入数据 *(volatile uint8_t *)(UART0_BASE THR_OFFSET) data[i]; } return true; }重要提示在回环测试模式Loopback Mode下MSR的这些引脚状态位不再反映外部引脚而是与MCR寄存器的相应位内部连接。资料中明确提到In loop-back mode it is equivalent to MCR[n]。例如在回环模式下NCTS_STS(MSR[4]) 反映的是RTS(MCR[1]) 的值。这在调试驱动逻辑时非常有用可以在不连接外部硬件的情况下测试流控代码。4.3 DSR/DCD/RI信号的应用虽然现代嵌入式系统中最常用的是RTS/CTS但其他信号在特定场景下仍有价值DSR (Data Set Ready)传统上表示Modem已上电并准备好。在一些工业协议中可能用作设备就绪信号。DCD (Data Carrier Detect)表示Modem检测到载波即电话线连通。在一些无线模块如GSM/GPRS的串口控制中可能用来指示网络注册状态。RI (Ring Indicator)表示电话振铃。在带有拨号功能的设备中用到。我们可以通过轮询MSR的低4位变化位来检测这些引脚的事件而无需持续轮询高4位状态位效率更高。// 中断服务程序或主循环中检查MSR变化 uint32_t msr_value *uart_msr; // 读取MSR会清除变化位 if (msr_value 0x01) { // CTS_STS变化 // 处理CTS变化事件 if ((msr_value 4) 0x01) { // 检查当前NCTS_STS // CTS有效可以恢复发送 } else { // CTS无效暂停发送 } } if (msr_value 0x02) { // DSR_STS变化 // 处理DSR变化事件 } // ... 类似处理RI和DCD5. 模式选择与高级功能寄存器MDR1, MDR2, TCR, TLR除了基础的收发状态AM62L的UART还提供了丰富的可配置功能这些功能主要通过MDR1、MDR2、TCR、TLR等寄存器控制。5.1 MDR1模式选择的核心MDR1的Bit 2-0 (MODE_SELECT) 是UART模块的“总开关”决定了其根本的工作模式。上电复位后默认值是7h(0b111)即禁用模式。这是很多新手容易忽略的一点如果不配置MDR1UART模块根本不会工作模式选择详解000-UART 16x 模式最常用的标准异步串口模式使用16倍过采样时钟。001-SIR 模式低速红外IrDA模式速率通常 up to 115.2 kbps。010-UART 16x 自动波特率模式UART可以自动检测输入数据的波特率。这在需要与不同波特率设备通信的Bootloader中非常有用。011-UART 13x 模式另一种过采样模式较少使用。100-MIR 模式中速红外IrDA模式速率 up to 1.152 Mbps。101-FIR 模式高速红外IrDA模式速率 up to 4 Mbps。110-CIR 模式消费电子红外Consumer Infrared模式用于遥控器等。111-禁用模式默认。配置流程与避坑指南顺序至关重要必须按照DLL/DLH (波特率) - LCR (数据格式) - MDR1 (模式)的顺序进行配置。在改变MDR1模式前最好先禁用UART或确保其处于空闲状态。一次性配置资料强调“The value of MDR1[2:0] must not be changed again during normal operation.” 这意味着模式一旦设定在通信过程中不应再更改。如果需要切换模式例如从UART切换到IrDA应先停止当前通信复位或重新初始化UART模块再配置新模式。中断的陷阱即使在禁用模式111如果中断使能寄存器IER打开了某些中断UART模式下的中断仍然可能产生。这可能会干扰系统。安全的做法是在更改模式前先清除并禁用所有UART中断。5.2 TCR与TLRFIFO管理与DMA效率优化现代UART内部通常都有FIFO缓冲区例如64字节。合理配置FIFO的触发水平Trigger Level可以极大提升系统效率减少中断次数或DMA请求频率。TLR (Trigger Level Register)TX_FIFO_TRIG_DMA(Bit 3-0):发送FIFO触发水平。当发送FIFO中的数据量低于或等于此值时可以触发DMA传输请求请求DMA控制器填充更多数据。例如设置为8则当TX FIFO中剩余空间大于等于8字节时触发DMA请求。RX_FIFO_TRIG_DMA(Bit 7-4):接收FIFO触发水平。当接收FIFO中的数据量达到或超过此值时触发DMA请求或接收中断通知系统来取走数据。例如设置为16则当RX FIFO中积累了16个字节时才产生一次中断让CPU一次读取16个字节而不是每收到1个字节就中断一次。TCR (Transmission Control Register)RX_FIFO_TRIG_HALT(Bit 3-0):接收FIFO暂停触发水平。用于硬件流控RTS/CTS。当接收FIFO中的数据量达到此阈值时UART模块会自动拉高RTS信号即告诉对方“暂停发送”以防止自己缓冲区溢出。RX_FIFO_TRIG_START(Bit 7-4):接收FIFO恢复触发水平。当接收FIFO中的数据被取走数量低于此阈值时UART模块会自动拉低RTS信号即告诉对方“可以继续发送”。配置策略示例 假设RX FIFO深度为64字节。我们希望当收到16字节时通知CPU中断或DMA则设置RX_FIFO_TRIG_DMA 16。为了防止溢出当FIFO快满比如还剩8字节空间时就让对方暂停发送。那么RX_FIFO_TRIG_HALT 64 - 8 56。当数据被取走FIFO空余超过32字节时再允许对方发送。那么RX_FIFO_TRIG_START 64 - 32 32。这样配置后硬件流控完全由UART模块自动管理软件只需处理数据大大减轻了CPU负担并保证了通信的可靠性。5.3 MDR2与IrDA/CIR模式深入当MDR1配置为IrDA或CIR模式时MDR2寄存器用于配置这些红外协议特有的参数。IRRXINVERT(Bit 6):红外接收信号反相。大多数红外收发器Transceiver输出的信号是反相的即收到光脉冲输出低电平。此位默认为0执行反相将外部反相信号再反相回来得到正确的逻辑。如果你的硬件设计不同可能需要将此位置1。STS_FIFO_TRIG(Bit 2-1):状态FIFO触发阈值。在IrDA模式下除了数据FIFO还有一个独立的“状态FIFO”用于存储每个接收帧的附加信息如帧长度、CRC错误等见SFLSR寄存器。此字段设置状态FIFO中有多少条目时产生中断。合理设置可以避免频繁中断。IRTX_UNDERRUN(Bit 0):红外发送欠载状态。这是一个只读状态位。当在IrDA发送过程中发生欠载发送FIFO为空但移位寄存器还需要数据时此位置1。这是一个关键的错误指示位。在IrDA高速模式下如果DMA或CPU供数不及时就容易发生欠载导致发送帧错误。发生欠载后需要读取UART_RESUME寄存器来清除错误状态并恢复传输。6. 错误排查与调试技巧实录理解了寄存器原理最终要落实到解决问题上。以下是我在多年调试中总结出的UART问题排查流程和技巧。6.1 通信完全不通无收发检查时钟与电源确认UART模块所在电源域已上电外设时钟例如来自PRCM模块已使能。这是最基本也最容易被忽略的一步。验证引脚复用使用芯片的PinMux工具或寄存器确认UART的TX、RX引脚已正确配置为UART功能而不是GPIO或其他功能。确认模式选择读取MDR1寄存器确认MODE_SELECT字段不是111禁用。这是新手最常见的错误之一。检查波特率配置计算并确认DLL和DLH寄存器的值是否正确。一个快速验证的方法是用示波器量TX引脚在软件中发送一个字节0x55(二进制01010101)。在8N1格式下这会输出一个方波其周期的一半就是位时间。测量位时间即可反算出实际波特率。环回测试将UART配置为内部环回模式通过LCR或MCR寄存器设置。在此模式下TX直接连接到RX。发送数据然后读取接收数据。如果环回模式下能自发自收则证明UART内核和软件配置基本正确问题出在外部引脚连接或对方设备上。6.2 能发送但不能接收或接收乱码首要怀疑对象波特率用示波器同时抓取发送方TX和接收方RX或接收方TX和发送方RX的信号。对比两个信号的位宽度。即使有微小偏差在大量数据传输后也会累积导致帧错误。确保双方使用的时钟源精度足够特别是如果使用内部RC振荡器。检查LSR错误位在接收中断或轮询中务必检查LSR寄存器在读取数据前的状态。uint32_t lsr *uart_lsr; if (lsr (UART_LSR_OE | UART_LSR_PE | UART_LSR_FE | UART_LSR_BI)) { // 处理错误 if (lsr UART_LSR_OE) { /* 溢出错处理 */ } if (lsr UART_LSR_FE) { /* 帧错误重点检查波特率 */ } // ... 即使有错误也读取数据寄存器以清除错误状态 uint8_t data uart_read_data(); // 记录或丢弃错误数据 } else if (lsr UART_LSR_DR) { // 数据就绪 uint8_t data uart_read_data(); // 正常处理数据 process_rx_data(data); }确认数据格式检查LCR寄存器确保数据位、停止位、奇偶校验设置与对方设备严格一致。一个常见的陷阱是对方设备使用7位数据位偶校验而我方配置为8位数据位无校验这会导致所有字符的高位错乱。6.3 大数据量传输不稳定或丢失启用并正确配置FIFO和流控这是解决此问题的关键。首先确保FIFO功能已启用通过FCR寄存器。然后根据你的系统处理能力CPU频率、中断延迟、DMA性能和通信波特率精心计算并设置TLR和TCR寄存器中的触发水平值。检查溢出错误OE如果LSR频繁报告OE说明你的系统来不及消费接收到的数据。解决方案优化接收代码路径减少中断服务程序的处理时间。增大接收FIFO的触发水平让CPU/DMA一次处理更多数据减少中断频率。如果使用查询方式提高轮询频率。考虑降低波特率。利用DMA对于高速或连续数据流强烈建议使用DMA进行UART数据传输。配置TLR寄存器让UART在FIFO达到一定深度时才触发DMA请求可以极大减少总线占用和CPU干预。同时为DMA设置正确的突发传输大小和流量控制避免DMA成为瓶颈。6.4 IrDA模式特有问题通信距离短或不通首先检查MDR2[6] (IRRXINVERT)的设置是否与红外收发器匹配。用示波器观察TXIR和RXIR引脚波形确保脉冲宽度和极性符合IrDA物理层规范如SIR是3/16位时间的窄脉冲。发送欠载Underrun在MIR/FIR等高速模式下如果IRTX_UNDERRUN(MDR2[0]) 被置位说明数据供应不上。需要优化DMA传输或提高发送数据填充的优先级。发生欠载后必须读取UART_RESUME寄存器才能继续发送。帧格式错误IrDA是面向帧的协议。确保正确配置了发送帧长度TXFLL/H或正确使用了EOT位通过ACREG寄存器来标识帧结束。同时接收方的最大帧长度RXFLL/H应设置得足够大以容纳预期帧。寄存器编程尤其是底层硬件寄存器编程是一个需要耐心和细致的工作。最好的调试工具就是你的思维逻辑和一块示波器。养成每次操作前查阅数据手册、每次异常后首先查看状态寄存器的习惯你就能逐渐驾驭UART乃至更复杂的通信外设构建出稳定可靠的嵌入式系统通信基石。