一、简介
随着科技进步,手机逐渐融入了我们的生活。通过在手机中内置红外发射器,手机可以模拟各种遥控器的操作,实现对不同家电设备的控制。在电视精灵的Android版本中,也支持了红外遥控器功能,实现对移动高清机顶盒的遥控操作,提升了用户手机控制大屏的体验。红外遥控器的具体样式,如下图1所示,基本涵盖了用户日常操作指令。
红外遥控是一种古老而实用的技术,它是利用红外线的特性来传递信息。红外线是一种不可见光,具有较强的穿透力和方向性。在红外遥控中,发射器会将控制指令编码成特定的红外信号,并通过发射二极管将其发射出去。当这些红外信号到达接收设备时,接收设备中的红外接收器会将其接收并解码,从而执行相应的操作。接下来,本文将详细介绍一下红外系统的实现原理,并以电视精灵红外遥控为例,介绍如何在Android系统上开发红外遥控功能。
二、红外遥控原理
2.1 红外系统
红外遥控系统通常由红外发射器和红外接收器组成。红外发射器将控制信号转换为红外光信号发射出去,而红外接收器则接收这些红外光信号,并将其转换回电信号,从而实现对设备的控制。红外遥控系统发送和接收的主要组成部分,如下图所示。
发送端:
指令输入:用户通过遥控器上的按键输入控制指令。
编码:将指令编码为红外信号格式。
调制:使用特定的调制方式,将编码后的信号与载波进行调制。
红外发射:通过红外发射二极管将调制后的红外信号发射出去。
接收端:
红外接收:红外接收二极管接收红外信号。
解调:对接收的信号进行解调,还原出编码信息。
解码:将解码后的信息转换为具体的控制指令。
指令执行:根据接收到的控制指令,执行相应的操作,如控制家电设备的开关、调节等。
2.2 红外编码
红外遥控器发射的信号由一串“0”和“1”的二进制代码组成,不同的芯片对“0”和“1”的编码有所不同,通常有曼彻斯特 (Manchester) 编码和脉冲宽度编码 (PWM)。
2.2.1 曼彻斯特编码(Manchester Encoding)
原理:曼彻斯特编码是一种双相编码,通过电平的高低转换来表示“0”或“1”。每位中间的电平转换既表示了数据代码,也作为定时信号使用。
-
特点:
每位数据都有一个电平跳变,位中间的跳变既作时钟信号,又作数据信号。
数据传输速率是调制速率的1/2,因为每个码元都被调制成两个电平。
编码效率约为50%,因为每个时钟位都必须有一次变化。
2.2.2 脉冲宽度编码(PWM, Pulse Width Modulation)
原理:脉冲宽度编码以发射红外载波的占空比代表“0”和“1”。一般通过固定发射红外载波的时间,通过改变不发射载波的时间来改变占空比。
-
特点:
节省能量,因为发射红外载波的时间固定。
解码方便,通常包含引导码以辅助解码。
不同芯片或制造商的PWM编码可能有所不同。
2.2.3 脉冲宽度编码举例
家用电器使用的红外遥控器绝大部分都是脉冲宽度编码,例如常用的电视遥控器使用NEC upd6121芯片,其“0”为载波发射0.56ms,不发射0.56ms;其“1”为载波发射0.56ms,不发射1.68ms。如下图所示:
2.3 红外调制
在红外通信中,将编码后的二进制信号调制成特定频率(如38kHz)的间断脉冲串是一个常见的做法。这种调制方式通常被称为脉冲调制或载波调制。在这个过程中,原始的二进制信号(由“0”和“1”组成)被用来控制一个高频载波信号(如38kHz的脉冲信号)的开关状态。
具体实现时,二进制信号中的“1”和“0”,分别由不同38kHz载波和低电平组成。如“0”为由 0.56ms 的 38kHz 载波和 0.56ms 的无载波低电平组合而成;“1”由 0.56ms 的 38kHz 载波和 1.69ms 的无载波低电平组合而成。这样,原始的二进制信号就被转换成了一个间断的脉冲串,其中每个脉冲都对应于原始信号中的一个位。
如下图所示,以下是一个简化的描述,说明如何使用高低电平来控制红外信号的调制:
原始二进制信号:例如,我们有二进制信号“0010”。
载波频率:选择38kHz作为载波频率。
-
调制过程:
当二进制信号为“1”时,生成一个由0.56ms 的 38kHz 载波和 1.69ms 的无载波低电平脉冲
当二进制信号为“0”时,生成一个由0.56ms 的 38kHz 载波和 0.56ms 的无载波低电平脉冲。
2.4 红外解调
解调是调制的逆过程,是通过红外接收管进行接收的。其基本工作过程为:当接收到调制信号时,输出高电平,否则输出为低电平。
2.5 红外解码
解码是将解调输出的脉冲,还原为二进制的“0”和“1”,得到二进制的“0”,“1”序列,进而通过编码协议分析传输内容所含的用户码和数据码。
三、开发实践
3.1 Android红外开发
截止目前,iphone手机内部没有配置红外发射硬件,因此在iphone手机上是不支持红外指令发射的。文中后续的开发介绍,以Android系统为基础。
3.1.1 权限申请
在App工程的AndroidManifest.xml中补充红外权限配置。
<!--红外遥控-->
<uses-permission android:name="android.permission.TRANSMIT_IR" />
<!-- 是否仅在支持红外的设备上运行 -->
<uses-feature android:name="android.hardware.ConsumerIrManager" android:required="false" />
3.1.2 API调用
红外遥控功能从Android4.4之后才开始支持,对应的管理类名叫ConsumerIrManager,常用的三个方法分别是:
- 检测设备是否支持红外发射器
/**
* 返回true表示支持红外发射,返回false表示不支持红外发射
*/
public boolean hasIrEmitter()
- 获得红外发射器可用的载波频率范围
/**
* 返回CarrierFrequencyRange类型数组,表示红外发射器可用的载波频率范围
*/
public CarrierFrequencyRange[] getCarrierFrequencies()
- 发射红外信号
/**
* @param carrierFrequency 信号频率,单位赫兹(Hz),家用电器的红外频率通常使用38000Hz
* @param pattern 整型数组形式的信号格式
*/
public void transmit(int carrierFrequency, int[] pattern)
3.1.3 码值编码
红外编码由“引导码 + 用户编码(高八位)+ 用户编码(低八位)+ 键数据码 + 键数据反码 + 结束码”组成,然后按照一定的编码规则,合成数组的形式。以NEC6122协议举例,引导码固定为(9000 + 4500),结束码固定为(560,20000)。不同遥控器差别主要在于用户码和数据码,同一个遥控器的用户码是一样的,不同按键有不同的码值,码值可以转换出对应的数据码和数据反码。
上述表格中列了NEC协议的几个指令,下面以按键数字2进行举例。
数字按键2的十六进制表示:
用户码:0x08E6
码值:0x41
转换为二进制:
-
用户码
高八位:00001000(表示08)
低八位:11100110(表示E6)
-
数据码
原码:01000001(表示41)
反码:10111110(41的反码)
由于手机与遥控器的信号编码有区别,需要逆序编码。
逆序编码:
-
用户码
高八位: 00010000
低八位: 01100111
-
数据码
原码:10000010
反码:01111101
编码转换完成,通过transmit方法进行发送。但是参数要传递整型数组形式的信号,并不是二进制数而是电平信号数据。电平是电路中某一点电压的高低状态,在数字电路中常用高电平表示“1”,用低电平表示“0”。根据上文可以看出,遥控器发射红外信号之时,通过“560us高电平+1690us低电平”代表“1”,通过“560us高电平+565us低电平”代表“0”。于是编写Android代码的时候,使用“560,1690”表示二进制的1,使用“560,565”表示二进制的0,具体数组值如下所示:
int[] patternForKey2 = {9000,4500, // 开头两个数字表示引导码
// 下面两行表示用户码: 00010000 01100111
560,565, 560,565, 560,565, 560,1690, 560,565, 560,565, 560,565, 560,565,560,565, 560,1690, 560,1690, 560,565, 560,565, 560,1690, 560,1690, 560,1690,
// 下面一行表示数据码:10000010
560,1690, 560,565, 560,565, 560,565, 560,565, 560,565, 560,1690, 560,565,
// 下面一行表示数据反码:01111101
560,565, 560,1690, 560,1690, 560,1690, 560,1690, 560,1690, 560,565, 560,1690,
560,20000}; // 末尾两个数字表示结束码
3.1.4 指令发送
当我们做好指令和数组值的映射,并选定信号频率。在需要发射红外信号处调用如下:
/**
* 按下按键发射红外信号
*/
public void transmit() {
ConsumerIrManagerApi.transmit(38000, patternForKey2);
}
3.2 电视精灵红外遥控实现
红外遥控功能,已经在电视精灵的Android版本中落地。为了保证用户体验和功能的有效性,在开发过程中,我们考虑并解决了以下两个问题:
电视精灵需要控制多种不同款的机顶盒,不同类型机顶盒,可能支持的红外码是不一样的。
用户快速点击多个指令,如何确保指令不丢失?
针对如上两个问题,对应解决方案分别是:
根据绑定设备类型,动态获取红外码值。
提供指令队列,防止指令丢失。
3.2.1 红外码值动态获取
红外遥控为了兼容不同设备,采用了红外码值动态下发的方式。主要流程如下图所示:
应用启动判断当前是否绑定设备,并发起红外配置获取请求,如果有设备则带上设备相关信息。
红外配置获取成功,则使用云端配置信息初始化红外遥控。
红外配置获取失败,则使用本地兜底数据初始化红外遥控。
3.2.2 指令队列控制
当用户快速点击红外遥控时,可能会导致部分指令丢失。为了确保每个指令在手机端都能得到处理,我们基于线程池框架,实现红外操作指令的控制队列,具体实现如下所示。
- 定义发码线程池
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
- 单线程发码保证先后顺序,确保每次只有一个指令在执行
/**
* 发射红外信号
* @param carrierFrequency 红外频率
* @param pattern 红外码
*/
public void transmit(int carrierFrequency, int[] pattern) {
executorService.submit(new Runnable() {
@Override
public void run() {
if(consumerIrManager != null){
consumerIrManager.transmit(carrierFrequency, pattern);
}
}
});
}
四、总结
红外遥控是一项非常实用的技术,它让我们能够轻松地操控各种家电设备。红外遥控具有操作简单、成本相对较低等优点,在家庭和日常生活中得到了广泛应用。但它也存在一些不足之处,比如信号容易被阻挡、对角度有一定要求,且不同设备之间可能存在兼容性问题。尽管如此,红外遥控依然是我们生活中不可或缺的一部分,它为我们带来了便利,也见证了科技的发展与进步。