UART进阶应用:地址匹配、硬件流控与红外通信详解

1. 项目概述:深入UART的进阶功能

在嵌入式开发领域,UART(通用异步收发传输器)几乎是每个工程师的“老朋友”。我们用它来打印调试信息、连接传感器、与上位机通信,其基础操作——配置波特率、数据位、停止位——早已是肌肉记忆。然而,当项目从简单的点对点通信,演进到需要连接多个从设备的总线系统,或是需要应对复杂物理层协议(如红外遥控)时,标准UART的“基础款”功能就显得捉襟见肘了。

这时,现代微控制器中集成的增强型UART模块的真正威力才开始显现。它远不止是一个简单的串口,而是一个集成了地址过滤、智能流控制、甚至红外编解码协议的通信引擎。你是否曾困惑于如何在一条总线上让多个设备只听“自己该听的”命令?是否在高速数据流下为FIFO溢出而烦恼?又或者,想用最少的硬件资源实现一个红外遥控收发器?这些问题的答案,都藏在UART那些看似复杂的寄存器配置背后。

本文将带你跳出UART的基础应用,深入其三大高级功能核心:地址匹配(Address Match)硬件流控制(Hardware Flow Control),以及特殊的IrDA/CIR模式。我会结合TI AM261x等主流芯片的参考手册,不仅告诉你寄存器该怎么设,更会拆解其背后的设计逻辑、应用场景以及实际调试中踩过的坑。无论你是正在设计工业RS-485总线,还是为智能家居设备添加红外学习功能,这些内容都将是你工具箱里的利器。

2. 核心功能一:地址匹配与多机通信

在多设备(Multi-drop)通信网络中,例如基于RS-485的半双工总线,所有从设备都挂载在同一条数据线上。主机发送的每一帧数据,所有从设备都能接收到。如果每个从设备都对每一帧数据做出响应,总线将立即陷入混乱。地址匹配机制就是为了解决这个问题:它让从设备“装睡”,只有当数据帧中的地址与自身预设的地址相符时,才“醒来”并接收后续的数据。

2.1 地址匹配的工作原理与寄存器配置

地址匹配的核心思想是“掩码比较”。它并非要求地址字节的每一位都精确相等,而是通过一个掩码来指定哪些位需要严格匹配,哪些位可以忽略(“Don‘t Care”)。这提供了极大的灵活性,可以实现单地址寻址、组播(Group Address)和广播(Broadcast)。

实现这一功能的三个核心寄存器是:

  • UART_MAR (Match Address Register):这是你为UART模块设置的本地地址。例如,你可以将设备A的UART_MAR设为0xA1
  • UART_MMR (Mask Match Register):这是掩码寄存器。它的每一位对应UART_MAR的一位。
    • 如果UART_MMR的某一位设为1,则表示接收到的地址帧对应位必须与UART_MAR中的对应位严格匹配
    • 如果设为0,则表示这一位是“无关位”,接收到的值是0还是1都可以,不参与匹配判断。
  • UART_MBR (Broadcast Address Register):广播地址寄存器。当使能广播功能后,接收到这个特定地址的帧会被所有设备接受,无论其UART_MARUART_MMR如何设置。

匹配过程解析: 当UART接收到一个数据帧,且其校验位被硬件识别为“地址帧”(在Multi-drop模式下,通常用校验位=1表示地址帧,校验位=0表示数据帧)时,硬件会进行如下操作:

  1. 提取接收到的地址字节(假设为Rx_Addr)。
  2. 计算:(Rx_Addr & UART_MMR) == (UART_MAR & UART_MMR)
  3. 如果上述等式成立,或者Rx_Addr == UART_MBR(且广播已使能),则发生“地址匹配”。
  4. 匹配成功后,该地址帧及其后续的所有数据帧(直到下一个地址帧出现)都会被存入接收FIFO。否则,这些帧将被硬件静默丢弃。

一个具体的计算示例: 假设我们配置:UART_MAR = 0xF3 (二进制 1111 0011)UART_MMR = 0xF9 (二进制 1111 1001)

  • 掩码0xF9意味着我们只关心第7、6、5、4、3和0位(值为1的位)。第2位和第1位是“无关位”。
  • 那么,哪些地址能匹配呢?我们列出所有“无关位”(第2、1位)的组合:
    • 第2、1位为00:1111 00 11->0xF3
    • 第2、1位为01:1111 01 11->0xF7
    • 第2、1位为10:1111 10 11->0xFB
    • 第2、1位为11:1111 11 11->0xFF
  • 但注意,我们还需要满足关心的位(第7,6,5,4,3,0位)与MAR(0xF3)匹配。0xFB的第0位是1,而0xF3的第0位是1,看起来匹配?等等,0xF3的二进制是1111 0011,第0位是1。0xFB1111 1011,第0位也是1。但第3位呢?0xF3第3位是1,0xFB第3位也是1。实际上,0xFB0xF3MMR关心的位上(1111 1001)并不完全一致。让我们重新精确计算:
    • 关心的位掩码:MMR = 0xF9 = 1111 1001
    • MAR & MMR = 0xF3 & 0xF9 = 1111 0011 & 1111 1001 = 1111 0001 = 0xF1
    • 所以,匹配的条件是(Rx_Addr & 0xF9) == 0xF1
    • 0xF3 & 0xF9 = 1111 0011 & 1111 1001 = 1111 0001 = 0xF1,匹配。
    • 0xF5 & 0xF9 = 1111 0101 & 1111 1001 = 1111 0001 = 0xF1,匹配。
    • 0xF7 & 0xF9 = 1111 0111 & 1111 1001 = 1111 0001 = 0xF1,匹配。
    • 0xF1 & 0xF9 = 1111 0001 & 1111 1001 = 1111 0001 = 0xF1,匹配。
    • 0xFB & 0xF9 = 1111 1011 & 1111 1001 = 1111 1001 = 0xF9,不等于0xF1不匹配
    • 0xFF & 0xF9 = 1111 1111 & 1111 1001 = 1111 1001 = 0xF9,不等于0xF1不匹配(除非它是广播地址MBR)。 因此,单地址和组地址匹配集为:0xF10xF30xF50xF7。如果UART_MBR设置为0xFF且广播使能,那么0xFF也是一个匹配地址。

实操心得:灵活运用掩码掩码寄存器UART_MMR是地址匹配的灵魂。例如,如果你有8个设备,地址希望设为0x00到0x07,你可以将UART_MMR设为0xF8(1111 1000)。这样,高5位被忽略,低3位用于寻址,完美匹配0-7的地址范围。这比为每个设备单独设置完全不同的地址要清晰得多。

2.2 地址匹配的软件处理与中断管理

地址匹配发生后,硬件会通过状态寄存器告知软件。理解这个流程对编写稳定的多机通信驱动至关重要。

1. 匹配地址的获取: 匹配的地址值存储在接收保持寄存器UART_RHR中,但读取方式取决于FIFO配置:

  • FIFO禁用或阈值=1:匹配的地址帧会停留在UART_RHR中,可以直接读取。这是最简单的情况。
  • FIFO启用且阈值>1:地址帧会像普通数据一样进入FIFO。为了标识它,硬件会将该帧的奇偶校验错误(Parity Error, PE)位置1。所以,你需要扫描FIFO,找到那个PE位被置位的帧,该帧的数据就是匹配的地址。这要求你的驱动必须能正确处理带错误标志的数据。

2. 中断与状态识别: 要使能地址匹配中断,需要设置UART_IER_UART[2](LINE_STS_IT)位。

  • 当发生地址匹配时,硬件会触发一个“接收线路状态错误”中断。通过读取中断识别寄存器UART_IIR_UART[5:1],你会得到值0x00011
  • 进入中断服务程序后,第一步是读取线路状态寄存器UART_LSR_UART。这个读取操作本身会清除部分中断标志。
  • 检查UART_LSR_UART[2](RX_PE,接收奇偶校验错误位)。在Multi-drop地址匹配模式下,此位被重载为“地址匹配指示位”。如果该位为1,表示发生了地址匹配。
  • 同时,UART_LSR_UART[0](RX_FIFO_E,接收FIFO非空)和UART_LSR_UART[7](RX_FIFO_STS,接收FIFO中有错误)通常也会被置位。

关键点UART_LSR_UART[2](RX_PE)位的含义完全由UART_EFR2[2](MULTIDROP)位决定。当MULTIDROP=0(标准模式),它表示真正的奇偶校验错误。当MULTIDROP=1(多机模式),它表示地址匹配事件。你的驱动代码必须根据当前模式来解析这个位。

3. 中断清除: 无论是标准模式还是多机模式,清除线路状态中断(包括地址匹配中断)的方法都是一样的:读取UART_LSR_UART寄存器。这个操作会更新内部状态,使中断线恢复高电平。

踩坑记录:FIFO与地址帧的纠缠在一次RS-485总线调试中,我发现从机偶尔会“漏掉”主机发送的命令。排查后发现,问题出在FIFO阈值的设置上。我使能了16字节的FIFO,并将触发中断的阈值设为8。当主机快速发送一串数据时,地址帧可能被淹没在FIFO中。如果我的中断服务程序只是简单地读取UART_RHR直到FIFO空,而没有检查每个字节的PE位,我就无法准确知道哪个字节是地址,从而导致后续数据解析错位。教训是:在使用地址匹配功能且启用FIFO时,必须连同状态位(如LSR)一起读取,或者使用DMA并设置专门的地址匹配中断来处理。

2.3 时间防护(Time-guard)功能

在多点通信中,不同设备的处理速度可能差异很大。一个快速的MCU发送完一帧数据后,如果立即发送下一帧,慢速的从设备可能还没来得及处理完上一帧就错过了起始位,导致帧错误。Time-guard功能就是为了解决这个问题。

原理:Time-guard本质上是在发送的两个字符之间,插入一段可编程的“空闲时间”(高电平)。这段空闲时间就像是一个加长的停止位,给了接收方足够的“喘息”时间来处理数据或准备接收下一帧。

配置:通过UART_TIMEGUARD寄存器设置。该寄存器的值定义了要插入的波特率时钟周期数。例如,如果波特率是115200(每位时间约8.68μs),设置TIMEGUARD=10,则会在两帧之间插入约86.8μs的空闲时间。

应用场景

  1. 连接低速外设:如某些老式打印机、调制解调器。
  2. RS-485总线方向切换缓冲:在发送完毕后,插入一个Time-guard延时,再切换收发器方向为接收,可以确保最后一个字节的停止位完全在总线上传播完毕,避免总线冲突。
  3. ISO7816智能卡协议:该协议中定义的等待时间(Waiting Time)可以用Time-guard功能来实现。

注意事项:Time-guard与停止位Time-guard是在标准的停止位之外额外添加的延时。在计算总的帧间隔时,需要把这部分时间考虑进去。对于时序要求苛刻的协议,过长的Time-guard会降低有效数据吞吐量,需要根据接收端的最慢处理能力进行权衡和测试。

3. 核心功能二:硬件与软件流控制

流控制是保证通信双方数据不会丢失的“交通警察”。当接收方缓冲区快满时,它需要告诉发送方“暂停发送”;当缓冲区有空余时,再通知发送方“恢复发送”。UART提供了硬件和软件两种流控制方式。

3.1 硬件流控制(RTS/CTS)

硬件流控制通过两根独立的信号线RTS(Request To Send)和CTS(Clear To Send)实现,无需占用数据带宽,效率高且可靠。

1. 自动RTS(Auto-RTS)

  • 功能:由接收方控制。当接收方的RX FIFO空间充足时,它自动拉低RTS信号(假设低电平有效),告诉对方“我可以接收,请发送”。
  • 触发阈值:通过UART_TCR寄存器设置两个水位线:
    • RX_FIFO_TRIG_HALT(HALT阈值):当RX FIFO中的数据量达到或超过此阈值时,RTS信号被置高(无效),通知发送方暂停。
    • RX_FIFO_TRIG_START(RESUME阈值):当RX FIFO中的数据被读取,存量低于此阈值时,RTS信号被重新拉低(有效),通知发送方恢复。
  • 工作原理:发送方会持续监测RTS输入线的状态。只有检测到RTS有效时,才会发送数据。由于信号传播和处理的延迟,发送方可能在收到RTS变高的信号前,已经开始发送下一个字节。因此,HALT阈值需要留有一定余量,防止溢出。

2. 自动CTS(Auto-CTS)

  • 功能:由发送方控制。发送方在发送每个字节的起始位之前,会检查CTS输入线的状态。
  • 关键时序:如果CTS变为无效(要求暂停),这个变化必须发生在当前正在发送的字节的最后一个停止位的中间点之前,发送器才能来得及在下一字节开始前停止。如果CTS在停止位中点之后才变无效,发送器可能已经启动了下一字节的发送,从而导致潜在的溢出风险。
  • 优势:极大地减轻了CPU负担。无需CPU中断来检测CTS状态变化,硬件自动完成流控。

3. 联合使用:通常,通信双方会同时使能Auto-RTS和Auto-CTS。这样,A设备的RTS输出连接B设备的CTS输入,B设备的RTS输出连接A设备的CTS输入,形成一个全双工的硬件流控制环,从根本上避免了因处理速度不匹配导致的FIFO溢出(Overrun)错误。

配置步骤

  1. 确保硬件上RTSCTS引脚已正确连接。
  2. UART_EFR寄存器中,使能AUTO_RTS_ENAUTO_CTS_EN位。
  3. 根据FIFO大小和系统处理能力,合理配置UART_TCR中的HALTRESUME阈值。例如,对于一个16字节的RX FIFO,可以设置HALT=12RESUME=4

3.2 软件流控制(XON/XOFF)

软件流控制通过在线路上传输特殊的控制字符(XON和XOFF)来管理数据流。它不需要额外的硬件连线,但会占用数据带宽。

核心概念

  • XOFF(Transmit Off):通常为0x13(DC3, Ctrl-S)。接收方发送此字符,请求发送方暂停。
  • XON(Transmit On):通常为0x11(DC1, Ctrl-Q)。接收方发送此字符,通知发送方恢复。
  • 字符对:为了增加可靠性,可以使用两个字符的组合(XON1/XON2, XOFF1/XOFF2),必须按顺序接收才被识别。

寄存器配置

  • 控制使能:通过UART_EFR[3:0]这4个位来独立控制发送和接收的流控制模式。
    • EFR[3:2]:控制发送流。01=发送XON1/XOFF1,10=发送XON2/XOFF2,11=发送XON1/XON2和XOFF1/XOFF2对。
    • EFR[1:0]:控制接收流。01=比较XON1/XOFF1,10=比较XON2/XOFF2,11=比较字符对。
  • 字符定义UART_XON1_ADDR1UART_XON2_ADDR2UART_XOFF1UART_XOFF2寄存器分别用于存放这四个控制字符的值。

工作流程

  • 接收方:当使能接收流控制后,UART硬件会持续比对接收到的字符与预设的XOFF字符。一旦匹配,它会自动暂停自身的发送(注意:是暂停本端的发送,以响应对方的请求),并可能产生一个XOFF中断。要恢复发送,必须接收到匹配的XON字符。
  • 发送方:当使能发送流控制后,UART硬件会根据自身RX FIFO的填充情况,自动向对方发送XOFF或XON字符。当RX FIFO数据量超过HALT阈值,发送两个XOFF1字符;当数据量低于START阈值,发送两个XON1字符。

高级特性

  • XON-AnyUART_MCR[5]):使能后,在收到XOFF暂停后,接收到任何字符(除了特殊字符)都会恢复传输,而不仅仅是XON。这提供了更灵活的控制,但需要应用层协议配合。
  • 特殊字符检测UART_EFR[5]):使能后,当接收到XOFF2字符时,会产生一个中断,但不会暂停传输。这允许软件介入处理一些特殊事件。

重要警告:硬件与软件流控制互斥参考手册中明确指出,不应同时使能硬件流控制和软件流控制。因为两者的控制逻辑会冲突。例如,硬件流控根据FIFO水位自动控制,而软件流控也可能发送XOFF,导致通信逻辑混乱。在设计协议时,必须二选一。

3.3 自动波特率检测(Autobauding)

自动波特率检测功能允许UART模块自动识别对方设备的通信波特率、数据位和校验位,无需手动配置。这在需要对接不同规格设备或实现即插即用的场景中非常有用。

工作原理:模块通过检测一个特定的引导序列(通常是“AT”或“at”这两个ASCII字符,后跟回车<CR>)的波形时间宽度,来反推出波特率。同时,通过分析“AT”字符的格式(7位/8位,奇校验/偶校验等),确定数据格式。

支持的范围(以48MHz时钟为例):

  • 波特率:从1200 bps到115200 bps,共10种标准速率。
  • 数据位:7位或8位。
  • 校验位:奇校验、偶校验或强制空格(Space)校验。注意:7位数据位+空格校验的组合不被支持。

配置与使用流程

  1. UART_MDR1[2:0](MODE_SELECT)设置为0x2,进入自动波特率模式。
  2. 等待对方发送“AT”或“at”引导序列。
  3. 当硬件成功检测到序列后,会触发一个中断,并将检测到的参数(波特率除数、数据位、校验位)更新到UART_UASR(自动波特率状态寄存器)中。
  4. 软件读取UART_UASR,并据此配置UART_LCR(数据格式)和UART_DLL/DLH(波特率除数)寄存器,使本端参数与对端匹配。
  5. 之后,通信即可正常进行。如果后续需要重新检测或切换回标准模式,必须先将MODE_SELECT设置为0x7(复位状态),然后再设置为0x0(标准模式)或0x2(重新开始自动波特率检测)。

实操心得:Autobaud的局限性与应用自动波特率检测依赖于标准的“AT”序列。如果你的通信对象无法发送这个序列,此功能就无法使用。此外,检测过程需要时间,会增加初始连接的延迟。它非常适合用于调制解调器、蓝牙模块等需要自适应速率的设备初始化。但在稳定通信阶段,建议切换到固定波特率模式以获得最佳性能。

4. 核心功能三:IrDA红外通信模式

IrDA(Infrared Data Association)是一种利用红外光进行短距离点对点通信的标准。UART模块通过集成IrDA编码/解码器(SIR, MIR, FIR),可以直接驱动红外LED和接收器,无需外部编解码芯片。

4.1 IrDA模式概述与时钟生成

IrDA定义了三种物理层速率:

  • SIR (Serial Infrared):速率从9.6kbps到115.2kbps,采用归零(RZI)编码,即“0”对应一个窄脉冲(3/16位时间或1.6μs),“1”对应无脉冲。
  • MIR (Medium Infrared):0.576Mbps和1.152Mbps,采用1/4占空比的脉冲调制。
  • FIR (Fast Infrared):4Mbps,采用4PPM(脉冲位置调制)编码。

时钟生成:IrDA的波特率生成器比标准UART更复杂,因为它需要产生特定宽度的红外脉冲。

  • SIR模式:除数 = 系统时钟 / (16 × 目标波特率)。例如,48MHz系统时钟下,要得到115200bps,除数 = 48,000,000 / (16 * 115200) ≈ 26.04,取整为26,实际波特率为115384bps,误差+0.16%。
  • MIR模式:除数 = 系统时钟 / (41×/42× × 目标波特率)。这是一个交替的41或42分频,用于产生平均波特率。
  • FIR模式:固定使用6倍分频,直接产生4MHz的基带时钟。

关键配置警告:在修改波特率除数寄存器(UART_DLHUART_DLL)之前,必须先将UART_MDR1[2:0](MODE_SELECT)设置为0x7(禁用模式),修改完成后再设回IrDA模式。否则可能导致不可预测的模块行为。

4.2 IrDA数据格式化与高级功能

1. 地址检查(IR Address Checking): 类似于UART的多机地址匹配,IrDA模式也支持地址过滤,用于红外多点通信环境。可以设置两个地址(通过UART_XON1_ADDR1UART_XON2_ADDR2寄存器),并通过UART_EFR[1:0]位选择检查其中一个或两个地址。只有地址匹配的帧才会被存入RX FIFO。

2. 帧结束(Frame Closing)方式: IrDA通信以帧为单位。有两种方式通知硬件一帧数据结束:

  • 帧长度法UART_MDR1[7]=0):软件在发送前,将本帧的总字节数写入UART_TXFLHUART_TXFLL寄存器。硬件发送完指定数量的字节后,自动添加帧结束标志。
  • 设置EOT位法UART_MDR1[7]=1):软件在将一帧的最后一个字节写入TX FIFO之前,先将UART_ACREG[0](EOT)位置1。硬件会为这个被标记的字节自动添加帧结束标志。这种方式更灵活,适合动态生成帧长度的场景。

3. 存储与控制传输(SCT Mode): 正常模式下,数据一写入TX FIFO,只要发送器空闲就会立即开始发送。在SCT模式下(UART_MDR1[5]=1),写入数据后不会立即发送。只有当软件将UART_ACREG[2](SCTX_EN)置1后,整个已写入FIFO的数据才会作为一个完整的帧开始发送。这对于发送短帧(如ACK帧)非常有用,可以避免因FIFO未填满而导致的发送间隔,确保帧的连续性。

4. 状态FIFO(Status FIFO): 这是IrDA模式的一个强大特性。除了数据FIFO,还有一个独立的8入口状态FIFO。每成功接收完一个完整的IrDA帧,硬件就会将一个状态字写入状态FIFO。状态字包含:

  • 帧长度:通过读取UART_SFREGHUART_SFREGL获得。
  • 错误状态:通过读取UART_SFLSR获得,如CRC错误、帧中止(Abort)等。 软件可以通过状态FIFO高效地管理接收流程。例如,结合DMA将数据自动搬运到内存,然后仅在状态FIFO达到一定深度时中断CPU。CPU通过状态FIFO的信息,就能知道收到了几帧、每帧多长、是否有错,从而进行高效处理(如只重传出错的帧)。

4.3 SIR、MIR、FIR模式特定要点

SIR模式

  • 中止序列(Abort):可以通过设置UART_ACREG[1](ABORT_EN)来发送一个特殊的“0x7D 0xC1”序列,强制中止当前帧的发送,不附加CRC。这在需要紧急终止传输时使用。
  • 脉冲整形:通过UART_ACREG[7](PULSE_TYPE)选择3/16位时间或固定1.6μs的脉冲宽度。
  • SIR自由格式(SIR FF):一种特殊的模式,允许UART模块产生SIR脉冲,但数据格式仍遵循UART规范(8N1)。这需要将模块模式设为UART(MODE_SELECT=0x0),但使能脉冲整形(UART_MDR2[3] PULSE=1)。

MIR/FIR模式

  • SIP(Sub-frame Identification Pulse):在MIR和FIR中,帧之间需要发送SIP脉冲。可以通过UART_MDR1[6](SIP_MODE)和UART_ACREG[3](SEND_SIP)位来控制SIP的发送策略。默认每帧后都发,也可以由软件定时控制发送,以减少协议开销。

调试经验:红外通信的视线与干扰IrDA是视线通信,发送和接收器之间不能有障碍物,且有一定夹角限制。在实际调试中,通信失败很多时候不是软件配置问题,而是物理问题:LED驱动电流不足、接收头被环境光干扰(尤其是日光灯)、或对准偏差。建议先用示波器观察TX引脚输出的脉冲波形是否正确,再用红外接收管直接观察是否有光信号发出。软件上,确保IrDA的RX极性(UART_MDR2[6] IRRXINVERT)设置正确,因为大多数红外接收头输出的信号是反向的。

5. 核心功能四:CIR消费红外模式

CIR(Consumer Infrared)模式专用于消费电子产品的红外遥控器信号收发,如电视、空调遥控器。它与IrDA完全不同,IrDA用于高速数据通信,而CIR用于传输低速、带有特定载波(通常为38kHz)的编码信号(如NEC, RC-5协议)。

5.1 CIR模式工作原理

CIR模式更像一个“可编程红外波形发生器与解码器”。

  • 发射端:你需要预先将编码好的波形数据(一系列表示高低电平时间的数值)写入TX FIFO。硬件会根据这些数据,结合载波调制设置,在输出引脚上生成对应的红外波形。
  • 接收端:红外接收头(通常已解调,输出数字信号)连接到RX引脚。硬件对信号进行采样、解码,并将解码出的数据(或原始脉冲时间)存入RX FIFO。

关键配置:载波生成载波频率(如38kHz)由UART_CFPS(载波频率预分频)寄存器控制。计算公式为:分频值 = (F_CLK / 12) / 目标载波频率其中F_CLK是系统时钟(如48MHz)。对于38kHz载波:分频值 = (48,000,000 / 12) / 38,000 ≈ 105.26,通常取整为105。硬件会用这个分频值对系统时钟进行分频,产生占空比可调(如1/3, 1/2等)的载波脉冲,用于调制数据。

5.2 CIR模式的数据结构与协议实现

CIR模式不关心具体的NEC或RC-5协议,它只负责生成或解析“脉冲-间隔”序列。因此,软件需要承担协议编解码的工作

例如,实现NEC协议发射

  1. NEC协议一个位“0”是:560μs载波脉冲 + 560μs空闲。
  2. 一个位“1”是:560μs载波脉冲 + 1680μs空闲。
  3. 你需要根据要发送的地址和命令码,生成一个比特流,并计算出每个电平持续的系统时钟周期数
  4. 将这些周期数按照“脉冲时间, 间隔时间, 脉冲时间, 间隔时间...”的顺序,组织成一个数据数组。
  5. 将这个数组写入UART的TX FIFO,并启动CIR发送模式。硬件会自动读取这些时间值,并生成带有38kHz调制的红外波形。

接收端则相反,硬件会测量输入脉冲的高低电平宽度,并将这些时间值存入RX FIFO。软件从中读取时间序列,再根据NEC协议的规则去解析出地址和命令。

优势与挑战

  • 优势:极其灵活,理论上可以实现任何脉冲距离编码的红外协议。
  • 挑战:所有协议细节都需要软件实现,包括引导码识别、数据位解析、重复码处理、校验等,开发复杂度高。对CPU的中断响应时间和处理能力有一定要求。

个人体会:CIR vs. 专用红外编码芯片对于简单的红外发射,使用CIR模式可以节省一颗外部的红外编码芯片(如PT2262等)。但对于复杂的、需要学习功能的万能遥控器,CIR模式的软件解码会占用大量CPU资源。此时,使用一个专用的红外编解码芯片,通过SPI或I2C与MCU通信,可能是更稳定、更省心的方案。CIR模式更适合于产品中需要固定发送某几种红外码,或对成本极其敏感的场景。

6. 错误处理、超时与调试技巧

可靠的通信系统必须能妥善处理异常情况。UART模块提供了丰富的错误检测和恢复机制。

6.1 错误检测与中断管理

UART通过UART_LSR_UART(线路状态寄存器)报告各种错误:

  • OE (Overrun Error):接收溢出错误。当RX FIFO已满,新数据又到来时发生。读取UART_LSR_UART寄存器会清除OE位
  • PE (Parity Error):奇偶校验错误。在Multi-drop模式下,此位被重用作地址匹配指示。
  • FE (Framing Error):帧错误。通常是由于波特率不匹配或噪声导致停止位检测不到。
  • BI (Break Indicator):线路中断错误。检测到长时间的低电平(Break信号)。
  • RX_FIFO_STS:当RX FIFO中存在任何错误(PE, FE, BI)时,此位被置1。只有当FIFO中所有错误帧都被读取后,此位才清零。

中断处理顺序建议

  1. 读取UART_IIR_UART获取中断源。
  2. 如果是接收数据中断(IIR=0x04),则从UART_RHR读取数据。
  3. 如果是接收线路状态中断(IIR=0x06),则立即读取UART_LSR_UART。根据LSR中的错误位进行相应处理(如丢弃错误数据、重置FIFO等)。
  4. 如果是字符超时中断(IIR=0x0C),则读取UART_RHR将FIFO中剩余数据全部取出。

6.2 接收超时与Break条件

接收超时(Timeout): 当接收线路空闲(保持高电平)超过一定时间后,会触发超时中断。这非常有用,它可以通知软件“一个不完整的数据包已经接收完毕”。例如,你期望接收10个字节,但对方只发了5个就停止了。没有超时功能,你会一直等待下去。有了超时,在空闲时间达到(例如,4个字符时间+12位时间)后,就会产生中断,让你可以处理已接收的5个字节。 超时行为可通过UART_EFR2[6]配置:默认只在FIFO中有数据时计数;也可以配置为即使FIFO为空,只要线路空闲就周期性产生中断(用于链路监测)。

发送Break信号: Break信号是通过将TX线拉低超过一个完整字符传输时间来实现的,常用于复位外设或标识帧开始。发送一个完整的、对齐到字符边界的Break需要精确操作:

  1. 确保TX FIFO为空(或复位TX FIFO)。
  2. 等待发送移位寄存器空(UART_LSR_UART[6] TX_SR_E == 1)。
  3. 等待一个完整的停止位时间(作为保护时间)。
  4. UART_LCR[6] BREAK_EN位置1,开始发送Break。
  5. 保持该位为1的时间,即为Break信号的持续时间。
  6. 将其清零,恢复正常通信。

6.3 常见问题排查实录

问题1:通信完全无反应,收不到任何数据。

  • 检查时钟与波特率:这是最常见的问题。确认系统时钟频率是否正确,计算出的波特率除数是否准确写入UART_DLL/DLH。用示波器测量TX引脚,看是否有波形,以及位时间是否正确。
  • 检查引脚复用:确认UART的TX、RX引脚功能已正确映射到GPIO,并且GPIO模式设置为复用功能。
  • 检查流控制:如果使能了硬件流控,检查RTS/CTS信号线是否被意外拉高/拉低,导致通信锁死。可以尝试暂时禁用流控进行测试。
  • 检查FIFO:如果使能了FIFO,确保在初始化时没有意外重置或禁用了FIFO。尝试禁用FIFO看是否恢复正常。

问题2:能收到数据,但全是乱码。

  • 检查数据格式:双方的数据位、停止位、校验位设置必须完全一致。一个常见的错误是8位数据位和7位数据位+奇偶校验的混淆(后者在传输时也占8位,但含义不同)。
  • 检查电平:确认双方是TTL电平(0V/3.3V)还是RS-232电平(±12V)。如果是RS-232,需要电平转换芯片。
  • 检查中断服务程序:确保在读取UART_RHR后,及时清除了相应的中断标志。如果中断标志未清除,可能导致后续中断无法触发。

问题3:多机通信中,从机响应混乱或收不到指定地址的数据。

  • 确认Multi-drop模式:确保UART_EFR2[2] MULTIDROP位已设置为1。
  • 仔细核对地址和掩码:使用我们前面介绍的方法,手动计算一下你的MARMMR设置,到底匹配哪些地址。最好写一个简单的测试程序,让从机打印出所有收到的地址帧,以验证匹配逻辑。
  • 检查地址帧标识:确认主机发送的地址帧,其校验位设置正确(通常为1)。在Multi-drop模式下,硬件依赖校验位来区分地址帧和数据帧。

问题4:使用IrDA或CIR时,通信距离极短或不稳定。

  • 检查驱动电流:红外LED的驱动电流是否足够?通常需要20-100mA的瞬时电流。检查限流电阻和三极管驱动电路。
  • 检查接收头:红外接收头是否被环境光干扰?尝试遮蔽环境光测试。接收头的载波频率是否匹配(通常是38kHz)?
  • 检查软件解码(针对CIR):用逻辑分析仪捕获TX/RX引脚波形,与标准协议对比。检查软件解码算法中对脉冲宽度的容错范围是否合理,因为红外传输存在抖动。

问题5:使能自动波特率后,无法建立连接。

  • 确认引导序列:对方发送的是否是确切的“AT”或“at”后跟回车(0x0D)?大小写敏感。
  • 检查模式切换顺序:在尝试自动波特率前,是否先将MODE_SELECT设为了0x2?检测失败后,要复位(设为0x7)再重试。
  • 波特率范围:确认对方的波特率在芯片支持的列表内(如1200-115200)。

调试串口通信,示波器或逻辑分析仪是最得力的工具。不要只依赖打印信息,直接观察线上的波形,能发现绝大多数时序和信号完整性问题。从最简配置开始(无FIFO,无流控,固定波特率),逐步添加复杂功能,是定位问题最高效的方法。