AM261x UART CIR模式:硬件实现红外遥控协议的原理与实战
2026/7/19 12:51:19 网站建设 项目流程

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模式下被用作SD(Shutdown)信号。它是一个输出信号,用于控制外部红外收发器的使能或关断。例如,它可以连接到一个红外发射电路的使能端,在不需要发射时关闭驱动电路以节省功耗。其输出电平是UART_ACREG[6]寄存器的SD_MOD位的反相值。

注意:硬件设计时务必确认原理图。红外发射部分通常需要增加驱动三极管(如8050),因为UART_TXD引脚的驱动电流有限(通常为4mA),不足以直接驱动红外发射二极管(IF约100mA)。接收部分则简单许多,红外接收头的输出端(通常为集电极开路或推挽输出)直接连接到UART_RXD即可,一般需要上拉电阻。

2.2 接口信号详解

下面的表格清晰地总结了CIR模式下这三个关键信号的定义和复位状态:

模块引脚设备级信号方向描述模块引脚复位值
RXUARTx_RXD输入串行数据输入(来自红外接收头)高阻态
TXUARTx_TXD输出CIR模式下的串行数据输出(调制红外信号)0
SDUARTx_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的每一个比特,按照配置的tT和占空比,转换成对应的红外脉冲或空白。因此,实现特定协议的关键在于如何用比特流去“描述”该协议的波形。

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 bit)
  • 5个系统地址位
  • 6个命令位

软件需要按照这个结构,将每个位根据上述的编码规则(如曼彻斯特编码)转换成对应的CIR比特序列,然后按顺序将这些比特打包成字节,写入UART的发送FIFO。对于接收,过程相反:硬件将红外信号解调成比特流存入FIFO,软件需要从FIFO中读取字节流,再按照协议规则解析出地址和命令。

核心要点CIR模式将复杂的红外波形生成与解码工作硬件化,但协议层的组帧和解析工作完全交给了软件。这提供了无与伦比的灵活性,允许你用同一套硬件支持几乎任何现有的或自定义的红外协议,但同时也对软件设计提出了更高要求,需要精确的时序计算和数据处理。

4. AM261x UART CIR模式配置实战指南

理论清晰后,我们进入实战环节。在AM261x上配置UART进入CIR模式并收发数据,需要遵循一系列步骤。这里假设你已具备基本的AM261x SDK开发环境,并了解如何操作外设寄存器。

4.1 整体配置流程

  1. 引脚复用配置:通过PINMUX控制器,将目标UART模块的TXD、RXD、RTSn引脚功能复用到对应的物理引脚上。确保RTSn引脚被正确配置为UART_RTSn功能,它在CIR模式下是SD信号。
  2. 时钟与电源初始化:确保UART模块所在的电源域和时钟域已使能。UART模块需要两个时钟:VBUS_CLK用于寄存器访问和内部逻辑,UART_CLK用于生成波特率和CIR的时基tUART_CLK的来源需要根据所需精度选择(如外部晶振或PLL输出)。
  3. 软件复位:向UART_SYSC[1]寄存器写入1,对UART模块进行软复位,使其回到已知状态。
  4. 模式选择:这是关键一步。通过配置UART_MDR1[2:0]寄存器,将模式选择为CIR_MODE
  5. CIR特定参数配置
    • 设置UART_MDR2[5:4]选择载波脉冲占空比(如1/3)。
    • 配置波特率发生器(UART_DLLUART_DLH寄存器)以确定基本时间单元tt = 1 / BaudRate。例如,要得到t = 26.33us(对应38kHz载波的半个周期?这里需要计算),波特率应设置为1 / 26.33e-6 ≈ 37978 baud。实际上,t是发送一个比特的时间,而一个比特可能对应一个脉冲或一段空白。你需要根据目标协议的时序来反推所需的波特率。
    • 配置UART_LCR寄存器设置数据位、停止位等(在CIR模式下,这些设置可能影响FIFO到移位寄存器的行为,但数据格式本身由软件定义)。
  6. FIFO与中断/DMA配置
    • 使能FIFO(UART_FCR[0] = 1)。
    • 设置发送和接收FIFO的触发阈值(UART_FCR[5:4][7:6],或更精细的UART_TLR寄存器)。
    • 根据应用需求,选择中断模式或DMA模式,并配置相应的中断使能寄存器(UART_IER_CIR)或DMA控制器。
  7. 使能收发器:通过UART_ECR寄存器分别使能发送器和接收器。
  8. 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_MOD=1,则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 调试心得与高级技巧

  1. 示波器是最好伙伴:没有比一台示波器更能直观理解CIR工作的工具了。直接测量UART_TXD引脚,你应该能看到清晰的、由短脉冲串(38kHz)和长空白间隔组成的波形。通过测量脉冲和空白的宽度,可以立刻验证你的t计算是否正确,软件组帧是否准确。

  2. 精确计算t与波特率t的精度直接决定了协议兼容性。尽量使用高精度、低抖动的时钟源作为UART_CLK,如外部晶振。波特率分频值(DLL/DLH)的计算务必使用浮点数,并考虑四舍五入带来的误差。对于NEC协议,560us和1690us的时长要求比较宽松,误差在±10%内通常可接受。但对于某些严格协议,误差必须控制在±5%以内。

  3. 利用DMA减轻CPU负担:红外遥控数据包虽然不长,但一旦开始发送,就需要连续、及时地向FIFO填充数据。使用DMA将预先编码好的整个数据帧从内存搬运到UART_THR,可以彻底解放CPU,避免因中断延迟或任务调度导致发送波形出现不该有的间隙。AM261x的UART支持TX和RX DMA请求,务必利用起来。

  4. 功耗考虑:在电池供电设备中,红外发射是耗电大户。CIR模式支持睡眠模式(通过UART_MDR1[3]设置)。在空闲时,确保进入睡眠模式以降低功耗。同时,通过SD引脚在非发射期间彻底关闭外部发射电路的电源,可以进一步省电。

  5. 协议栈设计:建议将红外协议编码/解码部分设计成独立的、与硬件无关的模块。这个模块的输入是地址、命令等逻辑数据,输出是按照特定协议规则编码好的比特流(或字节流)。底层驱动(CIR驱动)则负责将这个比特流通过硬件发送出去。这样的分层设计便于适配不同的硬件(CIR或GPIO模拟)和扩展新的协议。

通过深入理解CIR模式的硬件机制,并结合细致的软件设计,你可以在AM261x这类高性能处理器上实现稳定、高效且灵活的红外通信功能,为你的嵌入式产品增添可靠的遥控交互能力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询