前言

概述

BS2XV100通过API(Application Programming Interface)向开发者提供红外学习的相关接口,包括红外学习、发送以及恢复默认设置等相关接口。

读者对象

本文档主要适用于以下工程师:

  • 技术支持工程师

  • 软件开发工程师

  • 软件测试工程师

符号约定

在本文中可能出现下列标志,它们所代表的含义如下。

符号

说明

表示如不避免则将会导致死亡或严重伤害的具有高等级风险的危害。

表示如不避免则可能导致死亡或严重伤害的具有中等级风险的危害。

表示如不避免则可能导致轻微或中度伤害的具有低等级风险的危害。

用于传递设备或环境安全警示信息。如不避免则可能会导致设备损坏、数据丢失、设备性能降低或其它不可预知的结果。

“须知”不涉及人身伤害。

对正文中重点信息的补充说明。

“说明”不是安全警示信息,不涉及人身、设备及环境伤害信息。

修改记录

文档版本

发布日期

修改说明

03

2025-12-01

更新“通过比较器进行红外学习”章节内容。

02

2025-05-30

  • 更新“红外学习方式”章节内容。
  • 更新“通过比较器进行红外学习”章节内容。

01

2024-07-03

第一次正式版本发布。

红外学习方式

波形拷贝式学习方式

描述方法:载波频率+高低电平持续时间,也就是高低电平描述方式。

设计思想:把原遥控器所发出的信号进行完全拷贝,而不管遥控器是什么格式,目前将学习的波形数据通过SFC接口存储在memory_config_common.h中定义的IR Region地址中,在发送的时候读出数据进行发送。

优点:通用性非常好,可以描述一些协议,不用管逻辑值的定义。载波频率和高低电平也是非常容易获取的信息。

波形拷贝式学习方法解析

环境准备:红外接收器需要可以接受到红外载波并输入,载波周期和高低电平一起解析。

载波频率解析方法

计算两个下降沿时间差值。载波周期:Td1 – Td2 (us),载波频率:1/(Td1 – Td2) (us)。使用tcxo分别记录两次下降沿的时间,求差值,在学习结束之后将所有的差值进行平均值运算,计算出载波频率。

计算两个上升沿时间差值。载波周期:Tu1 – Tu2 (us),载波频率:1/(Td1 – Td2) (us)。使用tcxo分别记录两次下降沿的时间,求差值,在学习结束之后将所有的差值进行平均值运算,计算出载波频率。

图 1 红外载波计算

高低电平解析方法

  1. 在Tu处记录当前时间,在计算完载波频率后,启动一个timer定时器,定时大约为两个载波周期的时间。

  2. 在下一次gpio中断来的时候,清除并重启timer定时器。

  3. 在进入timer定时器中断的时候就证明没有gpio中断了,红外波形进入低电平阶段了,这是计算下TH,并在第一次定时器中断的时候起一个超时定时器,设置时间为200ms,用作学习结束处理中断。

  4. 在下一次进入gpio中断,计算下TL。然后重复步骤1~步骤3

这样就计算出高低电平时间。

static void ir_tickentry(void)
{
    uint64_t current_time = uapi_tcxo_get_us();
    if (g_rx_count == 0) {
        g_carrier_timer = (g_carrier_timer / IR_TICK_COUNT) + IR_TIMER_DELAY;
    }
    g_rx_pattern[g_rx_count] = (int16_t)(current_time - IR_TIMER1_OUT_US + g_carrier_timer - g_rx_start);
    g_rx_count++;
    g_rx_start = current_time  - IR_TIMER1_OUT_US;
    g_timer_flag = true;
    if (g_rx_count == 1) {
        ir_clock_check_study_end(IR_TIMER0_OUT_US);
    }
ir_port_tick_timer1_eoi_clr();
osal_irq_clear(TIMER_1_IRQN);
}

通过比较器进行红外学习

新增uapi_ir_study_by_cmp_start接口,需要硬件改板,暂时未在demo中使用,遥控器为了降低Bom成本的驱动下,尝试用芯片内比较器做红外RX,以减少板级有源管子的数量来降Bom成本。

红外Transceiver管R2经限流电阻R8接到红外控制IR_TX,在红外接收状态下IR_TX上拉高电平,D2在红外光照下会产生感光电压,该电压通过C22交流耦合至BS2X的比较器输入管脚,BS2X的芯片比较器需要直流偏置,通过20k/10k电阻产生1/3VDD的偏置,同时为了降低该电阻的静态漏电,可以通过GPIO来关断控制。

图 1 红外学习原理图

比较器学习方式

用比较器中断代替原有红外rx的gpio输入中断,解析方法与“红外学习方式”相同,其他操作不变,直接调用uapi_ir_study_by_cmp_start即可。

使用指南

  1. 调用uapi_ir_study_start接口开始学习,参数为学习的按键键值。

    void uapi_ir_study_start(uint8_t key_value)
    {
        g_rx_key = key_value;
        g_rx_count = 0;
        g_rx_start = 0;
        g_carrier_count = 0;
        g_carrier_timer_start = 0;
        g_carrier_timer = 0;
        g_carrier_flag = false;
        g_timer_flag = false;
        (void)memset_s(g_rx_pattern, PATTERN_LEN * sizeof(int16_t), 0, PATTERN_LEN * sizeof(int16_t));
        ir_port_flash_reg_read(IR_FLASH_OFFSET, (uint8_t*)(g_study_tmp_buff[0]), 0xFA0);
        ir_port_flash_reg_erase(IR_FLASH_OFFSET, 0x1000);
        ir_flash_write(key_value, (uint32_t**)g_study_tmp_buff);
        ir_port_unregister_irq(TIMER_1_IRQN);
        ir_port_register_irq(TIMER_1_IRQN, (osal_irq_handler)ir_tickentry);
        ir_port_unregister_irq(TIMER_0_IRQN);
        ir_port_register_irq(TIMER_0_IRQN, (osal_irq_handler)ir_study_end_tickentry);
        ir_port_gpio_init();
        ir_port_unregister_irq(GPIO_0_IRQN);
        ir_port_register_irq(GPIO_0_IRQN, (osal_irq_handler)ir_gpio_irq_handler);
    }
    
  2. timer1为载波超时中断,只有在大约两个载波周期没有来gpio中断后,才会进入timer1中断函数中,进入timer1中断函数时gpio电平为持续低电平,此时计算上一段高电平时间。

    static void ir_tickentry(void)
    {
        uint64_t current_time = uapi_tcxo_get_us();
        if (g_rx_count == 0) {
            g_carrier_timer = (g_carrier_timer / IR_TICK_COUNT) + IR_TIMER_DELAY;
        }
        g_rx_pattern[g_rx_count] = (int16_t)(current_time - IR_TIMER1_OUT_US + g_carrier_timer - g_rx_start);
        g_rx_count++;
        g_rx_start = current_time  - IR_TIMER1_OUT_US;
        g_timer_flag = true;
        if (g_rx_count == 1) {
            ir_clock_check_study_end(IR_TIMER0_OUT_US);
        }
        ir_port_tick_timer1_eoi_clr();
        osal_irq_clear(TIMER_1_IRQN);
    }
    
  3. timer0为学习超时/结束中断,在第一次进入timer1中断函数是开始计时,时间为200ms,在该中断函数中将学习到的载波数据写入flash中。

    static void ir_study_end_tickentry(void)
    {
        ir_port_tick_timer1_disable();
        ir_port_tick_timer0_disable();
        ir_port_gpio_mask_interrupt();
        uint32_t addr = 0;
        rx_pattern_info_t rx_info;
        rx_info.length = (uint32_t)g_rx_count;
        g_rx_count = 0;
        rx_info.rx_buff = g_rx_pattern;
        uint32_t irq_sts = osal_irq_lock();
        for (uint8_t i = 0; i < IR_KEY_NUM; i++) {
            if (g_rx_key == g_rx_key_index[i]) {
                addr = g_rx_addr_map[i];
                break;
            }
    }
    
    ir_study_freq_set(&rx_info.freq);
    
    if (rx_info.freq == 0 && g_ir_cb_register_flag == true) {
        g_ir_callback(IR_STUDY_FAILURE);
    }
    
    if (addr < IR_FLASH_OFFSET || addr > IR_FLASH_OFFSET + IR_FLASH_LENGTH) {
        osal_irq_restore(irq_sts);
        ir_port_cmp_deinit();
        osal_irq_clear(TIMER_0_IRQN);
        osal_printk("ir study addr error:0x%x\n", addr);
        return;
    }
    ir_port_flash_reg_write(addr, (uint8_t *)(&rx_info),
                            sizeof(uint32_t) * IR_FLASH_REG_OFFSET);
    ir_port_flash_reg_write(addr + sizeof(uint32_t) * IR_FLASH_REG_OFFSET, (uint8_t *) 
                           (rx_info.rx_buff), (rx_info.length) * sizeof(int16_t));
    if (g_ir_cb_register_flag == true) {
        g_ir_callback(IR_STUDY_SUCCESS);
    }
    osal_irq_restore(irq_sts);
    ir_port_tick_timer0_eoi_clr();
    osal_irq_clear(TIMER_0_IRQN);
    }
    

注意:当前留给红外学习的flash空间为4K,起始地址为IR_FLASH_OFFSET。