IR Receive
该示例演示红外接收功能的使用方法。
使用另一颗 EVB 下载 IR 发送的程序作为 IR 数据的发送端向该 EVB 发送 IR 数据。
在 IR 中断内进行数据的接收,若数据量大于 IR 的 FIFO,需要连续多次地接收数据。
IR 发送端的示例可参考 IR Transmit 。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
使用另一颗 EVB 下载 IR TX 程序,连接 IR 接收引脚 P2_5 和另一颗 EVB 的发送引脚。
配置选项
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\IR\Rx\mdk
Project file: board\evb\io_sample\IR\Rx\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
当 IR 接收计数器的个数达到设置的阈值,代表 IR 数据接收完毕,进入 IR 中断,打印接收数据。接收的数据即为 IR 发送端定义的数据内容。
[io_ir]io_handle_ir_msg: IR RX data[0] = xxx
[io_ir]io_handle_ir_msg: IR RX data[1] = xxx
...
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\IR\Rx
源码路径:
sdk\src\sample\io_sample\IR\Rx
该工程的工程文件代码结构如下:
└── Project: ir_rx
└── 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
├── ancs.c
├── app.c
├── app_task.c
└── io_ir.c
初始化
当 EVB 复位启动时,调用 main()
函数,将执行以下流程:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
global_data_init();
board_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
备注
le_gap_init()
,gap_lib_init()
,app_le_gap_init
,app_le_profile_init
等为 privacy 管理模块相关的初始化,参考 LE Peripheral Privacy 中的初始化流程介绍。
与外设相关的初始化流程具体如下:
在
global_data_init
中,执行global_data_ir_init
,该函数为全局初始化,初始化全局变量IR_Rx_Data
,重置 IR 接收数据。void global_data_ir_init(void) { /* Initialize adc k value! */ APP_PRINT_INFO0("[io_ir]global_data_ir_init"); memset(&IR_Rx_Data, 0, sizeof(IR_Rx_Data)); IR_RX_Count = 0; }
在
board_init
中,执行board_ir_init
,该函数为 PAD/PINMUX 设置,包含如下流程:配置 PAD:设置引脚、PINMUX 模式、PowerOn、无内部上拉、输出失能。
配置 PINMUX:分配引脚为 IRDA_RX 功能。
在执行
os_sched_start()
开启任务调度后,在app_main_task
主任务内,执行driver_init
对外设驱动进行初始化配置。在
driver_init
中执行driver_ir_init
,该函数为 IR 外设的初始化,包含如下流程:使能 RCC 时钟。
设置 IR 接收频率为 38kHz。
设置 IR 为自动接收模式。
设置 IR 接收阈值为 30,当 IR 接收 FIFO 满时丢弃最新数据,过滤低于 50ns 的杂波数据。
设置触发接收计数器阈值中断的电平类型为高电平,IR_RxCntThr 设置为 0x1F40。
使能 IR 外设接收功能,清除 IR 接收 FIFO。
void driver_ir_init(void) { /* 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 = 38000;/* IR carrier freqency is 38KHz */ IR_InitStruct.IR_Mode = IR_MODE_RX;/* IR receiveing mode */ IR_InitStruct.IR_RxStartMode = IR_RX_AUTO_MODE; IR_InitStruct.IR_RxFIFOThrLevel = IR_RX_FIFO_THR_LEVEL; /* Configure RX FIFO threshold level to trigger IR_INT_RF_LEVEL interrupt */ IR_InitStruct.IR_RxFIFOFullCtrl = IR_RX_FIFO_FULL_DISCARD_NEWEST;/* Discard the lastest received dta if RX FIFO is full */ IR_InitStruct.IR_RxFilterTime = IR_RX_FILTER_TIME_50ns;/* If high to low or low to high transition time <= 50ns,Filter out it. */ IR_InitStruct.IR_RxTriggerMode = IR_RX_FALL_EDGE;/* Configure trigger type */ IR_InitStruct.IR_RxCntThrType = IR_RX_Count_High_Level;/* IR_RX_Count_High_Level is counting high level */ IR_InitStruct.IR_RxCntThr = 0x1F40;/* Configure RX counter threshold.You can use it to decide to stop receiving IR data */ IR_Init(&IR_InitStruct); IR_Cmd(IR_MODE_RX, ENABLE); IR_ClearRxFIFO(); /* 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); }
功能实现
在主函数中执行
os_sched_start()
,开启任务调度。当 stack 准备好时,执行app_handle_dev_state_evt
,执行ir_demo
。配置 IR 接收 FIFO 数据个数大于设置的接收阈值中断
IR_INT_RF_LEVEL
和接收电平超时中断IR_INT_RX_CNT_THR
。取消屏蔽
IR_INT_RF_LEVEL
和IR_INT_RX_CNT_THR
中断。
void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause) { ... if (gap_dev_state.gap_init_state != new_state.gap_init_state) { if (new_state.gap_init_state == GAP_INIT_STATE_STACK_READY) { APP_PRINT_INFO0("GAP stack ready"); /*stack ready*/ ir_demo(); } } ... } void ir_demo(void) { /* Enable IR threshold interrupt. when RX FIFO offset >= threshold value, trigger interrupt*/ /* Enable IR counter threshold interrupt to stop receiving data */ IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); }
向 IR 收发模块发送 IR 数据。当 IR 接收 FIFO 的数据个数达到设置的接收阈值(此例中设为 30)时,触发
IR_INT_RF_LEVEL
中断。或当接收计数器的个数达到设置的阈值(此例中设为 0x1F40)时,触发IR_INT_RX_CNT_THR
中断,进入中断处理函数IR_Handler
。屏蔽
IR_INT_TF_LEVEL
和IR_INT_RX_CNT_THR
中断。如果触发的中断为
IR_INT_TF_LEVEL
,则需要 IR 从 FIFO 中接收数据。将数据存入 DataBuf 内,并记录已经接收的数据长度。如果触发的中断为
IR_INT_RX_CNT_THR
,则代表触发了 IR 接收数据的停止条件。将剩余数据存入 DataBuf 内,记录已经接收的数据长度,并打印数据内容。清除
IR_INT_RX_CNT_THR
中断挂起位。取消屏蔽
IR_INT_RF_LEVEL
和IR_INT_RX_CNT_THR
中断。
void IR_Handler(void) { uint16_t len = 0; ITStatus int_status_rfl = IR_GetINTStatus(IR_INT_RF_LEVEL); ITStatus int_status_rxcnt = IR_GetINTStatus(IR_INT_RX_CNT_THR); /* Mask IR all interrupt */ IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); /* Receive by interrupt */ if (int_status_rfl == SET) { len = IR_GetRxDataLen(); IR_ReceiveBuf(IR_Rx_Data.DataBuf + IR_RX_Count, len); IR_Rx_Data.DataLen += len; IR_RX_Count += len; IR_ClearINTPendingBit(IR_INT_RF_LEVEL_CLR); } /* Stop to receive IR data */ if (int_status_rxcnt == SET) { /* Read remaining data */ len = IR_GetRxDataLen(); IR_ReceiveBuf(IR_Rx_Data.DataBuf + IR_RX_Count, len); IR_Rx_Data.DataLen += len; IR_RX_Count += len; T_IO_MSG int_ir_msg; int_ir_msg.type = IO_MSG_TYPE_IR; int_ir_msg.subtype = 0; int_ir_msg.u.buf = (void *)(&IR_Rx_Data); if (false == app_send_msg_to_apptask(&int_ir_msg)) { APP_PRINT_ERROR0("[io_ir]IR_INT_RX_CNT_THR: Send int_ir_msg failed!"); //Add user code here! IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR); return; } IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR); } /* Unmask IR all interrupt */ IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); } void io_handle_ir_msg(T_IO_MSG *io_ir_msg) { IR_Data_TypeDef *p_buf = io_ir_msg->u.buf; for (uint16_t i = 0; i < p_buf->DataLen; i++) { APP_PRINT_INFO2("[io_ir]io_handle_ir_msg: IR RX data[%d] = 0x%x", i, p_buf->DataBuf[i]); } memset(&IR_Rx_Data, 0, sizeof(IR_Rx_Data)); IR_RX_Count = 0; }