Page 1 of 1

T2-U开发板实现红外遥控接收与发送

Posted: 2023年 Jun 2日 17:28
by chenyisong

红外遥控是利用近红外光进行数据传输的一种控制方式,广泛应用在工业控制、家电、照明等多个领域,很多产品在加入了智能控制功能后,依然还会保留红外控制方式。

这次我们就是使用Tuya T2-U开发板开发智能产品的基础上,加入红外接收、发送功能。不仅可以通过APP、语音等方式控制设备,还可以使用红外遥控器控制。

一、红外概况

近红外光波长0.76um1.5um,红外遥控收发器件波长一般为0.8um ~ 0.94um,具有传输效率高,成本低,电路实现简单,抗干扰强等特点。

红外遥控一般有发射和接收两部分组成,发射元件为红外发射管,接收一般采用一体化红外接收头,但发射载波频率与接收头固定频率需一致才能正确接收。

ir.png

二、发射

1. 调制

红外遥控是以调制方式发射数据,将数据调制到固定的载波上发送,调制发送抗干扰能力更强,传送距离也更远。
红外发送首先要解决的就是调制问题,目前主流的调制方式有PPM和PWM。

  • PPM:脉冲位置调制,调制脉冲宽度不变,用脉冲间隔来区分0和1。如下图所示,脉冲宽度不变都是560us,脉冲间隔改变。逻辑1总时间为2.25ms,逻辑0中时间长度为1.12ms。
ppm.png

图1:PPM调制

  • PWM:脉冲宽度调制,脉冲间隔不变,调制脉冲宽度改变。如下图所示,脉冲间隔 为600us,脉冲宽度不同。逻辑1高电平时间为1.2ms,逻辑0高电平时间为0.6ms。
pwm.png

图2:PWM调制

调制载波频率一般在30KHz到60KHz之间,常用的载波有33K,36K,36.6K,38K,40K,56K等,其中38K使用最多。
常用占空比有1/3、1/2,1/3最多。

2. 红外传输协议

常用的红外传输协议有ITT协议、NEC协议、Nokia NRC协议、Sharp协议、Philips RC-5、RC-6 RECS-80协议、Sony SIRC协议等,其中最常见的为NEC协议。
常见NEC协议分析:

  • 载波38KHz,逻辑1为2.25ms,脉冲时间560us;逻辑0为1.12ms,脉冲时间560us
nec.png

图3:NEC逻辑’0’与逻辑’1’

  • 协议格式
nec_protocol.png

图4:NEC红外载波发送协议

(1) 首先发送9ms的载波脉冲
(2) 然后发送4.5ms的低电平
(3) 接下来是8bit的地址码(低位在前)
(4) 然后是8bit的地址反码,用于检验地址码是否出错
(5) 接下来的是8bit的命令码(低位在前)
(6) 然后是8bit的命令反码,用于检验命令码是否出错。

  • 重复码
repeat.png

图5:NEC重复发送载波协议

如果一直按着一个键,将以110ms为周期发送重复码,重复码由9ms载波、2.25ms低电平及560us载波组成。

nec_repeat.png

图6:NEC重复码

3. 编码

虽然不同协议都对各自的协议格式做了不同定义,但总体而言还是有高低电平组成的一串数据。
对于红外发射,就是按照协议规定高电平时间内,在红外输出口输出固定频率载波;低电平则直接输出低。红外接收头接到载波时输出高电平,没有载波时输出低电平,完成数据解码。

nec_encode.png

图7:NEC解码后协议

三、接收

红外接收常采用一体化红外接收头,集红外接收、放大、滤波、比较器输出等功能,并输出MCU可识别的TTL信号的。常用的一体化红外接收头有SCR638、HS0038、VS1838等。

SCR638.png

SCR638

HS0038.png

HS0038

图8:一体化接收头

红外接收应用电路图:

application.png

图9:红外接收典型应用

四、T2-U开发板硬件连接

这次使用的是T2-U2开发板配套红外遥控功能板,实现设备红外接收与发送功能。
红外遥控功能板介绍:
https://developer.tuya.com/cn/docs/iot/tuya-sandwich-infrared-remote-control-board?id=K97o1wfxi7v9l

ir_function.png

红外遥控功能板

将遥控接收 study 管脚连接到T2开发板GPIO8,连接3.3V电源。
如需要红外发射功能将CRTL管脚连接到T2开发板GPIO7,同时连接5V电源。

五、TuyaOS红外功能介绍

TuyaOS红外接收目前支持NEC码、红外学习时间码(可用于万能红外遥控器)、红外发送功能。

TuyaOS红外接收采用中断+硬件定时器方式,可使用所有支持外部中断的GPIO,无 GPIO 管脚限制,给产品设计带来很大的便利。

红外接收功能:

  1. 支持查询模式和中断模式,可应用与不同的场景;如查询模式目前多用于万能红外遥控器学习状态,中断模式多用于设备红外控制。

  2. 支持NEC解码,支持高位之前/低位在前,引导码最大误差率 , 高电平最大误差率, 低电平最大误差率重复码最大误差率 设置

  3. 支持按下、松开通知,在中断模式下,可在回调中通过 s_frame_finish 获取,
    is_frame_finish 为 1 表示这帧数据接收完成,处于松开状态,为 0 表示这帧数据可能还没有结束还在接收中。

  4. 支持长按、短按通知,在中断模式下,可在回调函数中通过recv_data中断的repeat_cnt判断当前遥控器重复发送次数。
    中断模式下回调函数通过 tdl_ir_config(ir_handle, IR_CMD_RECV_CB_REGISTER, app_ir_recv_cb); 注册。

T2开发板上已经提供 tuyaos_ir_driver_demo_quickstart 工程可以快速实现红外接收与发送。红外接收目前支持 NEC 码、红外学习时间码(可用于万能红外遥控器)。tuyaos_ir_driver_demo_quickstart 可通过 wind_ide 或者 github 仓库先下载。

六、红外功能代码使用流程

初始流程为:硬件注册->查找设备->打开设备->操作设备(红外发送,介绍)

1. 硬件注册

选择驱动方式,支持下列三种驱动方式:

  • 单硬件定时器驱动

  • 双硬件定时器驱动

  • PWM 捕获驱动

捕获方式驱动不一定所有硬件都支持,其中除单硬件定时器驱动方式外,其他两种驱动方式都支持自发自收,这里选择的定时器必须是微妙级(us)的定时器。发送引脚应支持 38KHz 的 PWM 输出。

硬件注册示例代码如下:

Code: Select all

char dev_name[] = {"IR_DEVICE"};

    IR_DRV_CFG_T ir_hw_cfg = {
        .send_pin = GPIO_NUM_7,
        .recv_pin = GPIO_NUM_8,
        .send_timer = TIMER_NUM_0,
        .recv_timer = TIMER_NUM_0,
        .send_duty = 50,
    };

    TUYA_CALL_ERR_RETURN(tdd_ir_driver_register(IR_DEV_NAME, IR_DRV_SINGLE_TIMER, ir_hw_cfg)); 

2. 设备查找

根据设备名称,获取设备操作句柄。示例代码如下:

Code: Select all

IR_HANDLE_T ir_handle;

op_ret = tdl_ir_dev_find(dev_name, &ir_handle);
if (OPRT_OK != op_ret) {
    PR_NOTICE("tdl_ir_dev_find error:%d", op_ret);
    goto __EXIT;
}

3. 打开设备

这里可以通过配置,通过不同的协议方式开启设备,目前支持下列两种方式:

  • 时间码类型
  • NEC 协议类型

配置红外设备模式,支持以下三种模式配置:

  • 仅发送
  • 仅接收
  • 发送接收同时支持

时间码类型(timecode),是将红外码值按照发送时的高低电平时间进行发送和接收的。示例代码如下:

Code: Select all

ir_cfg.ir_mode = IR_MODE_SEND_RECV;  // 红外设备模式
ir_cfg.recv_queue_num = 3;    // 最多接收缓存红外数据条数
ir_cfg.recv_buf_size = 1024; // 单条红外码值最大支持空间大小
ir_cfg.recv_timeout = 1000; // 接收超时时间

ir_cfg.prot_opt = IR_PROT_TIMECODE;  // 时间码协议类型

op_ret = tdl_ir_dev_open(ir_handle, &ir_cfg);
if (OPRT_OK != op_ret) {
    PR_ERR("open failed, %d", op_ret);
    goto __EXIT;
}

NEC 协议初始化示例代码:

Code: Select all

ir_cfg.ir_mode = IR_MODE_SEND_RECV;
ir_cfg.recv_queue_num = 3;
ir_cfg.recv_buf_size = 1024;
ir_cfg.recv_timeout = 1000;

ir_cfg.prot_opt = IR_PROT_NEC; // NEC 协议类型

ir_cfg.prot_cfg.nec_cfg.is_nec_msb = 0,
ir_cfg.prot_cfg.nec_cfg.lead_err = 70; // 引导码最大误差率
ir_cfg.prot_cfg.nec_cfg.logics_err = 50; // 逻辑 0/1 高电平最大误差率
ir_cfg.prot_cfg.nec_cfg.logic0_err = 45; // 逻辑 0 低电平最大误差率
ir_cfg.prot_cfg.nec_cfg.logic1_err = 70; // 逻辑 1 低电平最大误差率
ir_cfg.prot_cfg.nec_cfg.repeat_err = 50; // 重复码最大误差率

op_ret = tdl_ir_dev_open(ir_handle, &ir_cfg);
if (OPRT_OK != op_ret) {
    PR_ERR("open failed, %d", op_ret);
    goto __EXIT;
}

4. 红外发送

这里需要注意的是,红外发送采用的是阻塞的方式,因为发送时使用数据是发送传入的数据的空间,所以必须等红外码值发送完成后才会执行后面的程序。

这里的发送是和 tdl_ir_dev_open 时设备的协议有关的, ir_cfg.prot_opt = IR_PROT_TIMECODE 时红外发送示例如下:

Code: Select all

UINT32_T data[] = {560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 1690, 1690};
ir_send_data.timecode.data = data;
ir_send_data.timecode.len = strlen(data);

op_ret = tdl_ir_dev_send(ir_handle, 38000, ir_send_data, 1);
if (OPRT_OK != op_ret) {
    PR_ERR("ir send error, %d", op_ret);
}
PR_DEBUG("ir send start");

 ir_cfg.prot_opt = IR_PROT_NEC 时红外发送示例如下:

Code: Select all

ir_send_data.nec_data.addr = 0x807F;
ir_send_data.nec_data.cmd = 0x1DE2;
ir_send_data.nec_data.repeat_cnt = 1;

op_ret = tdl_ir_dev_send(ir_handle, 38000, ir_send_data, 1);
if (OPRT_OK != op_ret) {
    PR_ERR("ir send error, %d", op_ret);
}
PR_DEBUG("ir send start");

5. 红外接收

红外接收默认也是阻塞的方式,但也支持通过回调的方式进行操作。如果选择的是 IR_PROT_TIMECODE 协议方式,那接收的数据将直接是解码后的数据。红外接收示例如下:

Code: Select all

op_ret = tdl_ir_dev_recv(ir_handle, &ir_recv_data, 3000);
if (OPRT_OK == op_ret) {
#if USE_NEC_DEMO
    PR_DEBUG("demo addr:%04x, cmd:%04x, cnt:%d", ir_recv_data->nec_data.addr, ir_recv_data->nec_data.cmd, ir_recv_data->nec_data.repeat_cnt);
#else
    PR_DEBUG("demo addr:%p, len:%d", ir_recv_data, ir_recv_data->timecode.len);
    for (i=0; i<ir_recv_data->timecode.len; i++) {
        PR_DEBUG_RAW("%d ", ir_recv_data->timecode.data[i]);
    }
    PR_DEBUG_RAW("\r\n");
#endif
    tdl_ir_dev_recv_release(ir_handle, ir_recv_data);
}

6. 接收回调注册

硬件注册->查找设备->打开设备 之后就可以注册接收回调后,红外接收到数据会立马通过注册的回调函数通知应用,无法再使用 tdl_ir_dev_recv() 获取数据。

在接收到有效数据后回调函数会传出两个参数 is_frame_finishrecv_datais_frame_finish 为 1 表示这帧数据接收完成,为 0 表示这帧数据可能还没有结束还在接收中;recv_data 表示接收的数据。回调函数类型如下:

Code: Select all

typedef void (*IR_APP_RECV_CB)(UINT8_T is_frame_finish, IR_DATA_U *recv_data);

这里的数据类型也是根据您初始化的时候选择的协议格式进行配置。比如:在初始化时您配置红外协议为 NEC 编码格式的话,那么红外接收到数据后会将接收到的红外码转换成 NEC 格式之后再通过回调函数将数据传出。

使用示例如下:

Code: Select all

void app_ir_recv_cb(UINT8_T is_frame_finish, IR_DATA_U *recv_data)
{
    TAL_PR_NOTICE("is_finish: %d, addr: 0x%04x, cmd: 0x%04x, repeat: %d", \
                    is_frame_finish, recv_data->nec_data.addr, recv_data->nec_data.cmd, recv_data->nec_data.repeat_cnt);
}

tdl_ir_config(ir_handle, IR_CMD_RECV_CB_REGISTER, app_ir_recv_cb);

日志如下:

Code: Select all

[01-01 00:00:29 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 0
[01-01 00:00:29 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 1
[01-01 00:00:29 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 2
[01-01 00:00:29 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 3
[01-01 00:00:30 ty N][app_main.c:43] is_finish: 1, addr: 0x807f, cmd: 0x0cf3, repeat: 3
[01-01 00:00:31 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 0
[01-01 00:00:31 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 1
[01-01 00:00:31 ty N][app_main.c:43] is_finish: 1, addr: 0x807f, cmd: 0x0cf3, repeat: 1
[01-01 00:00:33 ty N][app_main.c:43] is_finish: 0, addr: 0x807f, cmd: 0x0cf3, repeat: 0
[01-01 00:00:33 ty N][app_main.c:43] is_finish: 1, addr: 0x807f, cmd: 0x0cf3, repeat: 0

在应用上可以通过 repeat_cnt 去判断红外按键是按下,长按或释放等动作。