概述
注意:本教程已更新为可与IRLib 2.x一起使用,与以前的版本有显着差异。
大多数消费电子设备,例如电视,电缆盒,DVD播放器和其他设备,都使用红外信号进行远程控制。每个制造商都有自己的协议来对数据进行编码,以使发送给一台设备的信号不会干扰另一台设备。在LadyAdashe的早期教程中,介绍了从远程读取IR信号并使用IR LED创建自己的IR信号的内部工作方式。 。她的教程为您提供了IR工作原理的幕后花絮,但是要想弄清楚项目中的所有技术细节都有些困难。
如果您像我一样,则不知道该怎么做。 NeoPixels可以工作,也不可以在I2C或SPI通信的内部工作,但是您不需要这样做,因为我们有相应的库。一个好的代码库会将您(应用程序程序员)与硬件细节和设备的内部运作隔离开来,并为您提供一个API,使您可以轻松使用硬件而无需了解或关注幕后情况。
在本教程中,我们将向您展示如何在基于Arduino的项目中使用IRLib接收,解码和发送IR信号。我们将向您展示如何在NeoPixel上更改颜色,如何使用IR遥控器控制伺服器以及如何从Arduino向电视或电缆盒发送信号。未来的教程将包括IR控制鼠标,物联网远程控制和控制机械臂。
关于IR库
IR信号由一系列称为“标记”的调制脉冲组成,这些脉冲由称为“空格”的间隔隔开。通常,每个信号的开头都有一个长标记和空格,用作标头。然后,通过改变标记和空格的时序,可以传输一系列比特。如果必须存储整个信号的精确时序,则需要使用最多100个16位整数的数组。为了比较接收到的数据以查看是否是您想要的数据,您同样需要存储大量数据。
幸运的是,信号是根据非常特定的协议发送的,您可以使用此协议接收时序数据并将其转换为最多32位的单个二进制数。 IR库将时序信息收集到缓冲区中,然后将其转换为单个32位值。然后,您可以轻松地将该值与所需的值进行比较。
类似地,如果您要发送IR信号,您需要做的就是将32位值传递给库并告诉它要使用哪种协议使用。它将值转换为带有适当标题,位编码和定时的标记和空格流。
IR库的金标准是“ LIRC”或Linux红外遥控器,可在http://网站上找到它。/www.lirc.org/。它由驱动程序和有关数百个各种远程控制的大型信息数据库组成。如果我们使用的是基于Linux的系统,那么绝对是正确的选择。我们将不在这里讨论该库,因为我们打算专注于基于Arduino的系统。
2009年8月,Ken Shirrff在他的博客上发布了“ IRremote”,并在GitHub上发布了该库。然后在2013年1月,我根据Ken的早期工作发布了IRLib。此修订版重新组织了代码,使使用C ++中的面向对象编程设计可以更轻松地添加新协议。
有关IRLib的详细信息,请参见我的博客,网址为:http://tech.cyborg5.com/irlib/。 。它包括一个详尽的用户手册,该手册也可以在该库的“ manuals”文件夹中找到。。在本教程中,我们将使用IRLib来帮助您入门。
2016年9月,我们发布了主要的重写IRLib的名称称为IRLib 2.0。它与原始IRLib不完全向后兼容。本教程已更新为使用IRLib 2.0。以前的IRLib 1.x将不再受支持。最近发布的IRLib 2.03增加了对32位SAMD 21处理器的支持,例如Arduino Zero,Adafruit Feather M0和即将推出的Circuit Playground Express中使用的处理器。
接收和解码IR
软件安装
IRLib库的安装如下:
访问GitHib上的IRLib2页面。
选择“下载ZIP”按钮,或简单地单击此链接直接下载。
下载完成后解压缩ZIP文件。
生成的文件夹应命名为“ IRLib2-master”,并将包含5个单独的文件夹。这是因为IRLib 2.x实际上是5个可一起使用的库的集合。有时在Windows中,您会得到一个中级文件夹,并且需要四处移动。
将所有五个文件夹与其他Arduino库一起复制到Arduino库文件夹中,通常在(主文件夹)/Documents/Arduino/Libraries文件夹。库不应该与Arduino应用程序本身一起安装。
如果当前正在运行Arduino IDE,请重新启动
此存储库由总共五个库组成,每个库它必须在您的arduino/libraries/文件夹中。因此,例如,应按以下方式安装它……
arduino/libraries/IRLib2
arduino/libraries/IRLibFreq
arduino/libraries/IRLibProtocols
arduino/libraries/IRLibRecv
arduino/libraries/IRLibRecvPCI
请勿将它们安装在这样的单个文件夹中……
arduino/libraries/IRLib2_master
IRLib2
IRLibFreq
IRLib协议
IRLibRecv
IRLibRecvPCI
这是一个教程,指导您正确安装Arduino库。
所需的硬件
IRLib在基于8位AVR的Arduino板上运行,例如Uno,Leonardo,Mega和Micro。它也可以在Arduino Yun的Leonardo部分上运行。我们最近增加了对Arduino Zero,Feather M0和Circuit Playground Express中使用的32位ARM SAMD 21处理器的支持。但是,我们不支持Arduino Due或其他类似Arduino的系统。不幸的是,目前它不能在Adafruit Trinket和Adafruit Gemma之类的ATtiny85基础系统上运行,但对它的支持在工作罐中,并且应在不久的将来以精简版本提供给那些平台。在撰写本文时,它尚未在Adafruit Trinket Pro上进行过测试,但是由于它与Uno基于相同的ATmega328处理器,因此应该可以正常工作。因此,您需要的第一件事是Arduino Uno或其他兼容板。
您将需要一个IR接收器。例如,右列显示在特色产品下的TSOP38238。该设备结合了一个红外敏感光电管,一个38 kHz带通滤波器和自动增益控制。它可以在多种电源电压下工作,包括3.3v和5v。它可以对接收到的IR信号进行解调,并在电源电压水平上为您提供一个清晰的开,关脉冲方波。这意味着它是将其输出直接馈送到Arduino的数字输入引脚的理想选择。
最后,您将需要一个IR遥控器,例如用于控制电视,电缆盒或DVD播放器的遥控器。我们所有的示例都将使用右侧所示的Adafruit迷你遥控器,但是,我们将向您展示如何检测自己的电视遥控器正在使用的协议,如果IRLib支持该协议,则可以使用它。
连接红外接收器非常简单。将左侧的引脚连接到Arduino上的任何数字输入引脚。在我们的示例中,我们将使用引脚2。将中心引脚接地,将右侧引脚连接至+ 5v。
请注意,该设备的带通滤波器已调至38 kHz,这是大多数协议的典型频率。但是,某些协议会使用从36 kHz一直到57 kHz的频率。但是,该滤波器不是非常特定,我们在使用38 kHz接收器接收36-40 kHz范围内的信号方面取得了成功。 Panasonic_Old协议使用56 kHz。 Adafruit出售的TSOP38238很难解码该频率。但是,尽管Radio Shack出售的接收器是38 kHz的设备,但我还是取得了不错的成绩。 Radio Shock没有列出部件号,但我们认为它是TSOP4438。令人遗憾的是,这可能不再是一个选择:-(
这些设备是由Vishay制造的,具有多种包装样式,频率和AGC方法。如果Adafruit设备不适用于您并且您需要56 kHz时,您可以参考以下指南。
Vishay的IR接收器选择指南(PDF格式)
有关接收器和原理图的更多信息有关使用多个接收器的信息,请参见IRLib手册第1.4.3节。
解码红外数据
加载以下草图,它是库示例文件夹中“转储”草图的略微修改版本。所有示例草图均位于文件夹“ IRLib2/examples”。
下载:文件
复制代码
#include “IRLibAll.h”
//Create a receiver object to listen on pin 2
IRrecvPCI myReceiver(2);
//Create a decoder object
IRdecode myDecoder;
void setup() {
Serial.begin(9600);
delay(2000); while (!Serial); //delay for Leonardo
myReceiver.enableIRIn(); // Start the receiver
Serial.println(F(“Ready to receive IR signals”));
}
void loop() {
//Continue looping until you get a complete signal received
if (myReceiver.getResults()) {
myDecoder.decode(); //Decode it
myDecoder.dumpResults(true); //Now print results. Use false for less detail
myReceiver.enableIRIn(); //Restart receiver
}
} #include “IRLibAll.h”
//Create a receiver object to listen on pin 2
IRrecvPCI myReceiver(2);
//Create a decoder object
IRdecode myDecoder;
void setup() {
Serial.begin(9600);
delay(2000); while (!Serial); //delay for Leonardo
myReceiver.enableIRIn(); // Start the receiver
Serial.println(F(“Ready to receive IR signals”));
}
void loop() {
//Continue looping until you get a complete signal received
if (myReceiver.getResults()) {
myDecoder.decode(); //Decode it
myDecoder.dumpResults(true); //Now print results. Use false for less detail
myReceiver.enableIRIn(); //Restart receiver
}
}
在加载草图之后,打开串行监视器并确保将其设置为9600波特。接收者然后按下一个按钮。在此示例中,我们按下Adafruit Mini Remote上的“播放/暂停”按钮。结果如下:
Decoded NEC(1): Value:FD807F (32 bits)
Raw samples(68): Gap:40826
Head: m8850 s4450
0:m500 s600 1:m550 s550 2:m500 s600 3:m550 s600
4:m500 s600 5:m500 s600 6:m500 s600 7:m550 s550
8:m500 s1750 9:m500 s1700 10:m500 s1700 11:m550 s1650
12:m550 s1700 13:m500 s1700 14:m500 s600 15:m550 s1700
16:m500 s1700 17:m500 s600 18:m500 s600 19:m500 s600
20:m550 s600 21:m450 s650 22:m500 s600 23:m500 s600
24:m500 s600 25:m500 s1700 26:m550 s1700 27:m500 s1700
28:m500 s1700 29:m550 s1700 30:m500 s1700 31:m500 s1700
32:m500
Extent=65850
Mark min:450 max:550
此转储的重要部分是第一行。这告诉我们检测到的协议是“ NEC”,在IRLib支持的协议中是协议号“ 1”。接收到的数据值为32位十六进制值FD807F。其余信息是接收到的实际标记和空格的原始计时数据。该信息对于尝试理解和支持协议很有用。
此32位数字唯一标识您按下的按钮。如果我们按下此遥控器上的“降低音量”和“提高音量”按钮,我们将获得0xFD00FF和0xFD40BF值。
尝试按一下电视或DVD遥控器上的各种按钮,您可能躺在家里。如果顶行显示:
Decoded Unknown(0): Value:0 (0 bits)
,则表明IRLib无法理解您的遥控器使用的协议。以下是其他遥控器的一些典型值。我是从Sony DVD播放器上的电源按钮以及科学大西洋DVR/电缆盒上的播放按钮获得的。
Decoded Sony(2): Value:74BCA (20 bits)
Decoded Panasonic Old(5): Value:37990C (22 bits)
这表明DVD播放机使用了Sony协议,该协议是2号协议,并且是20位协议。电缆盒使用22位的Panasonic_Old协议5。大多数协议始终使用相同数量的位,但是某些协议(例如Sony)具有不同的版本,除了20外还可以使用8、12或15位。
工作原理
让我们看看这里发生了什么。接收器对象侦听红外传感器,当它看到信号时,便开始测量标记和空格的时间。如果经过特定时间没有其他信号,则认为数据已完成,并且当您调用My_Receiver.GetResults时,它将返回“ true”。它将数据传递到您的解码器对象。解码器使用时序信息和位数来查看它是否与所支持的协议之一匹配。如果成功,则返回“ true”,尽管在此草图中我们无需费心检查。
您可以访问My_Decoder.protocolNum中的协议号,My_Decoder.bits中的位数和
在草图的顶部,我们将解码器对象创建为“ IRdecode”类型。此类包含所有11种受支持的协议。如果您正在使用该库来控制诸如伺服之类的设备,或者打开和关闭继电器,则可能要使用具有一种协议的一个遥控器。一旦知道要使用的协议,您可能希望使用仅适用于您特定协议的其他解码器类。它可以在您的草图中节省宝贵的程序空间。例如,如果我们使用的是使用NEC协议的Adafruit Mini Remote,则会将第7行更改为:
下载:文件
复制代码
IRdecodeNEC My_Decoder; IRdecodeNEC My_Decoder;
特定于协议的问题
IRLib直接支持11种协议,并且可能包含有关如何实现其他协议的示例代码。如前所述,库的工作之一是将应用程序程序员与处理内部问题的需求隔离开来。但是,您可能需要处理一些特定于协议的问题。
IRLibProtocols/IRLibProtocols.h中的大约第14行枚举了这些协议,如下所示。
下载:文件
复制代码
#define UNKNOWN 0
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define PANASONIC_OLD 5
#define JVC 6
#define NECX 7
#define SAMSUNG36 8
#define GICABLE 9
#define DIRECTV 10
#define RCMM 11
#define UNKNOWN 0
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define PANASONIC_OLD 5
#define JVC 6
#define NECX 7
#define SAMSUNG36 8
#define GICABLE 9
#define DIRECTV 10
#define RCMM 11
您可能需要处理一些协议特定的问题。
NEC重复代码
NEC协议使用特殊的标记和空格序列,表示“我按下了按钮,因此您应该重复上次发送给您的内容”。由您决定是要允许重复代码还是要强制操作员每次按下和释放按钮。 IRLib返回0xFFFFFFFF的值,以告诉您已收到特殊的重复序列。您可以忽略使用户每次都释放并按下按钮的顺序,或者可以存储先前收到的代码并在看到特殊的重复消息时对其进行处理。
Sony三重消息
Sony协议的技术规范规定,每次按键时,您应该连续3次发送每个代码。 IRLib会为您发送三遍,因此您无需执行任何特殊操作。但是,在接收Sony时,请注意,每次用户按下按钮时,您将获得三份数据副本。如果您正在忙于处理第一个序列,则可能会错过其他两个序列,所以没关系。但是,如果您要计算按键或其他应用程序的数量,则需要意识到这一点。
RC5和RC6切换位
菲利普斯(Phillips)发明的RC5和RC6协议使用特殊的切换位来告知您是否通过按住按钮生成了代码,或者是一个独立的按键。例如,我有一台使用RC5协议的电视,“调高音量”的代码是0x1010。如果我按住该按钮,它将重复发送相同的代码。但是,如果我释放按钮并再次按下它,则会得到0x1810。每隔一次按键一次0x0800将关闭或打开。您可以通过掩盖该特定位来确保忽略此功能。当您从该协议收到解码后的值时,您可以执行以下操作:
下载:文件
复制代码
My_Decoder.value &=0xf7ff; My_Decoder.value &=0xf7ff;
这将确保切换位始终处于关闭状态。 RC6协议还具有一个标题位,即0x10000。因此,要掩盖它,您可以执行以下操作:
下载:文件
复制代码
My_Decoder.value &=0xfeffff; My_Decoder.value &=0xfeffff;
使用IR控制NeoPixels
在这个非常简单的示例中,我们将通过按遥控器上的按钮来更改NeoPixel的颜色。我们使用的是单个像素,但是您可以修改草图以控制整个条带或矩阵。有关NeoPixels的更多信息,请访问Adafruit学习系统中的本指南。这是代码:
下载:文件
复制代码
#include
#include
IRrecv myReceiver(2);//receiver on pin 2
IRdecode myDecoder;//Decoder object
//One NeoPixel connected to pin 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1,6,NEO_GRB + NEO_KHZ800);
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to ‘off’
myReceiver.enableIRIn(); // Start the receiver
}
void loop() {
if (myReceiver.getResults()) {
myDecoder.decode();
if (myDecoder.protocolNum == NEC) {
switch(myDecoder.value) {
case 0xfd00ff: //Volume Down
strip.setPixelColor(0,255,0,0);//Red
break;
case 0xfd807f: //Play/Pause
strip.setPixelColor(0,0,255,0);//Green
break;
case 0xfd40bf: //Volume Up
strip.setPixelColor(0,0,0,255);//Blue
break;
}
strip.show();
myReceiver.enableIRIn(); //Restart the receiver
}
}
} #include
#include
IRrecv myReceiver(2);//receiver on pin 2
IRdecode myDecoder;//Decoder object
//One NeoPixel connected to pin 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1,6,NEO_GRB + NEO_KHZ800);
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to ‘off’
myReceiver.enableIRIn(); // Start the receiver
}
void loop() {
if (myReceiver.getResults()) {
myDecoder.decode();
if (myDecoder.protocolNum == NEC) {
switch(myDecoder.value) {
case 0xfd00ff: //Volume Down
strip.setPixelColor(0,255,0,0);//Red
break;
case 0xfd807f: //Play/Pause
strip.setPixelColor(0,0,255,0);//Green
break;
case 0xfd40bf: //Volume Up
strip.setPixelColor(0,0,0,255);//Blue
break;
}
strip.show();
myReceiver.enableIRIn(); //Restart the receiver
}
}
}
我们创建一个NeoPixel带,其中一个像素连接到引脚6。还创建一个连接到引脚11的接收器对象和一个解码器对象。在设置例程中重新初始化像素带和IR接收器。然后在主环路中连续测试接收器,以查看其是否已接收到许多IR信号。如果myReceiver.getResults返回true,则我们解码数据。我们正在使用之前使用的Adafruit Mini Remote。它使用了NEC协议,因此我们确保确实收到了NEC协议数据。然后,我们使用switch语句针对My_Decoder.value中的解码数据测试各种32位十六进制值。
根据接收到的值设置像素颜色后,我们需要调用strip.show ()实际更改颜色,然后myReceiver.enableIRIn()重置接收器,以便它可以收集其他代码。
上载草图并尝试按调低音量,播放/暂停和调高音量按钮。您应该看到像素变为红色,绿色或蓝色。您可以轻松添加其他case语句和颜色,或者使其中一种case调用动画例程来对整个像素带进行动画处理。遥控器上的不同按钮会选择不同的动画模式。
如果使用其他遥控器,则必须修改此草图。将协议类型更改为:
下载:文件
复制代码
if (myDecoder.protocolNum==SONY) if (myDecoder.protocolNum==SONY)
,例如,如果您使用的是Sony遥控器。当然,您必须在每个case语句中替换适当的代码。可以在IRLib.h的第60行找到用于比较解码类型的可用协议的枚举列表。
使用IR控制伺服器
设置
在此示例中,我们将使用红外遥控器控制伺服器。我们可以调整伺服器的移动速度,并可以选择单个预设角度来定位伺服器。
这里是显示如何连接设备的示意图。像往常一样,我们将一个IR接收器连接到+ 5v,地和引脚11。我们还有一个带有三根导线的伺服器。红线为+ 5v。黑色或暗褐色的电线接地,其余的通常是黄色的电线是我们连接到引脚9的信号线,尽管它可以是任何数字输出引脚。
i》 注意:上图显示了接收器在引脚11上,但是示例代码使用了引脚2。可以使用任何数字输入引脚。
上传代码
下面是来自“ IRLib2/examples”文件夹。它已被修改为与Adafruit Mini Remote一起使用。如果使用其他遥控器,则必须使用dump.ino收集有关各种按钮的代码的信息,并使用正确的协议名称和代码来修改草图。
下载:文件
复制代码
#include
#include
// You will have to set these values depending on the protocol
// and remote codes that you are using. These are For the Adafruit
// Mini Remote
#define MY_PROTOCOL NEC
#define RIGHT_ARROW 0xfd50af //Move several clockwise
#define LEFT_ARROW 0xfd10ef //Move servo counterclockwise
#define SELECT_BUTTON 0xfd906f //Center the servo
#define UP_ARROW 0xfda05f //Increased number of degrees servo moves
#define DOWN_ARROW 0xfdb04f //Decrease number of degrees servo moves
#define BUTTON_0 0xfd30cf //Pushing buttons 0-9 moves to fixed positions
#define BUTTON_1 0xfd08f7 // each 20 degrees greater
#define BUTTON_2 0xfd8877
#define BUTTON_3 0xfd48b7
#define BUTTON_4 0xfd28d7
#define BUTTON_5 0xfda857
#define BUTTON_6 0xfd6897
#define BUTTON_7 0xfd18e7
#define BUTTON_8 0xfd9867
#define BUTTON_9 0xfd58a7
IRrecv myReceiver(2); //pin number for the receiver
IRdecode myDecoder;
Servo myServo; // create servo object to control a servo
int16_t pos; // variable to store the servo position
int16_t Speed; // Number of degrees to move each time a left/right button is pressed
uint32_t Previous;//handles NEC repeat codes
void setup() {
myServo.attach(9); // attaches the servo on pin 9 to the servo object
pos = 90; // start at midpoint 90 degrees
Speed = 3; // servo moves 3 degrees each time left/right is pushed
myServo.write(pos); // Set initial position
myReceiver.enableIRIn(); // Start the receiver
}
void loop()
{
if (myReceiver.getResults()) {
myDecoder.decode();
if(myDecoder.protocolNum==MY_PROTOCOL) {
if(myDecoder.value==0xFFFFFFFF)
myDecoder.value=Previous;
switch(myDecoder.value) {
case LEFT_ARROW: pos=min(180,pos+Speed); break;
case RIGHT_ARROW: pos=max(0,pos-Speed); break;
case SELECT_BUTTON: pos=90; break;
case UP_ARROW: Speed=min(10, Speed+1); break;
case DOWN_ARROW: Speed=max(1, Speed-1); break;
case BUTTON_0: pos=0*20; break;
case BUTTON_1: pos=1*20; break;
case BUTTON_2: pos=2*20; break;
case BUTTON_3: pos=3*20; break;
case BUTTON_4: pos=4*20; break;
case BUTTON_5: pos=5*20; break;
case BUTTON_6: pos=6*20; break;
case BUTTON_7: pos=7*20; break;
case BUTTON_8: pos=8*20; break;
case BUTTON_9: pos=9*20; break;
}
myServo.write(pos); // tell servo to go to position in variable ‘pos’
Previous=myDecoder.value;
}
myReceiver.enableIRIn();
}
} #include
#include
// You will have to set these values depending on the protocol
// and remote codes that you are using. These are For the Adafruit
// Mini Remote
#define MY_PROTOCOL NEC
#define RIGHT_ARROW 0xfd50af //Move several clockwise
#define LEFT_ARROW 0xfd10ef //Move servo counterclockwise
#define SELECT_BUTTON 0xfd906f //Center the servo
#define UP_ARROW 0xfda05f //Increased number of degrees servo moves
#define DOWN_ARROW 0xfdb04f //Decrease number of degrees servo moves
#define BUTTON_0 0xfd30cf //Pushing buttons 0-9 moves to fixed positions
#define BUTTON_1 0xfd08f7 // each 20 degrees greater
#define BUTTON_2 0xfd8877
#define BUTTON_3 0xfd48b7
#define BUTTON_4 0xfd28d7
#define BUTTON_5 0xfda857
#define BUTTON_6 0xfd6897
#define BUTTON_7 0xfd18e7
#define BUTTON_8 0xfd9867
#define BUTTON_9 0xfd58a7
IRrecv myReceiver(2); //pin number for the receiver
IRdecode myDecoder;
Servo myServo; // create servo object to control a servo
int16_t pos; // variable to store the servo position
int16_t Speed; // Number of degrees to move each time a left/right button is pressed
uint32_t Previous;//handles NEC repeat codes
void setup() {
myServo.attach(9); // attaches the servo on pin 9 to the servo object
pos = 90; // start at midpoint 90 degrees
Speed = 3; // servo moves 3 degrees each time left/right is pushed
myServo.write(pos); // Set initial position
myReceiver.enableIRIn(); // Start the receiver
}
void loop()
{
if (myReceiver.getResults()) {
myDecoder.decode();
if(myDecoder.protocolNum==MY_PROTOCOL) {
if(myDecoder.value==0xFFFFFFFF)
myDecoder.value=Previous;
switch(myDecoder.value) {
case LEFT_ARROW: pos=min(180,pos+Speed); break;
case RIGHT_ARROW: pos=max(0,pos-Speed); break;
case SELECT_BUTTON: pos=90; break;
case UP_ARROW: Speed=min(10, Speed+1); break;
case DOWN_ARROW: Speed=max(1, Speed-1); break;
case BUTTON_0: pos=0*20; break;
case BUTTON_1: pos=1*20; break;
case BUTTON_2: pos=2*20; break;
case BUTTON_3: pos=3*20; break;
case BUTTON_4: pos=4*20; break;
case BUTTON_5: pos=5*20; break;
case BUTTON_6: pos=6*20; break;
case BUTTON_7: pos=7*20; break;
case BUTTON_8: pos=8*20; break;
case BUTTON_9: pos=9*20; break;
}
myServo.write(pos); // tell servo to go to position in variable ‘pos’
Previous=myDecoder.value;
}
myReceiver.enableIRIn();
}
}
注意:如果使用Leonardo,Micro或Yun或其他ATmega32u4系统,请参阅本页末尾的特殊说明。
上传草图,然后尝试按左右箭头按钮。伺服器应左右旋转。按下输入按钮应使伺服器居中。按下向上或向下箭头按钮不会产生任何可见效果,但是会改变您向左或向右推动的移动速度。从零到九的编号按钮以20°的间隔将伺服器移动到10个不同的固定位置。
如果伺服器行为异常,则可能是电源问题。一些USB端口无法提供足够的电流来驱动Arduino和移动伺服器。您可能需要添加一个外部5伏电源。以下是演示此示例的视频。
暂时无法加载嵌入的内容:
暂时无法加载嵌入的内容:
暂时无法加载嵌入的内容:
工作原理
程序在对象,解码器对象和伺服对象上创建接收器。您可以在此处找到有关标准Arduino伺服库的更多信息。设置功能附加了伺服器,启用了IR输入,并初始化了几个变量。
循环功能获取一个IR代码,并根据其值将其传递给switch语句。 switch语句的每种情况处理根据需要移动伺服器的不同功能。
由于使用的是NEC协议,因此需要处理一点开销。该协议具有独特的功能,可让您查看是否按住了遥控器上的按钮以发送相同值的重复实例。它具有特殊的标记和空格序列,表示“重复您上次所做的操作”。当IRLib看到特殊序列时,它将返回值0xFFFFFFFF。我们通过将先前的值存储在switch语句的底部来处理这种特殊情况,以便如果我们得到重复的代码,则下次可以替换它。 NEC协议是唯一使用此特定方法检测重复代码的协议。其他协议具有其他系统,有关这些系统的详细信息,请参见IRLib文档。
基于ATmega32u4的系统的特殊说明
此处提供的示例在Arduino Uno或Mega上应该可以正常工作,但是如果您使用的是Arduino Leonardo,Arduino Micro,Arduino Yun或其他基于ATmega32u4的示例系统,您必须对IRLib进行一些修改。
IRLib使用Arduino的内置硬件计时器每隔50µs产生一次中断,以便它可以轮询输入引脚以查看是否已更改。默认情况下,它使用TIMER2。 Arduino伺服库还通过TIMER1使用硬件中断。但是,ATmega32u4处理器没有TIMER2,因此IRLib在使用该处理器的系统上默认为TIMER1。您将必须修改“ IRLibProtocols/IRLibHardware.h”以更改默认计时器。在该文件的大约第56行,您将看到类似以下内容的文件:
下载:文件
复制代码
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
// it‘s Teensy 2.0
//#define IR_SEND_TIMER1 14
//#define IR_SEND_TIMER3 9
#define IR_SEND_TIMER4_HS 10
#else
/* it’s probably Leonardo */
#define IR_SEND_TIMER1 9
//#define IR_SEND_TIMER3 5
//#define IR_SEND_TIMER4_HS 13
#endif
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
// it‘s Teensy 2.0
//#define IR_SEND_TIMER1 14
//#define IR_SEND_TIMER3 9
#define IR_SEND_TIMER4_HS 10
#else
/* it’s probably Leonardo */
#define IR_SEND_TIMER1 9
//#define IR_SEND_TIMER3 5
//#define IR_SEND_TIMER4_HS 13
#endif
您需要将//放在#define IR_SEND_TIMER1前面,以注释掉该行。然后从其他两个选项之一TIMER3或TIMER4_HS前面的斜杠上删除。请注意,这些定义说“ IR_SEND_TIMERxx”。在文件的后面,我们将该值复制为也用作接收计时器。如果您使用的是Leonardo,后来又使用IRLib发送IR信号,则需要在这些定义之后记下数字。尽管我们可以将接收器连接到任何数字输入引脚,但是IRLib要求您根据使用的计时器使用特定的输出引脚。稍后将在发送部分中介绍。
发送IR代码
硬件问题
IRLib不仅接收和解码IR信号,但它也可以使用IR LED和驱动器电路传输它们。该库已用于控制电视,电缆盒,DVD,VCR和诸如直升机和恐龙机器人之类的IR控制玩具。
它还可以用于控制某些家庭自动化设备。一些用户试图控制空调和风扇,但是用于空调的协议非常难以实现,并且由于它们很少见,我们还没有直接支持这种协议。
通常,Arduino的输出引脚无法提供足够的电流来驱动LED和IR LED,因此您将需要使用NPN晶体管实现一个简单的驱动器电路,并在此处显示一个470欧姆的电阻:
请确保正确设置了LED的极性。两条引线中的较短的一根连接到晶体管,而一根较长的一根连接到正电源。请注意,流经LED的电流很可能会超过最大连续电流额定值。但是,由于信号被调制并且发送的脉冲序列仅持续几毫秒,因此电路将正常工作。
IRLIb手册的第1.4节“硬件注意事项”中提供了更多高级驱动器电路原理图。/p》
虽然我们可以将IR接收器连接到任何可用的数字输入引脚,但您只能使用非常特定的引脚进行输出。该库使用PWM引脚并修改定时参数以更改该引脚的默认频率。
Arduino Uno和Arduino Mega的默认计时器为TIMER2。在Leonardo上的是TIMER1。针脚编号为Uno的针脚3,并为Leonardo和Mega使用针脚9。如果已将库修改为使用其他计时器,例如更改Leonardo上的计时器编号以避免与伺服库发生冲突,那么您将需要使用其他特定的引脚。有关显示硬件计时器和引脚号之间关系的表,请参见IRLib用户手册中的1.4.1支持的平台部分。
加载软件
我们假设您已经按照本教程前面所述安装了IRLib库。让我们加载一个简单的草图,看看它是如何工作的。这是来自示例文件夹的IRsendDemo草图。
下载:文件
复制代码
#include
IRsend mySender;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
//send a code every time a character is received from the serial port
//Sony DVD power A8BCA
mySender.send(SONY,0xa8bca, 20);
}
} #include
IRsend mySender;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
//send a code every time a character is received from the serial port
//Sony DVD power A8BCA
mySender.send(SONY,0xa8bca, 20);
}
}
在这个简单的示例中,每次您键入a时,我们都会发送代码以打开和关闭Sony DVD播放器。字符插入串行监视器。我们创建一个发送对象mySender。除了初始化串行端口外,没有其他设置。在循环中,我们检查输入的字符,如果有,请发送代码。
send方法具有三个参数:协议类型,数据和位数。
我们创建的IRsend对象是一个支持所有11种支持协议的通用例程。但是在这种情况下,由于我们仅使用一种协议,因此可以使用以下对象创建对象:
下载:文件
复制代码
IRsendSony mySender; IRsendSony mySender;
在循环内,发送命令将为:
下载:文件
复制代码
mySender.send(0xa8bca, 20); mySender.send(0xa8bca, 20);
某些协议(例如NEC)始终使用相同的位数,因此您无需将其指定为附加参数。请参阅用户手册以了解是否需要extra bits参数。
用户手册还为您提供有关如何创建仅使用受支持协议的特定子集的解码和发送例程的信息。在IRLib 2.0中,这比原始版本要容易得多。
在同一程序中发送和接收
在同一程序中进行发送和接收时,有一些特殊注意事项。发送和接收都使用建筑物硬件计时器。但是,计时器用于两个不同的目的。发送代码时,它将重新配置计时器并禁用接收。因此,您必须在每次发送后重新启用接收器。例如:
下载:文件
复制代码
mySender.send(Protocol, Data, Bits);
myReceiver.enableIRIn(); // Re-enable receiver mySender.send(Protocol, Data, Bits);
myReceiver.enableIRIn(); // Re-enable receiver
通常,您只需要调用myReceiver.enableIRIn();即可。在设置例程中一次,但是如果您同时在发送和接收,则必须在每次发送之后调用它。
有关如何在同一程序中发送和接收的完整示例,请查看record.ino “ IRLib2/examples”文件夹中的示例草图。加载草图时,请打开串行监视器,将遥控器指向接收器,然后按一个按钮。该程序将捕获该代码。然后,每当字符类型进入串行监视器时,它将通过LED重复该代码。
责任编辑:wv
-
Arduino
+关注
关注
188文章
6468浏览量
186935
发布评论请先 登录
相关推荐
评论