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
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
在逻辑分析仪内,观察 IR 发送波形。波形如下图所示:

IR 发送波形
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
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 设置,包含如下流程:
配置 PAD:设置引脚、PINMUX 模式、PowerOn、无内部上拉,输出低。
配置 PINMUX:分配引脚为 IRDA_TX 功能。
driver_ir_init
为对 IR 外设的初始化,包含如下流程:
使能 RCC 时钟。
设置 IR 发送频率为 38kHz。
设置 IR 载波占空比为 1/2。
设置 IR 为发送模式。
设置不反转 IR 发送数据。
设置 IR 发送 FIFO 阈值为 2。
配置 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); }
功能实现
在
ir_demo
内,定义 IR 发送数据。有载波数据用载波个数与 0x80000000 进行或运算表示,无载波数据用载波个数与 0x00000000 进行或运算表示。执行
IR_SendBuf()
函数,开始往 IR 发送 FIFO 中塞发送数据;使能 IR 外设发送功能。记录已经发送的数据个数。
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; }
当 IR 发送 FIFO 数据个数小于设置的发送阈值(此例中设为 2)时,触发
IR_INT_TF_LEVEL
中断,进入中断处理函数IR_Handler
。屏蔽
IR_INT_TF_LEVEL
中断。由于 IR 发送数据可能数据量较大(大于 IR TX FIFO 深度),因此需要分批进行发送。
如果剩余发送数据个数大于发送 FIFO 大小,往 IR 发送 FIFO 中塞 (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL) 个数据并发送,代表剩余的数据量仍然大于 IR TX FIFO 深度。
否则如果剩余发送数据个数大于 0,往 IR 发送 FIFO 中塞剩余数据,代表剩余的数据量小于 IR TX FIFO 深度,即发送最后一笔数据。
否则如果没有剩余数据,失能
IR_INT_TF_LEVEL
中断,代表 IR 所有数据发送完毕。取消屏蔽
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); }