UART/IrDA/CIR多模式驱动开发:从寄存器配置到实战调试

发布时间:2026/7/19 4:12:10
UART/IrDA/CIR多模式驱动开发:从寄存器配置到实战调试 1. 项目概述与核心价值搞嵌入式开发尤其是涉及到设备间通信UART通用异步收发传输器绝对是一个绕不开的“老朋友”。它简单、可靠从古老的单片机到最新的SoC几乎无处不在。但很多朋友对UART的理解可能还停留在“配置个波特率就能收发数据”的层面一旦遇到复杂的流控制、多模式切换比如和IrDA、CIR共用模块或者需要高可靠性时就容易抓瞎。实际上一个成熟的UART驱动其稳定性很大程度上取决于开发者对寄存器细节、时钟分频原理以及数据流管理机制的深入理解。最近在调试一块集成了UART、IrDA和CIR功能的SoC时我重新啃了一遍TI的官方手册把里面关于波特率生成、硬件/软件流控制、以及多模式下的寄存器映射这些“硬骨头”都梳理了一遍。这篇文章我就结合手册里的干货和我自己踩过的坑来一次深度的“庖丁解牛”。我们会从最根本的时钟分频和波特率计算讲起弄明白每一个比特时间是怎么来的然后深入到硬件流控制RTS/CTS和软件流控制XON/XOFF是如何在寄存器层面协同工作防止数据丢失的最后我们会拆解IrDA和CIR模式下的特殊配置看看同一个硬件模块如何通过寄存器“变身”成不同的通信接口。无论你是正在编写底层驱动还是遇到通信不稳定需要调试相信这些对寄存器位和时序的深入分析都能给你带来直接的帮助。2. 核心原理时钟、波特率与数据帧2.1 波特率生成的“心脏”可编程分频器UART通信是异步的双方没有统一的时钟线因此收发两端必须预先约定一个相同的速率这就是波特率Baud Rate。波特率发生器本质上是一个分频器。手册中给出的典型时钟源是48MHz我们的目标就是通过分频得到符合标准波特率如115200bps的发送和接收时钟。其核心公式非常简单分频值 工作频率 / (波特率倍数 × 目标波特率)这里的关键在于“波特率倍数”。在UART的16倍采样模式下接收端会对每个数据位采样16次以提高抗干扰能力和定位位中心的准确性。因此此时波特率倍数 16。而在某些高速模式如IrDA的MIR模式或为了兼容特定速率时倍数可能是13或41/42。以生成115200bps的波特率为例在16倍模式下计算 分频值 48,000,000 Hz / (16 × 115200) 26.041666... 显然分频值必须是整数。我们取整为26。此时实际波特率 48,000,000 / (16 × 26) ≈ 115384.6 bps误差约为0.16%。这个误差在串口通信的容限范围内通常要求3%。这个分频值26需要被写入两个8位寄存器DLL_REG除数锁存器低字节和DLH_REG除数锁存器高字节。26的十六进制是0x1A因此DLL_REG 0x1ADLH_REG 0x00。手册中的表格Table 17-30已经为我们计算好了常用波特率下的最佳分频值直接查表配置是最稳妥的方式。注意一个至关重要的配置顺序手册中用一个CAUTION特别强调在初始化或修改DLL_REG和DLH_REG之前必须先将模式选择寄存器MDR1_REG[2:0]设置为0x7即禁用模式。如果不遵守这个规则模块行为将不可预测。我个人的理解是在时钟分频器动态调整时如果模块正处于活跃状态可能会导致分频器产生毛刺或错误时钟进而引发乱码甚至硬件锁死。安全的配置流程应该是停止模块 - 配置分频 - 设置模式 - 启用模块。2.2 数据帧格式不止是数据位和停止位配置好波特率接下来要定义数据包的格式。这通过LCR_REG线路控制寄存器完成。LCR_REG[1:0](CHAR_LENGTH): 定义数据位长度通常为5、6、7或8位。LCR_REG[2](NB_STOP): 定义停止位数量1位或2位。LCR_REG[5:3](PARITY_EN, PARITY_TYPE_1/2): 定义奇偶校验位。奇偶校验的配置稍微复杂一点它是一个3比特的组合PARITY_ENPARITY_TYPE1PARITY_TYPE2校验类型0XX无校验100奇校验110偶校验101校验位强制为1111校验位强制为0“强制为1/0”这种模式可能不太常用但在某些需要特定帧结构的私有协议中可能会用到。2.3 自动波特率检测让设备“自适应”这是一个非常实用的高级功能尤其在产品需要兼容不同上位机或作为调试接口时。通过设置MDR1_REG[2:0] 0x2进入自动波特率模式。此时模块会监听接收线上的特定字符序列如“AT”或“at”加回车符并通过测量其脉冲宽度来自动计算出对方的波特率、数据位和校验方式。它的工作流程是这样的使能自动波特率模式。模块等待接收“AT”或“at”字符串。一旦成功检测到模块会触发一个中断并将检测到的参数波特率、字长、校验更新到UASR_REG自动波特率状态寄存器中。后续的通信就使用这些检测到的参数。需要注意的限制仅支持1.2Kbps到115.2Kbps之间的10种标准波特率。仅支持7位或8位字符长度不支持5、6位。不支持“7位数据空格校验”这种组合。在实际使用中我建议在自动波特率检测成功后软件读取UASR_REG并据此重新配置LCR_REG、DLL_REG和DLH_REG然后退出自动波特率模式切换回标准模式进行正常通信。这样更稳定。3. 数据流控制硬件与软件的“交通警察”当收发双方速度不匹配或者接收方处理不及时时就会发生数据丢失溢出。流控制就是解决这个问题的“交通警察”。3.1 硬件流控制RTS与CTS的握手硬件流控制通过两根额外的信号线实现RTS请求发送输出和CTS清除发送输入。它完全由硬件自动管理效率高软件开销小。自动RTSAuto-RTS由接收方控制。当接收FIFO先入先出缓冲区中的数据量低于TCR_REG[3:0]设置的RX_FIFO_TRIG_HALT暂停触发电平接收方会拉低RTS信号告诉对方“我可以接收数据请发送”。当FIFO数据达到HALT电平RTS被拉高表示“缓冲区快满了请暂停发送”。当数据被读取FIFO深度降到TCR_REG[7:4]设置的RX_FIFO_TRIG_START恢复触发电平时RTS再次拉低通知对方恢复发送。这里有个细节发送设备可能在RTS变高后已经开始了下一个字节的发送因此这个字节仍会被接收这解释了为什么触发电平需要留出一些余量。自动CTSAuto-CTS由发送方检查。发送方在发送每个字节之前会检查CTS引脚。只有当CTS为有效低电平时它才会发送数据。如果CTS在当前字节的最后一个停止位的中点之前变为无效发送方就会停止发送后续字节。这个“中点之前”的时序要求非常关键确保了流控制的及时性。通过EFR_REG[7:6]可以独立使能自动CTS和自动RTS。当两者同时启用时形成了双向流控制能最大程度避免溢出错误。请注意RTS和CTS都是低电平有效。3.2 软件流控制XON/XOFF字符协议在没有预留硬件流控制引脚的情况下可以使用软件流控制。它通过在线路上插入特殊的控制字符XOFF暂停发送ASCII DC30x13和XON恢复发送ASCII DC10x11来管理流量。配置通过EFR_REG[3:0]进行可以独立设置发送和接收时比较的字符对XON1/XOFF1 或 XON2/XOFF2。字符值存储在XON1_ADDR1_REG、XOFF1_REG、XON2_ADDR2_REG、XOFF2_REG中。工作流程接收方当接收FIFO快满时它会通过发送XOFF字符通知对方暂停。发送方接收到XOFF后停止发送数据当前字符完成后停止。接收方当FIFO数据被处理空出空间后发送XON字符。发送方接收到XON后恢复发送。两个需要注意的特殊功能XON Any功能(MCR_REG[5])使能后在收到XOFF后接收到任何字符而不仅仅是匹配的XON字符都会恢复传输。这增加了灵活性但也可能带来意外恢复。特殊字符检测(EFR_REG[5])使能后当接收到与XOFF2匹配的字符时会触发一个XOFF中断 (IIR_REG[4])但不会停止传输。这个字符会被存入FIFO。这可以用于实现自定义的带内信令。重要经验硬件与软件流控制不要混用手册明确假设软件流控制和硬件流控制不会同时启用。如果同时启用两者的控制信号可能会产生冲突导致通信逻辑混乱。在设计协议时必须二选一。4. 错误处理与中断管理4.1 错误检测与状态读取UART模块提供了完善的错误检测机制状态集中在LSR_REG线路状态寄存器中。BIBreak Interrupt线路中断条件即接收线被长时间拉低超过一个完整字符的时间。FEFraming Error帧错误停止位不是预期的逻辑1。PEParity Error奇偶校验错误。OEOverrun Error溢出错误当接收FIFO已满新字符又到来时发生。这里有一个至关重要的读取顺序陷阱LSR_REG[4:2]反映的是RX FIFO顶部即下一个将被读取的字符的错误状态。因此正确的操作顺序是读取LSR_REG获取错误标志。读取RHR_REG接收保持寄存器读取数据同时清除该字符的错误状态并移动FIFO指针。如果先读RHR_REG再读LSR_REG你读到的错误标志可能就是下一个字符的了。OE位比较特殊读取LSR_REG本身就会清除它。4.2 中断系统详解UART有7种中断被归为6个优先级数字越小优先级越高。中断发生时IIR_REG[0]变为0IIR_REG[5:1]指示中断类型。中断优先级与处理Table 17-33接收线路状态最高OE,FE,PE,BI错误。清除方法对于FE/PE/BI读取RHR_REG对于OE读取LSR_REG。接收超时RX FIFO中有数据但一段时间没有新数据或读取操作。清除方法读取RHR_REG。RHR中断接收数据就绪FIFO非空或达到触发水平。清除方法读取RHR_REG直到条件消失。THR中断发送保持寄存器空可写入新数据。清除方法写入THR_REG直到条件消失。调制解调器状态变化CTS、RTS等调制解调器信号状态改变。清除方法读取MSR_REG。XOFF/特殊字符中断接收到XOFF或特殊字符。清除方法接收到XON字符针对XOFF或读取IIR_REG针对特殊字符。中断服务程序ISR的标准写法通常是读取IIR_REG判断中断源。根据中断类型跳转到相应的处理子程序。在子程序中执行上述“清除方法”对应的操作来清除中断标志。对于FIFO触发中断通常采用循环读取/写入直到FIFO为空/满的方式以提高效率。5. IrDA模式深度解析IrDA红外数据协会模式利用UART的硬件基础通过红外光进行通信。它主要分为SIR低速最高115.2kbps、MIR中速1.152Mbps和FIR高速4Mbps三种速率。5.1 模式切换与时钟分频首先通过MDR1_REG[2:0]将模块切换到IrDA模式。IrDA的波特率生成器与UART共享DLL_REG和DLH_REG但分频倍数不同SIR模式使用16倍分频公式与UART相同。MIR模式使用41倍或42倍分频具体取决于编码公式为分频值 48MHz / (41或42 × 目标波特率)。例如对于1.152Mbps分频值1。FIR模式固定使用6倍分频且分频值不由DLL/DLH控制。5.2 IrDA特有的关键功能IRRX极性控制(MDR2_REG[6])大多数红外收发器会对信号进行反相。这个位允许你在模块内部再次反相确保逻辑电平与协议预期一致。通常需要使能。地址检查用于红外多点通信。可以设置两个地址XON1_ADDR1_REG和XON2_ADDR2_REG。通过EFR_REG[1:0]使能地址检查后只有目标地址匹配的帧才会被存入RX FIFO有效过滤无关数据。帧结束处理IrDA是面向帧的协议。有两种方式告知模块一帧结束帧长度法(FRAME_END_MODE0)软件预先将本帧长度写入TXFLH_REG和TXFLL_REG硬件发送完指定字节数后自动添加结束标志。EOT位法(FRAME_END_MODE1)软件在写入帧的最后一个字节到TX FIFO之前先将ACREG_REG[0](EOT位) 置1。硬件会为该字节打上“结束”标记并在发送它时正确结束帧。存储与控制传输(MDR1_REG[5]- SCT位)正常模式下数据一写入TX FIFO就开始发送。在SCT模式下写入数据后需要软件主动设置ACREG_REG[2](SCTX_EN) 来启动发送。这对于需要精确控制发送时机或者组装一个完整短帧后再发送的场景非常有用可以避免发送欠载TX Underrun。状态FIFO这是IrDA模式的一大特色。除了数据FIFO还有一个独立的8入口状态FIFO。每成功接收完一帧硬件就会将该帧的长度可通过SFREGH_REG和SFREGL_REG读取和错误状态CRC错误、帧中止、帧长错误通过SFLSR_REG读取压入状态FIFO。软件可以通过轮询或中断状态FIFO达到触发水平来批量处理多帧的元信息再根据长度信息从数据FIFO中准确提取每一帧的内容效率远高于每收一个字节就处理一次。5.3 SIR、MIR、FIR模式要点SIR模式采用3/16位时间或固定1.6μs的脉冲进行编码。可以通过ACREG_REG[7]选择脉冲类型。它还有一个“自由格式”模式实际上是通过配置为UART模式 (MODE_SELECT0x0)并开启脉冲整形 (UART_PULSE1) 来实现的此时需要固定配置为8位数据、1位停止、无校验。MIR/FIR模式涉及SIP串行红外脉冲的管理。可以通过MDR1_REG[6]强制每帧后发送SIP或者通过ACREG_REG[3]由软件控制SIP的发送。后者可以减少协议开销。5.4 IrDA中断差异IrDA模式的中断与UART不同没有优先级所有中断通过IIR_REG的不同位来标识见Table 17-35。需要特别关注的中断有状态FIFO中断状态FIFO达到触发水平提示软件有一批帧信息待处理。TX状态中断可能表示发送完成也可能表示发送过程中发生了欠载错误。接收EOF中断成功接收到一个完整的帧。6. CIR模式与寄存器映射精讲CIR消费红外模式通常用于电视、空调遥控器等消费电件的红外信号收发其编码格式如NEC、RC5与UART/IrDA完全不同。手册指出在所用的SoC中CIR功能仅由UART3模块支持并且只使用表17-29中列出的寄存器子集。6.1 寄存器功能重映射这是理解多模式模块的关键。同一个物理寄存器在不同模式下其各个比特位的含义可能完全不同。例如THR_REG发送保持寄存器在UART模式下用于写入待发送数据在CIR模式下它可能用于写入特定的红外载波脉冲模式参数。IER_REG/IIR_REG中断相关的寄存器其比特位定义在UART、IrDA、CIR模式下是独立的编程时必须参考当前模式的寄存器手册章节Section 17.6。LCR_REG[7]这个比特位在CIR模式下被单独列出说明它可能用于启用CIR的某种特定编码格式。开发中的黄金法则在切换模式通过MDR1_REG[2:0]前一定要查阅对应模式的寄存器手册绝不能想当然地沿用UART模式的配置。最好的做法是为每种模式编写独立的初始化函数清晰地配置所有相关寄存器。6.2 CIR模式配置要点虽然手册没有展开CIR的具体协议但从寄存器限制和通用CIR原理我们可以推断出配置流程模式选择将MDR1_REG[2:0]设置为CIR模式对应的值非0127。时钟配置CIR的载波频率通常为38kHz和位编码时序需要特定的时钟分频。这很可能通过配置DLL_REG/DLH_REG以及ACREG_REG、CFPS_REG等寄存器来实现。引脚复用确保SoC的引脚复用控制器将UART3的TX/RX引脚配置为CIR功能。中断配置根据CIR模式下的IER_REG定义使能所需的中断如接收完成、接收错误。数据收发通过CIR模式下的数据寄存器可能仍是THR_REG/RHR_REG但按帧或按脉冲组读写进行操作。7. 实战配置与调试心得7.1 一个完整的UART初始化流程以1152008N1硬件流控为例// 伪代码展示流程和关键操作 void UART_Init(void) { // 1. 禁用模块或确保处于禁用状态 UART-MDR1_REG.BITS.MODE_SELECT 0x7; // 进入禁用模式 // 2. 配置波特率 (115200, 16x mode) // 查表得 DLH0x00, DLL0x1A UART-LCR_REG.BITS.DLAB 1; // 使能访问DLL/DLH UART-DLL_REG 0x1A; UART-DLH_REG 0x00; UART-LCR_REG.BITS.DLAB 0; // 禁用访问DLL/DLH // 3. 配置数据帧格式 (8位数据1位停止无校验) UART-LCR_REG.BITS.CHAR_LENGTH 3; // 8 bits UART-LCR_REG.BITS.NB_STOP 0; // 1 stop bit UART-LCR_REG.BITS.PARITY_EN 0; // No parity // 4. 使能并配置FIFO如果使用 UART-FCR_REG.BITS.FIFO_EN 1; UART-FCR_REG.BITS.RX_FIFO_TRIG 1; // 例如设置接收触发点为8字节 // 5. 配置硬件流控制 UART-EFR_REG.BITS.AUTO_CTS_EN 1; UART-EFR_REG.BITS.AUTO_RTS_EN 1; // 设置RTS触发电平 (例如HALT12字节 START4字节) UART-TCR_REG.BITS.RX_FIFO_TRIG_HALT 12; UART-TCR_REG.BITS.RX_FIFO_TRIG_START 4; // 6. 配置中断例如使能接收数据就绪中断 UART-IER_REG.BITS.ERBI 1; // Enable Receiver Data Available interrupt // 7. 最后切换到UART工作模式 UART-MDR1_REG.BITS.MODE_SELECT 0x0; // UART模式 }7.2 常见问题排查实录问题1通信完全无数据或全是乱码。检查1时钟与波特率。这是最常见的问题。确认输入给UART模块的时钟频率是否正确是48MHz吗。用示波器测量TX引脚看比特宽度是否与预期波特率匹配例如115200bps约为8.68μs/bit。务必确认在配置DLL/DLH前已将模块禁用。检查2数据帧格式。确保收发双方的LCR_REG配置数据位、停止位、校验位完全一致。一个停止位和校验位的差异就足以导致连续误码。检查3引脚映射与电平。确认TX、RX引脚是否正确复用。用万用表或示波器检查引脚是否有物理连接电平是否正常通常是3.3V或1.8V。问题2通信一段时间后卡死或丢失数据包。检查1流控制。如果通信速率高或数据量大务必启用流控制。检查RTS/CTS硬件连线是否正确或者软件流控制字符是否被正确识别和处理。确保没有同时启用硬件和软件流控制。检查2中断服务程序。是否及时清除了中断标志读取RHR_REG是否足够快如果FIFO溢出需要按手册要求先复位RX FIFO (FCR_REG[1])再读取RESUME_REG来清除内部标志。检查3缓冲区管理。确保你的应用程序读取数据的速度不低于数据到达的速度。如果使用查询方式轮询间隔必须短于接收FIFO被填满的时间。问题3IrDA模式无法通信。检查1模式与分频。确认MDR1_REG已设置为正确的IrDA模式SIR/MIR/FIR。确认DLL/DLH值是否针对当前IrDA模式SIR-16x MIR-41/42x计算正确。检查2红外收发器。IrDA需要专用的红外收发器模块如TFDU4101。检查其供电、使能引脚并用手机摄像头部分可看到红外光粗略检查发射管在发送时是否闪烁。检查3极性。尝试翻转MDR2_REG[6](IRRXINVERT) 位。红外收发器的输入/输出极性可能因型号而异。检查4帧结构。IrDA是帧协议你发送的数据需要包含起始标志、地址域如果启用检查、数据、CRC和结束标志。确认你的软件正确构建了完整的IrDA帧而不是仅仅发送UART那样的原始字节流。问题4从UART模式切换到CIR/IrDA模式后功能异常。检查1寄存器重新初始化。模式切换后许多寄存器的含义变了。最安全的做法是在切换模式后按照新模式的规范对所有相关的寄存器进行一次完整的重新配置而不是依赖之前的配置。检查2引脚复用。某些模式下TX/RX引脚可能被用于不同的信号如CIR的载波输出。检查SoC的引脚控制寄存器确保已切换到正确的功能。理解这些寄存器每一位的含义就像掌握了硬件通信的“密码”。调试时不要只盯着软件逻辑多用调试器或直接读取这些寄存器的值结合示波器观察波形往往能快速定位问题根源。希望这篇基于手册和实战的详解能让你下次面对UART、IrDA或CIR时更加游刃有余。