本文适用于在没有红外发射器的手机上,利用音频接口连接相关发射器进行信号发射。效果展示:http://t.cn/RLhOuCf
2016年2月28日更新:
使用音频还是要给手机插音频线,所以具有相当大的局限性。而且在开发过程中还不容易采样,容易受各种因素干扰。用声波模拟脉冲信号也具有一定难度。最近在玩Arduino,发现这个开发板很适合用来做采样和发射。
通过Arduino录制红外与播放红外信号的相关信息写在了这篇博文中:
http://blog.csdn.net/luhanglei/article/details/50762325
2016年06月07日更新
关于“正弦波”的作用:
通过在Arduino上实验就能知道,传感器接收红外信号的时候,并不是只要红外发光二极管亮起就是1,灭掉就是0。
红外接收器其实只接收频率为38KHz的信号(不是光的频率,就是通断电而闪烁的频率),因此当需要输出为1的信号的时候,发出的实际是一个20KHz(因为其实20KHz也可以被接收到)的信号,而不是常亮。
硬件:
作者的手机型号是nexus4,使用直接连接红外发射管(直接无反应)和DIY使用三极管,进行信号放大的方式(光太暗),均告失败。。。
在制作硬件的过程中,可以使用①用手机摄像头观察和②暂时用可见光发光二极管替代的方法查看效果。
最终解决方法:jd买了一个usb小音响(19RMB左右),把喇叭全都拆掉,将红外二极管串联相应大小的电阻(电阻大小多少合适,有公式请百度),焊接到原来喇叭的位置上。
效果图:
原理:手机输出的音频信号太弱,势必要进行放大才够我们使用,三极管放大的效果还是太弱。这时候小音箱就成了救命稻草了。。。它很便宜,关键是有着很成熟的音频信号放大电路!
以上内容完成以后可以使用现有的遥控类软件进行测试。
软件:
①首先查找要目标设备的遥控器编码文档。
②现在网上已经可以下到很多可以让手机当遥控器的软件了,他们不开源,但是可以获取他们输出的信号参考一下。
(下图是用一根两端都是公头的音频线,一端连接手机,另一端连接电脑麦克口,使用录音软件,用44100采样率录下来的,再用cooledit打开分析的。线也可以在jd买到,不到10块)
根据我空调的文档,前面9000μs高电平+4500μs低电平是起始码,后面的01都是高低电平组合,一高一低为一位,低电平短的是0,长的是1。放大以后可以看到,生成的是很漂亮的正弦波。
③自己根据需要生成带有高低电平的声波。
根据网上搜索到的正弦波生成算法,作者仿造了上面的正弦波,但发现再次用电脑声卡捕获以后,高电平全体在低电平一侧,而且低电平的坐标出现很大的偏移。
图中内容为低电平出现偏移,一开始认为是在播放一开始就发声会导致偏移,图中已经采取相关措施,看来这个猜想不正确。即使文件开始很久之后才开始发声,还是会偏移。
后来经过多次测试,发现问题出在“低电平”的处理上。在使用8bit pcm编码的情况下,一直认为正弦波与横轴交点的纵坐标意味着0,上为正,下为负,于是作者简单的将低电平置为了0x00,后来发现问题就出在这里。正弦波的与横轴的焦点,是整个宽度的中间值,而不是一个负值。
生成高低电平波代码如下(HEIGHT为振幅):
/**
* @param waveLen 周期,每个周期占用多少次采样率
* @param length 长度,单位同样是占用了多少次采样率。例如采样率为44100,需要1秒长,则length值为44100/waveLen
* @return
*/
public static byte[] getHigh(int waveLen, int length) {
byte[] wave = new byte[length];
for (int i = 0; i < length; i++) {
wave[i] = (byte) (HEIGHT * (1 - Math.sin(2 * Math.PI
* ((i % waveLen) * 1.00 / waveLen))));
}
return wave;
}
public static byte[] getLow(int waveLen, int length) {
byte[] wave = new byte[length];
for (int i = 0; i < length; i++) {
wave[i] = (byte) (HEIGHT);
}
return wave;
}
private byte[] get0() {
int highLength = (int) Math.round(sampleRate / 1000000.0 * HIGHTIME / WAVELEN) * WAVELEN;//采样率/1000000.0*高电平时间=高电平占用的采样次数,先除后乘是想得到一个整数倍的周期,具体有没有益处未证实
byte[] high = getHigh(WAVELEN, highLength);
int lowLength = (int) Math.round(sampleRate / 1000000.0 * LOWTIMEOF0 / WAVELEN) * WAVELEN;
byte[] low = getLow(WAVELEN, lowLength);
byte[] res = new byte[highLength + lowLength];
System.arraycopy(high, 0, res, 0, high.length);
System.arraycopy(low, 0, res, high.length, low.length);
return res;
}
private byte[] get1() {
int highLength = (int) Math.round(sampleRate / 1000000.0 * HIGHTIME / WAVELEN) * WAVELEN;
byte[] high = getHigh(WAVELEN, highLength);
int lowLength = (int) Math.round(sampleRate / 1000000.0 * LOWTIMEOF1 / WAVELEN) * WAVELEN;
byte[] low = getLow(WAVELEN, lowLength);
byte[] res = new byte[highLength + lowLength];
System.arraycopy(high, 0, res, 0, high.length);
System.arraycopy(low, 0, res, high.length, low.length);
return res;
}
将生成好的数据按照编码格式拼接起来,连接到发射器播放,即可控制空调等设备。
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT, wave.length, AudioTrack.MODE_STATIC);
if (audioTrack != null) {
audioTrack.write(wave, 0, wave.length);
audioTrack.play();
}
建议在开发过程中遇到问题的时候多抓取音频分析,发现问题所在。
如果出现开头丢失的问题,可以在数据之前加入一定的中低电平和低电平信号,来当炮灰。
感谢
http://blog.csdn.net/kangear/article/details/39376105
http://m.blog.csdn.net/blog/caoshichao520326/8646913