开学初,听到某同学在台湾留学时候,成功使用Android手机通过bluetooth设备控制Arduino单片机来实现对宿舍空调的遥控。当时就觉得蛮有趣的,但是他的Android手机程序是通过Appinventor写的,我就想是否自己能够通过Eclipse来重新实现这一过程,也就是用Android手机通过Bluetooth控制Arduino单片机来遥控空调。但是宿舍空调离我的实验室比较远,所以先用Nikon D3300来试试手。
今天先讲Arduino遥控nikon d3300的心酸历程。
废话不多讲,接下来我们进入正题。首先我们来看一下总的思路
相信上图显示的流程大家都不难理解。接下来就是各个部分的详细情况。
首先我们知道,要通过Arduino来遥控红外设备,就得知道Arduino单片机需要传送给红外发射二极管什么码型或者什么波形。我参考了《Arduino互动设计入门》以及网上各大Arduino资料,基本上都是使用IRremote这个开源的库来读取码型。IRremote库下载地址:点击打开链接。
当然,我也会去尝试。将1838一体化红外接收头连接好Arduino单片机(1838的VCC、GND和信号脚分别接Arduino的VCC、GND和11脚),Arduino单片机通过串口连接电脑,电脑打开Arduino,并打开IRrecvDump这一例程,选择好Arduino单片机型号和串口(我的是Arduino MEGA 2560),并打开Serial Monitor,如图。
用nikon自带遥控器对着1838按一下,就可以在Serial Monitor读到如图的Raw码。
首先我是不知道这些Raw码是什么意思,先留着。各种参考资料说就获得的Raw做以下操作:
1、去掉第一个数字;2、全部数字取绝对值;3、将空格改为逗号(英文状态)。并存储为以下数组,比如
unsigned int test[]={550,1350,550,3350,500}。
为什么要这么操作,一开始我也是不知道。后面通过查看下载的IRremote库的IRremot.h和IRremote.cpp代码终于明白了,下文会提及到。
将上图的电路连接好了之后(红外发送二极管接330欧姆电阻接Arduino的PWM脚,即3号脚),通过Arduino编写如下代码发送刚刚获取的Raw码。
unsigned int test[]={550,1350,550,3250,500}; irsend.sendRaw(test,5,38); delay(100); irsend.sendRaw(test,5,38);
其实我也不知道两次码型传输之间的间隔是多少,所以就试了100ms(这并不重要)。
照理来说,这时候应该是可行了吧。
但是但是,冥冥注定,这篇文照会有所不同,所以我还未能通过Arduino来操控nikon d3300。
一开始很灰心,因为明明按照参考书来操作的,怎么就跟剧本发展不同呢。接下来就是本文的重点了。
我从实验室找来了一台示波器(型号:Agilent Technologies InfiniiViision DSO-X 3034A),来记录遥控器和Arduino发送的波形有什么区别。
上图为接收到的遥控器的波形。
上图为Arduino单片机通过test发送的Raw码接收到的波形。对比遥控器的波形,很明显我们可以看出,Arduino发送的波形少了前面一小段,那么只要我们增加前面的一小段信号,那么就可以用Arduino来遥控单反了。现在问题来了,前面一小段波形怎么添加呢?
通过查看IRremote.cpp里面的IRsendRaw函数,我们就可以知道IRsendRaw这个函数是做了什么事情。
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf[i]);
}
else {
mark(buf[i]);
}
}
space(0); // Just to be sure
}
void IRsend::mark(int time) {
// Sends an IR mark for the specified number of microseconds.
// The mark output is modulated at the PWM frequency.
TIMER_ENABLE_PWM; // Enable pin 3 PWM output
delayMicroseconds(time);
}
void IRsend::space(int time) {
// Sends an IR space for the specified number of microseconds.
// A space is no output, so the PWM output is disabled.
TIMER_DISABLE_PWM; // Disable pin 3 PWM output
delayMicroseconds(time);
}
来到这里,我们就可以比较清IRsendRaw这个函数就是用来改变PWM(3号脚)的高低值(0或1),test数组内的数字是用来延时的(单位:微秒),这也就是要讲读取到的数组内的数字全部取绝对值的原因。一旦我们读取出遥控器发送的信号波形的时间参数,再重新定义一个test2[]数组,让Arduino发送这个test2[数组,我们就可以让Arduino发送的波形和遥控器发送的波形一模一样,也就可以来遥控单反了。
通过测量遥控器发送波形的时间参数,我们重新定义了
unsigned int test1[]={2086,27038,556,1372,532,3384,516};
irsend.sendRaw2(test1,7,38);
delay(67);
irsend.sendRaw2(test1,7,38);
and
上左图为Arduino重新发送的波形,上右图是遥控器发送的波形。基本上信号(两段)是一样的(PS:两段信号之间的时间间隔影响不大)。到这里,我他喵的终于成功了。
细心的同学可能会发现我使用的是irsend.sendRaw2(test1,7,38)函数而非irsend.sendRaw(test1,7,38)函数。这是涉及到溢出问题,可参考http://www.geek-workshop.com/archiver/tid-9763.html。
这篇文章写得很好,我也是按照里面去IRremote.h和IRremote.cpp添加sendRaw2()和mark2()和space2()函数的。
接下来,我会更新如何使用Eclipse来编程Android连接Bluetooth模块的。