树莓派3b——红外篇

前言

树莓派自身已经包含了接收/发射红外的库,名为lirc,通过修改/boot/config.txt文件可以启用此特性(修改完后记得重启):

dtoverlay=lirc-rpi

默认情况下,lirc使用12引脚作为红外接收引脚,可以将此引脚直接和红外接收管进行连接来接收红外信号;使用11脚作为红外发射脚,此引脚可以直接和led红外发射管连接,从而发射38khz的红外信号。当然,直接连红外发射管的话,功率可能小些,可以使用一个三极管对信号进行简单的放大,从而提高发射功率和发射举例。

网上的教程大都是教你怎么使用lircd这个程序(注意,这是一个守护进程,可以使用apt-get install lirc来安装,具体使用方法参考百度)来接收红外遥控的信号,然后控制树莓派的。好一点的教程会教你如何录制空调遥控信号(空调遥控和电视遥控有本质的不同,相对更复杂些),然后通过发射管来发送红外信号控制空调的。

但是对于我来说,这远远不够。我希望能编程接收遥控器的指令,也能编程发射红外信号(本人之前用单片机实现了此功能,现在想把此功能移植到树莓派上,WTF)。就这个功能,居然没有人做过!!!!!!!

所以,本篇文章将会介绍如何通过程序(JAVA,没错,就是万能的JAVA)直接读取lirc驱动返回的红外数据,亦或直接通过lirc驱动发送38khz的红外新号。

启用lirc驱动

当我们在config.txt中启用了lirc之后,可以看到多出了/dev/lirc0这个文件。我们的所有功能都是基于这个设备文件实现的。

连接电路。。。。。。(这里省略一万字)

读取lirc数据

我们可以使用一个电视遥控器对着红外接收头按下,然后编程直接读取此文件(可以使用InputFileStream直接读取)的内容,可以看到返回了一堆byte数组,它的格式是这样的:

byte1,byte2,byte3,byte4
byte5,byte6,byte7,byte8

返回的数据,每四个分为一组:

byte1:不知道啥玩意,忽略不计
byte2,byte3:组成一个整形数,表示当前矩形波的宽度,计算方式为byte2 * 0xFF + byte3
byte4:表示此条数据是pulse(占空比中的占)还是space(占空比中的空),1表示pulse,0表示space

所以我们只需要把读取的byte数组每四个分成一组,然后按照如上协议解析数据,即可得到红外遥控器(无论是电视还是空调遥控器)的发射波形,波形的解析可以参考各个遥控器的协议。当然我们也可以直接将这些数据保存,用于后续红外的发射使用。

使用lirc发射38khz红外信号

lirc驱动不仅可以接收红外信号,也可以发射红外信号,我们只需要直接写入/dev/lirc0这个设备文件(可以使用OutputFileStream)即可。
要注意的是,发射的数据要保证其元素个数为奇数(因为红外发射时都是先发射一个pulse(占),然后跟一个space(空),最后的结尾也必须是一个占(pulse),所以元素个数必须为奇数)。这里假设我们要发射[1000,1000,1000]这组数据,它的波形图如下:
树莓派3b——红外篇_第1张图片
写入的协议如下:

byte1,byte2,byte3,byte4
byte5,byte6,byte7,byte8
byte9,byte10,byte11,byte12

每个整数拆分为4个byte,也就是1000=byte1 *0xFF000000 + byte2*0xFF0000 + byte3*0xFF00 + byte4 ,而且第一个整数对应第一个占,最后一个整数也对应占。

至此,通过lirc驱动直接进行红外信号的接收和发射就介绍完了。

实际操作时会遇到的问题

在linux下(实际windows也这样),每个文件被打开后,都会有一个句柄,我们使用这个句柄可以对文件进行读或写操作,亦或同时读写。但在java里,每个文件被打开为OutputFileStream和InoutFileStream时,都会被open一次,也就是我们同时对lirc进行读和写时,lirc驱动会被打开两次,而lirc驱动内部又对此进行了限制,所以当我们打开第二个流时,就被报设备忙碌的异常(手动滑稽)。。。。
为了解决这个问题,我尝试过改写lirc驱动的源码,从而关闭此项限制,但最终也未成功。后来我想到使用linux的c语言函数可以实现打开文件,然后同时读或写,才解决了此问题。此方案的伪代码如下(linux的c语言函数需用jna进行调用):

int  filehandler = open ("/dev/lir00",O_RDWR | O_NOCTTY);
int realcount = read(fileHandler, byte[],bytes.length);//读操作
write(fileHandler, byte[],bytes.length);//写操作

另外,lirc驱动不仅可以发送38khz方波,也可以发送普通的方波(即0hz的方波),例如我们需要通过315Mhz模块发送数据,就可以利用lirc的此特性。不过此功能需要重新编译lirc驱动,而且需要使用ioctl函数对lirc进行控制,我会另写篇文章来介绍。

你可能感兴趣的:(树莓派3b)