AM261x UART CIR模式:硬件实现红外遥控协议的原理与实战 1. 项目概述与CIR模式核心价值在嵌入式开发尤其是智能家居、消费电子和工业控制领域红外遥控是一种经典且成本低廉的无线通信方式。我们通常需要一颗专用的红外编解码芯片或者用MCU的通用定时器配合GPIO来模拟红外载波这无疑增加了硬件成本和软件复杂度。但如果你手头的处理器比如德州仪器的AM261x系列其UART模块内置了消费者红外模式事情就变得简单多了。CIR模式本质上是对UART硬件的一种“超频”使用它让一个原本设计用于异步串行通信的接口摇身一变成为了一个灵活可编程的红外信号发生器与解码器。这带来的直接好处是“一体化”。你不再需要额外的硬件编解码芯片也无需在软件层面用宝贵的CPU周期去精确控制定时器和GPIO翻转来生成38kHz载波和复杂的脉冲序列。UART的硬件FIFO、DMA和中断机制可以被直接复用CPU只需要像发送普通串口数据一样将编好码的字节流写入发送FIFO硬件就会自动将其调制为符合红外协议格式的波形从TX引脚输出。接收亦然红外接收头输出的信号经过硬件解调直接还原成字节数据存入接收FIFO。这不仅极大降低了CPU负载提高了系统实时性也让代码结构更清晰协议切换更灵活。无论是常见的RC-5、SIRC还是自定义协议都可以通过配置UART的CIR相关寄存器来实现。接下来我们就深入AM261x的UART模块拆解CIR模式的工作原理、配置要点和实战代码。2. CIR模式硬件接口与信号定义要使用CIR模式首先得搞清楚硬件引脚是如何复用的。在普通UART模式下我们熟悉的是TXD发送、RXD接收可能还有RTS/CTS流控。但在CIR模式下这些引脚被赋予了新的角色。2.1 引脚功能重映射根据AM261x的技术参考手册当UART模块被配置为CIR模式时其物理引脚的功能会发生如下变化UARTx_TXD引脚从普通的串行数据输出转变为CIR调制信号输出。这个引脚会输出经过脉宽调制的红外载波信号需要外接一个三极管或专用的红外发射管驱动电路来驱动红外发射二极管。UARTx_RXD引脚功能保持不变仍作为串行数据输入。在CIR接收模式下它连接红外接收模块的输出端。红外接收头如HS0038B会将接收到的38kHz调制红外信号解调为数字电平信号直接送入此引脚。UARTx_RTSn引脚这个引脚在CIR模式下被用作SDShutdown信号。它是一个输出信号用于控制外部红外收发器的使能或关断。例如它可以连接到一个红外发射电路的使能端在不需要发射时关闭驱动电路以节省功耗。其输出电平是UART_ACREG[6]寄存器的SD_MOD位的反相值。注意硬件设计时务必确认原理图。红外发射部分通常需要增加驱动三极管如8050因为UART_TXD引脚的驱动电流有限通常为4mA不足以直接驱动红外发射二极管IF约100mA。接收部分则简单许多红外接收头的输出端通常为集电极开路或推挽输出直接连接到UART_RXD即可一般需要上拉电阻。2.2 接口信号详解下面的表格清晰地总结了CIR模式下这三个关键信号的定义和复位状态模块引脚设备级信号方向描述模块引脚复位值RXUARTx_RXD输入串行数据输入来自红外接收头高阻态TXUARTx_TXD输出CIR模式下的串行数据输出调制红外信号0SDUARTx_RTSn输出SD模式用于配置使能/关断外部收发器1理解这个映射关系是硬件连接和软件初始化的基础。例如SD引脚复位后为高电平1如果外部电路是低电平有效使能那么复位后红外发射电路是关闭的这是一个安全的设计。3. CIR协议原理与数据格式深度解析CIR模式的核心魅力在于其灵活性。它不像某些专用红外芯片那样固化了某一种协议而是提供了一套基于可变脉宽调制的底层硬件引擎上层协议完全由软件定义。3.1 载波调制与脉冲占空比红外遥控信号并非持续的高电平或低电平而是用一定频率的载波通常是38kHz对基带信号进行幅度调制。在CIR模式下每一个被发送的逻辑‘1’或‘0’都被转换成一个或多个载波脉冲块。基本时间单元t这是CIR模式的“心跳周期”其长度由UART的波特率发生器决定。t是红外信号编码的最小时间分辨率。所有脉冲的宽度都是t的整数倍。脉冲调制一个逻辑‘1’会被发送为一个持续时间为t的调制脉冲。这个“脉冲”实际上是一串频率为载波频率的方波。逻辑‘0’则被发送为一段持续时间为T的空白期无载波。T的长度也是可编程的通常是t的整数倍用于区分不同的编码格式。占空比选择调制脉冲内部载波的占空比是可以配置的通过设置UART_MDR2[5:4] (CIR_PULSE_MODE)位域可以选择1/4、1/3、5/12或1/2四种占空比。占空比影响发射功率和接收灵敏度。1/2占空比能量最强但功耗也最大1/4占空比较为节能。通常38kHz载波标准占空比为1/3但CIR模式提供了灵活性以适应不同接收头的特性。这里有一个关键点硬件保证每个调制脉冲都会被完整发送不会被截断。这意味着你无需担心字节边界处的脉冲不完整。但是当连续发送多个字节时字节之间没有硬件自动插入的延迟。如果目标协议如NEC要求数据帧间有特定的引导码或帧间间隔这个间隔必须由软件在组帧时计算并插入相应的“空白”数据来实现。3.2 主流红外编码协议实现CIR硬件不关心高层协议它只负责将你写入FIFO的每一个比特按照配置的t、T和占空比转换成对应的红外脉冲或空白。因此实现特定协议的关键在于如何用比特流去“描述”该协议的波形。1. 脉冲宽度编码如NEC协议这是最常见的一类用脉冲和空白的不同时长来表示‘0’和‘1’。例如NEC协议引导码9ms的载波脉冲 4.5ms的空白。逻辑‘0’560us脉冲 560us空白。逻辑‘1’560us脉冲 1690us空白。 在CIR模式下我们需要定义t。假设我们选择t 560us这需要根据系统时钟和波特率分频器精确计算。那么逻辑‘0’可以编码为一个t脉冲 一个t空白即比特序列10但注意这是硬件层面的脉冲/空白不是数据位的值。逻辑‘1’可以编码为一个t脉冲 三个t空白即比特序列1000。引导码则需要特殊处理16个t脉冲9ms / 560us ≈ 16 8个t空白4.5ms / 560us ≈ 8。这需要你构造一个很长的“1”脉冲串然后跟一个长的“0”空白串。由于硬件发送连续字节无间隔你需要精确计算这些长脉冲/空白对应的字节序列并写入FIFO。2. 双相编码如RC-5协议RC-5协议使用曼彻斯特编码每一位中间都有跳变。‘0’表示为先高后低‘1’为先低后高每位时长固定为1.778ms。在CIR模式下我们可以用“01”这个2-bit序列来表示RC-5的‘1’因为‘01’会产生一个t脉冲后跟一个t空白正好形成一个从有载波到无载波的跳变对应先高后低这里需要仔细对应。实际上手册举例说明为了用CIR模拟RC-5需要将RC-5的每个位映射成两个t脉冲。例如RC-5的‘1’一个位周期内前半部分高后半部分低可能被映射为“01”序列第一个t为脉冲第二个t为空白。因此要发送RC-5的比特序列“0101”主机CPU需要向UART的FIFO写入二进制字符10011001即0x99。这是因为每个RC-5位被拆成了两个CIR比特。3. 脉冲距离编码如SIRC协议索尼的SIRC协议用脉冲的持续时间来区分‘1’和‘0’但空白时间固定。‘1’1.2ms的脉冲。‘0’0.6ms的脉冲。每位之后都有0.6ms的固定空白。 在CIR模式下这可以通过设置不同的T空白时间固定为0.6ms对应的t倍数和不同的脉冲宽度‘1’用2个t脉冲’0‘用1个t脉冲来实现。同样需要软件将协议符号映射成具体的字节序列。3.3 数据包构造与软件职责由于CIR硬件只处理比特到脉冲的转换完整的红外数据包包括引导码、地址、命令、校验和等必须由软件构造。以RC-5标准帧为例一帧数据包含2个起始位总是‘1’1个翻转位Toggle bit5个系统地址位6个命令位软件需要按照这个结构将每个位根据上述的编码规则如曼彻斯特编码转换成对应的CIR比特序列然后按顺序将这些比特打包成字节写入UART的发送FIFO。对于接收过程相反硬件将红外信号解调成比特流存入FIFO软件需要从FIFO中读取字节流再按照协议规则解析出地址和命令。核心要点CIR模式将复杂的红外波形生成与解码工作硬件化但协议层的组帧和解析工作完全交给了软件。这提供了无与伦比的灵活性允许你用同一套硬件支持几乎任何现有的或自定义的红外协议但同时也对软件设计提出了更高要求需要精确的时序计算和数据处理。4. AM261x UART CIR模式配置实战指南理论清晰后我们进入实战环节。在AM261x上配置UART进入CIR模式并收发数据需要遵循一系列步骤。这里假设你已具备基本的AM261x SDK开发环境并了解如何操作外设寄存器。4.1 整体配置流程引脚复用配置通过PINMUX控制器将目标UART模块的TXD、RXD、RTSn引脚功能复用到对应的物理引脚上。确保RTSn引脚被正确配置为UART_RTSn功能它在CIR模式下是SD信号。时钟与电源初始化确保UART模块所在的电源域和时钟域已使能。UART模块需要两个时钟VBUS_CLK用于寄存器访问和内部逻辑UART_CLK用于生成波特率和CIR的时基t。UART_CLK的来源需要根据所需精度选择如外部晶振或PLL输出。软件复位向UART_SYSC[1]寄存器写入1对UART模块进行软复位使其回到已知状态。模式选择这是关键一步。通过配置UART_MDR1[2:0]寄存器将模式选择为CIR_MODE。CIR特定参数配置设置UART_MDR2[5:4]选择载波脉冲占空比如1/3。配置波特率发生器UART_DLL和UART_DLH寄存器以确定基本时间单元t。t 1 / BaudRate。例如要得到t 26.33us对应38kHz载波的半个周期这里需要计算波特率应设置为1 / 26.33e-6 ≈ 37978 baud。实际上t是发送一个比特的时间而一个比特可能对应一个脉冲或一段空白。你需要根据目标协议的时序来反推所需的波特率。配置UART_LCR寄存器设置数据位、停止位等在CIR模式下这些设置可能影响FIFO到移位寄存器的行为但数据格式本身由软件定义。FIFO与中断/DMA配置使能FIFOUART_FCR[0] 1。设置发送和接收FIFO的触发阈值UART_FCR[5:4]和[7:6]或更精细的UART_TLR寄存器。根据应用需求选择中断模式或DMA模式并配置相应的中断使能寄存器UART_IER_CIR或DMA控制器。使能收发器通过UART_ECR寄存器分别使能发送器和接收器。SD引脚控制根据外部电路配置UART_ACREG[6]的SD_MOD位以控制SD引脚RTSn的输出电平从而使能或关闭外部红外发射电路。4.2 关键寄存器详解与配置示例以下是一个简化的CIR发送初始化代码片段展示了关键寄存器的配置// 假设 UART2 基地址为 UART2_BASE // 1. 引脚复用配置 (需根据具体板级设计设置PINMUX此处省略) // 2. 使能模块时钟 (依赖具体平台时钟初始化函数此处省略) // 3. 软件复位 HW_WR_REG32(UART2_BASE UART_SYSC, 0x2); // 设置SOFTRESET位 while((HW_RD_REG32(UART2_BASE UART_SYSC) 0x1) 0x1); // 等待复位完成 // 4. 选择CIR模式 HW_WR_REG32(UART2_BASE UART_MDR1, 0x3); // MODE_SELECT 0x3 (CIR Mode) // 5. 配置CIR参数 uint32_t mdr2_val 0; mdr2_val | (0x1 4); // 示例选择 1/3 占空比 (CIR_PULSE_MODE 0x01) HW_WR_REG32(UART2_BASE UART_MDR2, mdr2_val); // 6. 配置波特率以定义时间基准 t // 假设系统UART_CLK为48MHz我们需要 t 26.33us (约38kHz载波周期的一半常用于NEC协议) // 所需波特率 1 / 26.33e-6 ≈ 37978 baud // 分频值 DLL/DLH UART_CLK / (16 * 波特率) 48e6 / (16 * 37978) ≈ 78.94 // 取整为79实际波特率约为 48e6 / (16 * 79) 37974 baud误差可接受。 HW_WR_REG32(UART2_BASE UART_LCR, 0x80); // 设置DLAB位为1允许访问DLL/DLH HW_WR_REG32(UART2_BASE UART_DLL, 79); // 写入分频值低8位 HW_WR_REG32(UART2_BASE UART_DLH, 0); // 写入分频值高8位 HW_WR_REG32(UART2_BASE UART_LCR, 0x03); // 8位数据位1位停止位无校验清除DLAB // 7. 配置FIFO和中断 HW_WR_REG32(UART2_BASE UART_FCR, 0x07); // 使能FIFO清除TX/RX FIFO触发级别默认 // 使能发送FIFO空中断当TX FIFO为空时产生中断便于连续发送 HW_WR_REG32(UART2_BASE UART_IER_CIR, 0x02); // 使能THR中断 (bit 1) // 8. 使能发送器 HW_WR_REG32(UART2_BASE UART_ECR, 0x1); // 使能TX // 9. 配置SD引脚如果需要使能外部发射电路 // 假设SD引脚低电平有效使能外部电路 HW_WR_REG32(UART2_BASE UART_ACREG, (1 6)); // 设置SD_MOD1则RTSn(SD)输出低电平4.3 数据发送与协议模拟配置完成后发送红外数据就变成了向UART_THR寄存器或FIFO写入特定的字节序列。以发送一个简单的NEC协议“0”键地址0x00命令0x45为例我们需要先根据NEC协议的时序将整个帧转换成对应的CIR比特流再打包成字节。NEC一帧数据9ms脉冲4.5ms空白 8位地址 8位地址反码 8位命令 8位命令反码 结束脉冲。逻辑‘0’560us脉冲 560us空白。逻辑‘1’560us脉冲 1690us空白。我们已经设置t 26.33us。那么560us ≈ 21.27个t取整21。1690us ≈ 64.18个t取整64。9ms ≈ 341.8个t取整342。4.5ms ≈ 170.9个t取整171。这意味着我们需要用软件构造一个很长的比特序列。例如发送一个逻辑‘1’我们需要写入一个代表21个t脉冲的“1”紧接着写入64个代表t空白“0”。这需要我们将这些连续的“1”和“0”打包成字节。一个高效的实现方法是预先计算好整个协议帧对应的字节数组在发送时直接通过DMA或循环写入FIFO。// 示例一个极度简化的发送函数实际应用需要根据协议精确计算比特流 void send_cir_pulse_train(uint32_t duration_t_units, uint8_t is_pulse) { // duration_t_units: 脉冲或空白持续的 t 单元数 // is_pulse: 1表示发送载波脉冲0表示发送空白 uint32_t bits_remaining duration_t_units; while(bits_remaining 0) { uint8_t byte_to_send 0; for(int i 0; i 8 bits_remaining 0; i) { byte_to_send | (is_pulse i); // 每个bit都设置为脉冲或空白 bits_remaining--; } // 等待THR就绪或使用中断/DMA while((HW_RD_REG32(UART2_BASE UART_LSR) 0x20) 0); // 等待THR空 HW_WR_REG32(UART2_BASE UART_THR, byte_to_send); } } // 发送NEC引导码概念性代码未处理字节边界 send_cir_pulse_train(342, 1); // 9ms脉冲 send_cir_pulse_train(171, 0); // 4.5ms空白 // ... 接着发送地址、命令等数据位重要提醒上述代码仅为原理演示实际工程中必须精心设计比特到字节的打包算法并考虑字节间无延迟的特性。对于NEC这类协议引导码和数据位的时长不同需要分别计算。更常见的做法是使用一个状态机或查找表将整个协议帧预先编码成一个字节缓冲区然后一次性启动DMA传输。5. 常见问题、调试技巧与实战心得在实际项目中调试CIR功能经常会遇到一些棘手的问题。这里分享一些踩坑后总结的经验。5.1 典型问题排查表现象可能原因排查步骤与解决方案完全无红外信号发射1. SD引脚未正确使能外部电路。2. UART未配置为CIR模式。3. 发射管或驱动电路故障。4. UART_TXD引脚未正确复用。1. 用示波器测量SD引脚电平确认符合外部电路使能逻辑。2. 检查UART_MDR1寄存器模式选择位。3. 检查硬件连接测量驱动三极管基极连接TXD是否有波形。4. 确认PINMUX配置。红外信号波形畸变或接收端无反应1. 基本时间单元t计算错误波特率不准。2. 载波占空比设置不当。3. 发射管驱动电流不足。4. 软件组帧逻辑错误协议不对。1.用示波器测量TXD引脚波形核对脉冲和空白的实际宽度是否符合预期t的倍数。这是最直接的调试手段。2. 尝试调整CIR_PULSE_MODE标准38kHz接收头通常适应1/3占空比。3. 检查限流电阻确保发射管峰值电流足够通常20-100mA。4. 使用逻辑分析仪或带红外解码功能的示波器捕获发射波形与标准协议对比。能发送但不能接收1. 接收头电源或接地不良。2. UART_RXD引脚上拉电阻缺失或错误。3. 接收中断或FIFO触发未配置。4. 发送与接收的t基准不一致。1. 测量接收头VCC和GND。2. 红外接收头输出通常是开漏需接上拉电阻如4.7kΩ至VCC。3. 检查UART_IER_CIR接收中断是否使能或检查LSR寄存器DR位。4. 确保收发使用相同的波特率即相同的t。通信距离短1. 发射管驱动电流太小。2. 载波占空比过低平均功率小。3. 发射管指向性或周围强光干扰。1. 减小驱动三极管的限流电阻增大电流注意不要超过管子额定值。2. 将占空比改为1/2。3. 避免阳光或白炽灯直射接收头确保发射管对准接收窗。连续发送时数据粘连字节间无间隔导致。在软件组帧时在协议要求的帧间间隔处插入足够数量的“空白”比特即发送对应数量的逻辑‘0’。5.2 调试心得与高级技巧示波器是最好伙伴没有比一台示波器更能直观理解CIR工作的工具了。直接测量UART_TXD引脚你应该能看到清晰的、由短脉冲串38kHz和长空白间隔组成的波形。通过测量脉冲和空白的宽度可以立刻验证你的t计算是否正确软件组帧是否准确。精确计算t与波特率t的精度直接决定了协议兼容性。尽量使用高精度、低抖动的时钟源作为UART_CLK如外部晶振。波特率分频值DLL/DLH的计算务必使用浮点数并考虑四舍五入带来的误差。对于NEC协议560us和1690us的时长要求比较宽松误差在±10%内通常可接受。但对于某些严格协议误差必须控制在±5%以内。利用DMA减轻CPU负担红外遥控数据包虽然不长但一旦开始发送就需要连续、及时地向FIFO填充数据。使用DMA将预先编码好的整个数据帧从内存搬运到UART_THR可以彻底解放CPU避免因中断延迟或任务调度导致发送波形出现不该有的间隙。AM261x的UART支持TX和RX DMA请求务必利用起来。功耗考虑在电池供电设备中红外发射是耗电大户。CIR模式支持睡眠模式通过UART_MDR1[3]设置。在空闲时确保进入睡眠模式以降低功耗。同时通过SD引脚在非发射期间彻底关闭外部发射电路的电源可以进一步省电。协议栈设计建议将红外协议编码/解码部分设计成独立的、与硬件无关的模块。这个模块的输入是地址、命令等逻辑数据输出是按照特定协议规则编码好的比特流或字节流。底层驱动CIR驱动则负责将这个比特流通过硬件发送出去。这样的分层设计便于适配不同的硬件CIR或GPIO模拟和扩展新的协议。通过深入理解CIR模式的硬件机制并结合细致的软件设计你可以在AM261x这类高性能处理器上实现稳定、高效且灵活的红外通信功能为你的嵌入式产品增添可靠的遥控交互能力。