IR Transmit

该示例演示 IR 发送功能的使用方法。

使用 IR 外设进行数据发送,实现红外发射功能,使用逻辑分析仪观察 IR 发送波形。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

更多信息请参考 快速入门

硬件连线

连接 IR 发送引脚 P2_5 至逻辑分析仪。

编译和下载

该示例的工程路径如下:

Project file: board\evb\io_sample\IR\Tx\mdk

Project file: board\evb\io_sample\IR\Tx\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译 APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MP Tool 给出的步骤将 app bin 烧录至 EVB 内。

  5. 按下 reset 按键,开始运行。

测试验证

在逻辑分析仪内,观察 IR 发送波形。波形如下图所示:

这里应该是IR发送波形的图片

IR 发送波形

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\board\evb\io_sample\IR\Tx

  • 源码路径: sdk\src\sample\io_sample\IR\Tx

该工程的工程文件代码结构如下:

└── Project: ir_tx
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            ├── ROM.lib
            └── adc.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_ir.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

初始化

当 EVB 复位启动时,执行 main 函数,执行以下流程:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    __enable_irq();

    ir_demo();

    ...
}

ir_demo 中,包含了 PAD/PINMUX 设置,IR 外设初始化流程。

void ir_demo(void)
{
    ...
    board_ir_init();
    driver_ir_init(IR_TxData.CarrierFreq);

    ...
}

board_ir_init 为 IR 相关引脚的 PAD 与 PINMUX 设置,包含如下流程:

  1. 配置 PAD:设置引脚、PINMUX 模式、PowerOn、无内部上拉,输出低。

  2. 配置 PINMUX:分配引脚为 IRDA_TX 功能。

driver_ir_init 为对 IR 外设的初始化,包含如下流程:

  1. 使能 RCC 时钟。

  2. 设置 IR 发送频率为 38kHz。

  3. 设置 IR 载波占空比为 1/2。

  4. 设置 IR 为发送模式。

  5. 设置不反转 IR 发送数据。

  6. 设置 IR 发送 FIFO 阈值为 2。

  7. 配置 IR 发送 FIFO 数据个数小于设置的发送阈值中断 IR_INT_TF_LEVEL

void driver_ir_init(uint32_t vFreq)
{
    /* Enable ir clock */
    RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, ENABLE);

    /* Initialize ir */
    IR_InitTypeDef IR_InitStruct;
    IR_StructInit(&IR_InitStruct);
    IR_InitStruct.IR_Freq           = vFreq;
    IR_InitStruct.IR_DutyCycle      = 2; /* !< 1/2 duty cycle */
    IR_InitStruct.IR_Mode           = IR_MODE_TX;
    IR_InitStruct.IR_TxInverse      = IR_TX_DATA_NORMAL;
    IR_InitStruct.IR_TxFIFOThrLevel = IR_TX_FIFO_THR_LEVEL;
    IR_Init(&IR_InitStruct);

    /* Enable IR threshold interrupt. when TX FIFO offset <= threshold value, trigger interrupt*/
    IR_INTConfig(IR_INT_TF_LEVEL, ENABLE);

    /* Configure nvic */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = IR_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

功能实现

  1. ir_demo 内,定义 IR 发送数据。有载波数据用载波个数与 0x80000000 进行或运算表示,无载波数据用载波个数与 0x00000000 进行或运算表示。

  2. 执行 IR_SendBuf() 函数,开始往 IR 发送 FIFO 中塞发送数据;使能 IR 外设发送功能。

  3. 记录已经发送的数据个数。

    void ir_demo(void)
    {
        /* Data to send */
        IR_TxData.CarrierFreq = 38000;
        IR_TxData.DataLen = 67 + 1; //2+64+1;
        IR_TxData.DataBuf[0] =  0x80000000 | 0x156; //342 about 9ms
        IR_TxData.DataBuf[1] =  0x00000000 | 0xAB; //171 about 4.5ms
        for (uint16_t i = 2; i < IR_TxData.DataLen - 1;)
        {
            IR_TxData.DataBuf[i] =  0x80000000 | 0x15; //21  about 560us
            IR_TxData.DataBuf[i + 1] =  0x00000000 | 0x15; //21  about 565us
            i += 2;
        }
        IR_TxData.DataBuf[30] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[31] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[62] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[63] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[64] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[65] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[66] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[IR_TxData.DataLen - 1] =  0x80000000 | 0x15;
    
        ...
    
        /* Start to send data. */
        IR_SendBuf(IR_TxData.DataBuf, IR_TX_FIFO_SIZE, DISABLE);
        IR_Cmd(IR_MODE_TX, ENABLE);
        /* Record number which has been sent */
        IR_TX_Count = IR_TX_FIFO_SIZE;
    }
    
  4. 当 IR 发送 FIFO 数据个数小于设置的发送阈值(此例中设为 2)时,触发 IR_INT_TF_LEVEL 中断,进入中断处理函数 IR_Handler

    1. 屏蔽 IR_INT_TF_LEVEL 中断。

    2. 由于 IR 发送数据可能数据量较大(大于 IR TX FIFO 深度),因此需要分批进行发送。

    3. 如果剩余发送数据个数大于发送 FIFO 大小,往 IR 发送 FIFO 中塞 (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL) 个数据并发送,代表剩余的数据量仍然大于 IR TX FIFO 深度。

    4. 否则如果剩余发送数据个数大于 0,往 IR 发送 FIFO 中塞剩余数据,代表剩余的数据量小于 IR TX FIFO 深度,即发送最后一笔数据。

    5. 否则如果没有剩余数据,失能 IR_INT_TF_LEVEL 中断,代表 IR 所有数据发送完毕。

    6. 取消屏蔽 IR_INT_TF_LEVEL 中断。

    void IR_Handler(void)
    {
        /* Get IR interrupt status */
        ITStatus int_status = IR_GetINTStatus(IR_INT_TF_LEVEL);
    
        /* Mask IR interrupt */
        IR_MaskINTConfig(IR_INT_TF_LEVEL, ENABLE);
    
        /* Continue to send by interrupt */
        if (int_status == SET)
        {
            /* The remaining data is larger than the TX FIFO length */
            if ((IR_TxData.DataLen - IR_TX_Count) >= IR_TX_FIFO_SIZE)
            {
                IR_SendBuf(IR_TxData.DataBuf + IR_TX_Count, (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL), DISABLE);
                IR_TX_Count += (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL);
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
            else if ((IR_TxData.DataLen - IR_TX_Count) > 0)
            {
                /* The remaining data is less than the TX FIFO length */
    
                /*  Configure TX threshold level to zero and trigger interrupt when TX FIFO is empty */
                IR_SetTxThreshold(0);
                IR_SendBuf(IR_TxData.DataBuf + IR_TX_Count, IR_TxData.DataLen - IR_TX_Count, DISABLE);
                IR_TX_Count += (IR_TxData.DataLen - IR_TX_Count);
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
            else
            {
                /* Tx completed */
                /* Disable IR tx empty interrupt */
                IR_INTConfig(IR_INT_TF_LEVEL, DISABLE);
                IR_TX_Count = 0;
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
        }
    
        /* Unmask IR interrupt */
        IR_MaskINTConfig(IR_INT_TF_LEVEL, DISABLE);
    }