红外遥控是一种无线控制技术,它具有功耗小、成本低、易实现等诸多优点,因而被各种电子设备特别是家用电器广泛采用,像日常生活中的电视遥控器、空调遥控器等等基本都采用红外遥控技术。
不过遥控器并不都是红外遥控,也可能是射频遥控。红外遥控使用近红外光线(频率只有几万赫兹)作为遥控光源,而射频遥控使用超高频电磁波(频率高达几亿赫兹)作为信号载体。红外遥控器的顶部,有的镶嵌一个或多个小灯泡,有的是一小片黑色盖子,这个黑盖子对红外线来说可是透明的,只是人的肉眼看不穿它。射频遥控器的顶部,有的突出一根天线,有的啥都没有(其实发射器包在盖子里面)。红外遥控器带着灯泡就像一支手电筒,红外光照到哪里,哪里的电器才会接收响应,这决定了红外遥控的三个特性:
1、遥控器要对准电器才有反应。要是手电筒没照到这儿,那肯定是黑乎乎的;
2、遥控器不能距离电器太远,最好是五米之内。这也好理解,手电筒离得远了,照到物体上的光线都变暗了;
3、遥控器与电器之间不能有障碍物。你能想象手电筒发出来的灯光会穿透墙壁吗?
而射频遥控器正好与红外的特性相反,它采用超高频电磁波,所以信号是四散开的不具备方向性,并且射频信号的有效距离可以长达数十米,末了射频信号还能轻松穿透非金属的障碍物。红外遥控和射频遥控的不同特性决定了它们各自擅长的领域,红外遥控看似局限很多,其实正适用于家用电器,否则每个人隔着墙还能遥控邻居家的电器,这可怎么得了;射频遥控的强大抗干扰能力,更适用于一些专业的电子设备。因为红外遥控更贴近日常生活,所以人民大众购买的智能手机,自然配置的是红外遥控了(有的手机可能没装红外发射器)。
听起来装了红外发射器的手机,可以拿来当遥控器使用,还能一部手机遥控许多家电,这不是什么天方夜谭噢,接下来看看如何在App开发中运用红外遥控技术。
首先要在App工程的AndroidManifest.xml中补充红外权限配置,具体的配置例子见下:
其次在代码中初始化红外遥控的管理器,注意红外遥控功能从Android4.4之后才开始支持。红外遥控对应的管理类名叫ConsumerIrManager,它的常用方法主要有三个,分别说明如下:
hasIrEmitter : 检查设备是否拥有红外发射器。返回true表示有,返回false表示没有。
getCarrierFrequencies : 获得可用的载波频率范围。
transmit : 发射红外信号。第一个参数为信号频率,单位赫兹(Hz),家用电器的红外频率通常使用38000Hz;第二个参数为整型数组形式的信号格式。
下面是红外遥控管理器的初始化代码例子:
private ConsumerIrManager cim;
private void initInfrared() {
// 获取系统的红外遥控服务
cim = (ConsumerIrManager) getSystemService(Context.CONSUMER_IR_SERVICE);
if (!cim.hasIrEmitter()) {
tv_infrared.setText("当前手机不支持红外遥控");
}
}
最后准备发射遥控信号之时调用transmit方法就好了。
果真如此简单吗?当然不是,这里面的玄机全在transmit方法的信号格式参数上面。想一想,家电有很多种,每种家电又有好几个品牌,便是房间里的某个家电,遥控器上也有数排的按键。这么算下来,信号格式的各种组合都数不清了,普通开发者又不是电器厂商的内部人员,要想破解这些电器的红外信号编码,那可真是比登天还难。
手工破解固然不容易,却也并非没有办法,现在有一种红外遥控器的解码仪,可到淘宝上面购买。这个解码仪能够分析常见家电的红外遥控信号,下面两种除外:
1、空调遥控器,空调的控制比较复杂,光光温度就可能调节十几次,难以破解。
2、灯光遥控器,灯本身发光发热,同时也会散发大量红外线,势必对外部的红外信号造成严重干扰;所以灯只能采取射频遥控器。
红外解码仪是家电维修人员的必备仪器,常用于检测遥控器能否正常工作,开发者为了让手机实现遥控功能,也要利用解码仪捕捉每个按键对应的红外信号。接下来以扫地机器人的遥控解码为例,介绍如何通过解码仪获取对应的红外遥控指令。
先将扫地机器人的遥控器对准解码仪正面的红外接收窗口,按下遥控器上的clean键(开始扫地/停止扫地),此时解码仪的分析结果如下图所示:
从上图可见,clean键的红外信号由三部分组成,分别是用户码4055、数据码44、电路61212。其中用户码表示厂商代号,每个厂家都有自己的唯一代号;数据码表示按键的编号,不同的数据码代表不同的按键;电路格式表示红外信号的编码协议,每种协议都有专门的指令格式。比如说电路61212表示的是NEC6121协议,该协议的红外信号编码格式为:引导码+用户码+数据码+数据反码+结束码,其中引导码和结束码都是固定的,数据反码由数据码按位取反得来,真正变化的只有用户码和数据码。
然而解码仪获得的用户码和数据码并不能直接写在代码中,因为液晶屏上的编码其实是十六进制数,需要转换为二进制数才行。例如用户码4055,对应的二进制数为0100 0000 0101 0101;数据码44,对应的二进制数为0100 0100,按位取反得到数据反码的二进制数为1011 1011。
可是前述的transmit方法,参数要传递整型数组形式的信号,并不是二进制数,这意味着二进制数还得转换成整型数组。那么整型数组里面存放的到底是些什么数据呢?这就要从数字电路中的电平说起了。电平是“电压平台”的简称,指的是电路中某一点电压的高低状态,在数字电路中常用高电平表示“1”,用低电平表示“0”。遥控器发射红外信号之时,通过“560微秒低电平+1680微秒高电平”代表“1”,通过“560微秒低电平+560微秒低电平”代表“0”。于是编写Android代码的时候,使用“560,1680”表示二进制的1,使用“560,560”表示二进制的0,此处的560和1680只是大概的数值,也可使用580、600替换560,或者使用1600、1650替换1680。
根据数字电路的电平规则,用户码4055对应的二进制数为0100 0000 0101 0101,转换成电平信号就变成了“560,560, 560,1680, 560,560, 560,560, 560,560, 560,560, 560,560, 560,560, 560,560, 560,1680, 560,560, 560,1680, 560,560, 560,1680, 560,560, 560,1680, ”,数据码44及其数据反码的电平信号依此类推。再加上NEC协议固定的引导码“9000,4500”,以及结束码“560,20000”,即可得出前面clean键的红外信号整型数组,具体的数组数值如下所示:
int[] pattern = {9000,4500, // 开头两个数字表示引导码
// 下面两行表示用户码
560,560, 560,1680, 560,560, 560,560, 560,560, 560,560, 560,560, 560,560,
560,560, 560,1680, 560,560, 560,1680, 560,560, 560,1680, 560,560, 560,1680,
// 下面一行表示数据码
560,560, 560,1680, 560,560, 560,560, 560,560, 560,1680, 560,560, 560,560,
// 下面一行表示数据反码
560,1680, 560,560, 560,1680, 560,1680, 560,1680, 560,560, 560,1680, 560,1680,
560,20000}; // 末尾两个数字表示结束码
接着在App代码中代入上述的信号格式数组,即调用transmit方法传递格式参数,示例如下:
// 普通家电的红外发射频率一般为38KHz
cim.transmit(38000, pattern);
运行测试App,却发现不管让手机发送多少次的红外信号,扫地机器人都呆若木鸡,丝毫没有反应。这是咋回事?奥秘在于NEC协议只规定了大体上的编码规则,实际的遥控器信号在整体规则内略有调整。之前提到的解码仪,既是家电售后的检测仪器,也可作为App开发者的调试工具。拿起手机对准解码仪正面的接收窗口,点击按钮发送红外信号,解码仪同步显示分析后的信号数据,如下图所示:
由上图可知,此时手机发出的红外信号符合NEC6121协议,只不过用户码变成了02AA,数据码变成了22。把这两个码数翻译成二进制,则用户码02AA转为0000 0010 1010 1010,数据码22转为0010 0010。回头比较遥控器的解码数据,遥控器发出的用户码4055对应0100 0000 0101 0101,数据码44对应0100 0100。看起来手机与遥控器的信号区别,应当是每两个十六进制数先转为二进制数,然后倒过来排列,也就是所谓的逆序编码。
找到问题的症结便好办了,数学上有负负得正,编码则有逆逆得顺。既然4055逆序编码后变为02AA,那么02AA逆序编码后必为4055,于是再次构造用户码02AA以及数据码22的电平信号,更改后的红外信号数据如下所示:
int[] pattern = {9000,4500, // 开头两个数字表示引导码
// 下面两行表示用户码
560,560, 560,560, 560,560, 560,560, 560,560, 560,560, 560,1680, 560,560,
560,1680, 560,560, 560,1680, 560,560, 560,1680, 560,560, 560,1680, 560,560,
// 下面一行表示数据码
560,560, 560,560, 560,1680, 560,560, 560,560, 560,560, 560,1680, 560,560,
// 下面一行表示数据反码
560,1680, 560,1680, 560,560, 560,1680, 560,1680, 560,1680, 560,560, 560,1680,
560,20000}; // 末尾两个数字表示结束码
重新编译运行测试App,手机依旧对准解码仪,然后点击按钮发射红外信号,解码仪终于正常显示用户码4055、数据码44了。这时再将手机对准扫地机器人,点击发射按钮,机器人居然转动起来了耶。至此遥控器clean键的红外编码正式破解完成,其它按键乃至其它家电遥控器的红外信号编码,均可通过解码仪破译得到。
当然,以上的红外信号解析办法,仅限于编码规则广泛公开的NEC协议。对于其它格式未知的电路协议,只能借助于更专业的单片机来分析,话说开发者拿起电路板,一边做电工,一边做码农,其乐也融融。采用红外遥控的家电种类与品牌都很繁多,前人已经对它们做了不少的信号破译工作,这些已知的红外信号数据详见网址http://www.remotecentral.com/cgi-bin/codes/,里面包括各大国外家电品牌的信号编码,有兴趣的读者可参考。
点此查看Android开发笔记的完整目录
__________________________________________________________________________
本文现已同步发布到微信公众号“老欧说安卓”,打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。