概述
注意:本教程已更新為可與IRLib 2.x一起使用,與以前的版本有顯著差異。
大多數(shù)消費(fèi)電子設(shè)備,例如電視,電纜盒,DVD播放器和其他設(shè)備,都使用紅外信號進(jìn)行遠(yuǎn)程控制。每個制造商都有自己的協(xié)議來對數(shù)據(jù)進(jìn)行編碼,以使發(fā)送給一臺設(shè)備的信號不會干擾另一臺設(shè)備。在LadyAdashe的早期教程中,介紹了從遠(yuǎn)程讀取IR信號并使用IR LED創(chuàng)建自己的IR信號的內(nèi)部工作方式。 。她的教程為您提供了IR工作原理的幕后花絮,但是要想弄清楚項目中的所有技術(shù)細(xì)節(jié)都有些困難。
如果您像我一樣,則不知道該怎么做。 NeoPixels可以工作,也不可以在I2C或SPI通信的內(nèi)部工作,但是您不需要這樣做,因為我們有相應(yīng)的庫。一個好的代碼庫會將您(應(yīng)用程序程序員)與硬件細(xì)節(jié)和設(shè)備的內(nèi)部運(yùn)作隔離開來,并為您提供一個API,使您可以輕松使用硬件而無需了解或關(guān)注幕后情況。
在本教程中,我們將向您展示如何在基于Arduino的項目中使用IRLib接收,解碼和發(fā)送IR信號。我們將向您展示如何在NeoPixel上更改顏色,如何使用IR遙控器控制伺服器以及如何從Arduino向電視或電纜盒發(fā)送信號。未來的教程將包括IR控制鼠標(biāo),物聯(lián)網(wǎng)遠(yuǎn)程控制和控制機(jī)械臂。
關(guān)于IR庫
IR信號由一系列稱為“標(biāo)記”的調(diào)制脈沖組成,這些脈沖由稱為“空格”的間隔隔開。通常,每個信號的開頭都有一個長標(biāo)記和空格,用作標(biāo)頭。然后,通過改變標(biāo)記和空格的時序,可以傳輸一系列比特。如果必須存儲整個信號的精確時序,則需要使用最多100個16位整數(shù)的數(shù)組。為了比較接收到的數(shù)據(jù)以查看是否是您想要的數(shù)據(jù),您同樣需要存儲大量數(shù)據(jù)。
幸運(yùn)的是,信號是根據(jù)非常特定的協(xié)議發(fā)送的,您可以使用此協(xié)議接收時序數(shù)據(jù)并將其轉(zhuǎn)換為最多32位的單個二進(jìn)制數(shù)。 IR庫將時序信息收集到緩沖區(qū)中,然后將其轉(zhuǎn)換為單個32位值。然后,您可以輕松地將該值與所需的值進(jìn)行比較。
類似地,如果您要發(fā)送IR信號,您需要做的就是將32位值傳遞給庫并告訴它要使用哪種協(xié)議使用。它將值轉(zhuǎn)換為帶有適當(dāng)標(biāo)題,位編碼和定時的標(biāo)記和空格流。
IR庫的金標(biāo)準(zhǔn)是“ LIRC”或Linux紅外遙控器,可在http://網(wǎng)站上找到它。/www.lirc.org/。它由驅(qū)動程序和有關(guān)數(shù)百個各種遠(yuǎn)程控制的大型信息數(shù)據(jù)庫組成。如果我們使用的是基于Linux的系統(tǒng),那么絕對是正確的選擇。我們將不在這里討論該庫,因為我們打算專注于基于Arduino的系統(tǒng)。
2009年8月,Ken Shirrff在他的博客上發(fā)布了“ IRremote”,并在GitHub上發(fā)布了該庫。然后在2013年1月,我根據(jù)Ken的早期工作發(fā)布了IRLib。此修訂版重新組織了代碼,使使用C ++中的面向?qū)ο?a target="_blank">編程設(shè)計可以更輕松地添加新協(xié)議。
有關(guān)IRLib的詳細(xì)信息,請參見我的博客,網(wǎng)址為:http://tech.cyborg5.com/irlib/。 。它包括一個詳盡的用戶手冊,該手冊也可以在該庫的“ manuals”文件夾中找到。。在本教程中,我們將使用IRLib來幫助您入門。
2016年9月,我們發(fā)布了主要的重寫IRLib的名稱稱為IRLib 2.0。它與原始IRLib不完全向后兼容。本教程已更新為使用IRLib 2.0。以前的IRLib 1.x將不再受支持。最近發(fā)布的IRLib 2.03增加了對32位SAMD 21處理器的支持,例如Arduino Zero,Adafruit Feather M0和即將推出的Circuit Playground Express中使用的處理器。
接收和解碼IR
軟件安裝
IRLib庫的安裝如下:
訪問GitHib上的IRLib2頁面。
選擇“下載ZIP”按鈕,或簡單地單擊此鏈接直接下載。
下載完成后解壓縮ZIP文件。
生成的文件夾應(yīng)命名為“ IRLib2-master”,并將包含5個單獨(dú)的文件夾。這是因為IRLib 2.x實際上是5個可一起使用的庫的集合。有時在Windows中,您會得到一個中級文件夾,并且需要四處移動。
將所有五個文件夾與其他Arduino庫一起復(fù)制到Arduino庫文件夾中,通常在(主文件夾)/Documents/Arduino/Libraries文件夾。庫不應(yīng)該與Arduino應(yīng)用程序本身一起安裝。
如果當(dāng)前正在運(yùn)行Arduino IDE,請重新啟動
此存儲庫由總共五個庫組成,每個庫它必須在您的arduino/libraries/文件夾中。因此,例如,應(yīng)按以下方式安裝它……
arduino/libraries/IRLib2
arduino/libraries/IRLibFreq
arduino/libraries/IRLibProtocols
arduino/libraries/IRLibRecv
arduino/libraries/IRLibRecvPCI
請勿將它們安裝在這樣的單個文件夾中……
arduino/libraries/IRLib2_master
IRLib2
IRLibFreq
IRLib協(xié)議
IRLibRecv
IRLibRecvPCI
這是一個教程,指導(dǎo)您正確安裝Arduino庫。
所需的硬件
IRLib在基于8位AVR的Arduino板上運(yùn)行,例如Uno,Leonardo,Mega和Micro。它也可以在Arduino Yun的Leonardo部分上運(yùn)行。我們最近增加了對Arduino Zero,F(xiàn)eather M0和Circuit Playground Express中使用的32位ARM SAMD 21處理器的支持。但是,我們不支持Arduino Due或其他類似Arduino的系統(tǒng)。不幸的是,目前它不能在Adafruit Trinket和Adafruit Gemma之類的ATtiny85基礎(chǔ)系統(tǒng)上運(yùn)行,但對它的支持在工作罐中,并且應(yīng)在不久的將來以精簡版本提供給那些平臺。在撰寫本文時,它尚未在Adafruit Trinket Pro上進(jìn)行過測試,但是由于它與Uno基于相同的ATmega328處理器,因此應(yīng)該可以正常工作。因此,您需要的第一件事是Arduino Uno或其他兼容板。
您將需要一個IR接收器。例如,右列顯示在特色產(chǎn)品下的TSOP38238。該設(shè)備結(jié)合了一個紅外敏感光電管,一個38 kHz帶通濾波器和自動增益控制。它可以在多種電源電壓下工作,包括3.3v和5v。它可以對接收到的IR信號進(jìn)行解調(diào),并在電源電壓水平上為您提供一個清晰的開,關(guān)脈沖方波。這意味著它是將其輸出直接饋送到Arduino的數(shù)字輸入引腳的理想選擇。
最后,您將需要一個IR遙控器,例如用于控制電視,電纜盒或DVD播放器的遙控器。我們所有的示例都將使用右側(cè)所示的Adafruit迷你遙控器,但是,我們將向您展示如何檢測自己的電視遙控器正在使用的協(xié)議,如果IRLib支持該協(xié)議,則可以使用它。
連接紅外接收器非常簡單。將左側(cè)的引腳連接到Arduino上的任何數(shù)字輸入引腳。在我們的示例中,我們將使用引腳2。將中心引腳接地,將右側(cè)引腳連接至+ 5v。
請注意,該設(shè)備的帶通濾波器已調(diào)至38 kHz,這是大多數(shù)協(xié)議的典型頻率。但是,某些協(xié)議會使用從36 kHz一直到57 kHz的頻率。但是,該濾波器不是非常特定,我們在使用38 kHz接收器接收36-40 kHz范圍內(nèi)的信號方面取得了成功。 Panasonic_Old協(xié)議使用56 kHz。 Adafruit出售的TSOP38238很難解碼該頻率。但是,盡管Radio Shack出售的接收器是38 kHz的設(shè)備,但我還是取得了不錯的成績。 Radio Shock沒有列出部件號,但我們認(rèn)為它是TSOP4438。令人遺憾的是,這可能不再是一個選擇:-(
這些設(shè)備是由Vishay制造的,具有多種包裝樣式,頻率和AGC方法。如果Adafruit設(shè)備不適用于您并且您需要56 kHz時,您可以參考以下指南。
Vishay的IR接收器選擇指南(PDF格式)
有關(guān)接收器和原理圖的更多信息有關(guān)使用多個接收器的信息,請參見IRLib手冊第1.4.3節(jié)。
解碼紅外數(shù)據(jù)
加載以下草圖,它是庫示例文件夾中“轉(zhuǎn)儲”草圖的略微修改版本。所有示例草圖均位于文件夾“ IRLib2/examples”。
下載:文件
復(fù)制代碼
#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
}
}
在加載草圖之后,打開串行監(jiān)視器并確保將其設(shè)置為9600波特。接收者然后按下一個按鈕。在此示例中,我們按下Adafruit Mini Remote上的“播放/暫停”按鈕。結(jié)果如下:
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
此轉(zhuǎn)儲的重要部分是第一行。這告訴我們檢測到的協(xié)議是“ NEC”,在IRLib支持的協(xié)議中是協(xié)議號“ 1”。接收到的數(shù)據(jù)值為32位十六進(jìn)制值FD807F。其余信息是接收到的實際標(biāo)記和空格的原始計時數(shù)據(jù)。該信息對于嘗試?yán)斫夂椭С謪f(xié)議很有用。
此32位數(shù)字唯一標(biāo)識您按下的按鈕。如果我們按下此遙控器上的“降低音量”和“提高音量”按鈕,我們將獲得0xFD00FF和0xFD40BF值。
嘗試按一下電視或DVD遙控器上的各種按鈕,您可能躺在家里。如果頂行顯示:
Decoded Unknown(0): Value:0 (0 bits)
,則表明IRLib無法理解您的遙控器使用的協(xié)議。以下是其他遙控器的一些典型值。我是從Sony DVD播放器上的電源按鈕以及科學(xué)大西洋DVR/電纜盒上的播放按鈕獲得的。
Decoded Sony(2): Value:74BCA (20 bits)
Decoded Panasonic Old(5): Value:37990C (22 bits)
這表明DVD播放機(jī)使用了Sony協(xié)議,該協(xié)議是2號協(xié)議,并且是20位協(xié)議。電纜盒使用22位的Panasonic_Old協(xié)議5。大多數(shù)協(xié)議始終使用相同數(shù)量的位,但是某些協(xié)議(例如Sony)具有不同的版本,除了20外還可以使用8、12或15位。
工作原理
讓我們看看這里發(fā)生了什么。接收器對象偵聽紅外傳感器,當(dāng)它看到信號時,便開始測量標(biāo)記和空格的時間。如果經(jīng)過特定時間沒有其他信號,則認(rèn)為數(shù)據(jù)已完成,并且當(dāng)您調(diào)用My_Receiver.GetResults時,它將返回“ true”。它將數(shù)據(jù)傳遞到您的解碼器對象。解碼器使用時序信息和位數(shù)來查看它是否與所支持的協(xié)議之一匹配。如果成功,則返回“ true”,盡管在此草圖中我們無需費(fèi)心檢查。
您可以訪問My_Decoder.protocolNum中的協(xié)議號,My_Decoder.bits中的位數(shù)和
在草圖的頂部,我們將解碼器對象創(chuàng)建為“ IRdecode”類型。此類包含所有11種受支持的協(xié)議。如果您正在使用該庫來控制諸如伺服之類的設(shè)備,或者打開和關(guān)閉繼電器,則可能要使用具有一種協(xié)議的一個遙控器。一旦知道要使用的協(xié)議,您可能希望使用僅適用于您特定協(xié)議的其他解碼器類。它可以在您的草圖中節(jié)省寶貴的程序空間。例如,如果我們使用的是使用NEC協(xié)議的Adafruit Mini Remote,則會將第7行更改為:
下載:文件
復(fù)制代碼
IRdecodeNEC My_Decoder; IRdecodeNEC My_Decoder;
特定于協(xié)議的問題
IRLib直接支持11種協(xié)議,并且可能包含有關(guān)如何實現(xiàn)其他協(xié)議的示例代碼。如前所述,庫的工作之一是將應(yīng)用程序程序員與處理內(nèi)部問題的需求隔離開來。但是,您可能需要處理一些特定于協(xié)議的問題。
IRLibProtocols/IRLibProtocols.h中的大約第14行枚舉了這些協(xié)議,如下所示。
下載:文件
復(fù)制代碼
#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
您可能需要處理一些協(xié)議特定的問題。
NEC重復(fù)代碼
NEC協(xié)議使用特殊的標(biāo)記和空格序列,表示“我按下了按鈕,因此您應(yīng)該重復(fù)上次發(fā)送給您的內(nèi)容”。由您決定是要允許重復(fù)代碼還是要強(qiáng)制操作員每次按下和釋放按鈕。 IRLib返回0xFFFFFFFF的值,以告訴您已收到特殊的重復(fù)序列。您可以忽略使用戶每次都釋放并按下按鈕的順序,或者可以存儲先前收到的代碼并在看到特殊的重復(fù)消息時對其進(jìn)行處理。
Sony三重消息
Sony協(xié)議的技術(shù)規(guī)范規(guī)定,每次按鍵時,您應(yīng)該連續(xù)3次發(fā)送每個代碼。 IRLib會為您發(fā)送三遍,因此您無需執(zhí)行任何特殊操作。但是,在接收Sony時,請注意,每次用戶按下按鈕時,您將獲得三份數(shù)據(jù)副本。如果您正在忙于處理第一個序列,則可能會錯過其他兩個序列,所以沒關(guān)系。但是,如果您要計算按鍵或其他應(yīng)用程序的數(shù)量,則需要意識到這一點(diǎn)。
RC5和RC6切換位
菲利普斯(Phillips)發(fā)明的RC5和RC6協(xié)議使用特殊的切換位來告知您是否通過按住按鈕生成了代碼,或者是一個獨(dú)立的按鍵。例如,我有一臺使用RC5協(xié)議的電視,“調(diào)高音量”的代碼是0x1010。如果我按住該按鈕,它將重復(fù)發(fā)送相同的代碼。但是,如果我釋放按鈕并再次按下它,則會得到0x1810。每隔一次按鍵一次0x0800將關(guān)閉或打開。您可以通過掩蓋該特定位來確保忽略此功能。當(dāng)您從該協(xié)議收到解碼后的值時,您可以執(zhí)行以下操作:
下載:文件
復(fù)制代碼
My_Decoder.value &=0xf7ff; My_Decoder.value &=0xf7ff;
這將確保切換位始終處于關(guān)閉狀態(tài)。 RC6協(xié)議還具有一個標(biāo)題位,即0x10000。因此,要掩蓋它,您可以執(zhí)行以下操作:
下載:文件
復(fù)制代碼
My_Decoder.value &=0xfeffff; My_Decoder.value &=0xfeffff;
使用IR控制NeoPixels
在這個非常簡單的示例中,我們將通過按遙控器上的按鈕來更改NeoPixel的顏色。我們使用的是單個像素,但是您可以修改草圖以控制整個條帶或矩陣。有關(guān)NeoPixels的更多信息,請訪問Adafruit學(xué)習(xí)系統(tǒng)中的本指南。這是代碼:
下載:文件
復(fù)制代碼
#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
}
}
}
我們創(chuàng)建一個NeoPixel帶,其中一個像素連接到引腳6。還創(chuàng)建一個連接到引腳11的接收器對象和一個解碼器對象。在設(shè)置例程中重新初始化像素帶和IR接收器。然后在主環(huán)路中連續(xù)測試接收器,以查看其是否已接收到許多IR信號。如果myReceiver.getResults返回true,則我們解碼數(shù)據(jù)。我們正在使用之前使用的Adafruit Mini Remote。它使用了NEC協(xié)議,因此我們確保確實收到了NEC協(xié)議數(shù)據(jù)。然后,我們使用switch語句針對My_Decoder.value中的解碼數(shù)據(jù)測試各種32位十六進(jìn)制值。
根據(jù)接收到的值設(shè)置像素顏色后,我們需要調(diào)用strip.show ()實際更改顏色,然后myReceiver.enableIRIn()重置接收器,以便它可以收集其他代碼。
上載草圖并嘗試按調(diào)低音量,播放/暫停和調(diào)高音量按鈕。您應(yīng)該看到像素變?yōu)榧t色,綠色或藍(lán)色。您可以輕松添加其他case語句和顏色,或者使其中一種case調(diào)用動畫例程來對整個像素帶進(jìn)行動畫處理。遙控器上的不同按鈕會選擇不同的動畫模式。
如果使用其他遙控器,則必須修改此草圖。將協(xié)議類型更改為:
下載:文件
復(fù)制代碼
if (myDecoder.protocolNum==SONY) if (myDecoder.protocolNum==SONY)
,例如,如果您使用的是Sony遙控器。當(dāng)然,您必須在每個case語句中替換適當(dāng)?shù)拇a。可以在IRLib.h的第60行找到用于比較解碼類型的可用協(xié)議的枚舉列表。
使用IR控制伺服器
設(shè)置
在此示例中,我們將使用紅外遙控器控制伺服器。我們可以調(diào)整伺服器的移動速度,并可以選擇單個預(yù)設(shè)角度來定位伺服器。
這里是顯示如何連接設(shè)備的示意圖。像往常一樣,我們將一個IR接收器連接到+ 5v,地和引腳11。我們還有一個帶有三根導(dǎo)線的伺服器。紅線為+ 5v。黑色或暗褐色的電線接地,其余的通常是黃色的電線是我們連接到引腳9的信號線,盡管它可以是任何數(shù)字輸出引腳。
i》 注意:上圖顯示了接收器在引腳11上,但是示例代碼使用了引腳2。可以使用任何數(shù)字輸入引腳。
上傳代碼
下面是來自“ IRLib2/examples”文件夾。它已被修改為與Adafruit Mini Remote一起使用。如果使用其他遙控器,則必須使用dump.ino收集有關(guān)各種按鈕的代碼的信息,并使用正確的協(xié)議名稱和代碼來修改草圖。
下載:文件
復(fù)制代碼
#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系統(tǒng),請參閱本頁末尾的特殊說明。
上傳草圖,然后嘗試按左右箭頭按鈕。伺服器應(yīng)左右旋轉(zhuǎn)。按下輸入按鈕應(yīng)使伺服器居中。按下向上或向下箭頭按鈕不會產(chǎn)生任何可見效果,但是會改變您向左或向右推動的移動速度。從零到九的編號按鈕以20°的間隔將伺服器移動到10個不同的固定位置。
如果伺服器行為異常,則可能是電源問題。一些USB端口無法提供足夠的電流來驅(qū)動Arduino和移動伺服器。您可能需要添加一個外部5伏電源。以下是演示此示例的視頻。
暫時無法加載嵌入的內(nèi)容:
暫時無法加載嵌入的內(nèi)容:
暫時無法加載嵌入的內(nèi)容:
工作原理
程序在對象,解碼器對象和伺服對象上創(chuàng)建接收器。您可以在此處找到有關(guān)標(biāo)準(zhǔn)Arduino伺服庫的更多信息。設(shè)置功能附加了伺服器,啟用了IR輸入,并初始化了幾個變量。
循環(huán)功能獲取一個IR代碼,并根據(jù)其值將其傳遞給switch語句。 switch語句的每種情況處理根據(jù)需要移動伺服器的不同功能。
由于使用的是NEC協(xié)議,因此需要處理一點(diǎn)開銷。該協(xié)議具有獨(dú)特的功能,可讓您查看是否按住了遙控器上的按鈕以發(fā)送相同值的重復(fù)實例。它具有特殊的標(biāo)記和空格序列,表示“重復(fù)您上次所做的操作”。當(dāng)IRLib看到特殊序列時,它將返回值0xFFFFFFFF。我們通過將先前的值存儲在switch語句的底部來處理這種特殊情況,以便如果我們得到重復(fù)的代碼,則下次可以替換它。 NEC協(xié)議是唯一使用此特定方法檢測重復(fù)代碼的協(xié)議。其他協(xié)議具有其他系統(tǒng),有關(guān)這些系統(tǒng)的詳細(xì)信息,請參見IRLib文檔。
基于ATmega32u4的系統(tǒng)的特殊說明
此處提供的示例在Arduino Uno或Mega上應(yīng)該可以正常工作,但是如果您使用的是Arduino Leonardo,Arduino Micro,Arduino Yun或其他基于ATmega32u4的示例系統(tǒng),您必須對IRLib進(jìn)行一些修改。
IRLib使用Arduino的內(nèi)置硬件計時器每隔50μs產(chǎn)生一次中斷,以便它可以輪詢輸入引腳以查看是否已更改。默認(rèn)情況下,它使用TIMER2。 Arduino伺服庫還通過TIMER1使用硬件中斷。但是,ATmega32u4處理器沒有TIMER2,因此IRLib在使用該處理器的系統(tǒng)上默認(rèn)為TIMER1。您將必須修改“ IRLibProtocols/IRLibHardware.h”以更改默認(rèn)計時器。在該文件的大約第56行,您將看到類似以下內(nèi)容的文件:
下載:文件
復(fù)制代碼
#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”。在文件的后面,我們將該值復(fù)制為也用作接收計時器。如果您使用的是Leonardo,后來又使用IRLib發(fā)送IR信號,則需要在這些定義之后記下數(shù)字。盡管我們可以將接收器連接到任何數(shù)字輸入引腳,但是IRLib要求您根據(jù)使用的計時器使用特定的輸出引腳。稍后將在發(fā)送部分中介紹。
發(fā)送IR代碼
硬件問題
IRLib不僅接收和解碼IR信號,但它也可以使用IR LED和驅(qū)動器電路傳輸它們。該庫已用于控制電視,電纜盒,DVD,VCR和諸如直升機(jī)和恐龍機(jī)器人之類的IR控制玩具。
它還可以用于控制某些家庭自動化設(shè)備。一些用戶試圖控制空調(diào)和風(fēng)扇,但是用于空調(diào)的協(xié)議非常難以實現(xiàn),并且由于它們很少見,我們還沒有直接支持這種協(xié)議。
通常,Arduino的輸出引腳無法提供足夠的電流來驅(qū)動LED和IR LED,因此您將需要使用NPN晶體管實現(xiàn)一個簡單的驅(qū)動器電路,并在此處顯示一個470歐姆的電阻:
請確保正確設(shè)置了LED的極性。兩條引線中的較短的一根連接到晶體管,而一根較長的一根連接到正電源。請注意,流經(jīng)LED的電流很可能會超過最大連續(xù)電流額定值。但是,由于信號被調(diào)制并且發(fā)送的脈沖序列僅持續(xù)幾毫秒,因此電路將正常工作。
IRLIb手冊的第1.4節(jié)“硬件注意事項”中提供了更多高級驅(qū)動器電路原理圖。/p》
雖然我們可以將IR接收器連接到任何可用的數(shù)字輸入引腳,但您只能使用非常特定的引腳進(jìn)行輸出。該庫使用PWM引腳并修改定時參數(shù)以更改該引腳的默認(rèn)頻率。
Arduino Uno和Arduino Mega的默認(rèn)計時器為TIMER2。在Leonardo上的是TIMER1。針腳編號為Uno的針腳3,并為Leonardo和Mega使用針腳9。如果已將庫修改為使用其他計時器,例如更改Leonardo上的計時器編號以避免與伺服庫發(fā)生沖突,那么您將需要使用其他特定的引腳。有關(guān)顯示硬件計時器和引腳號之間關(guān)系的表,請參見IRLib用戶手冊中的1.4.1支持的平臺部分。
加載軟件
我們假設(shè)您已經(jīng)按照本教程前面所述安裝了IRLib庫。讓我們加載一個簡單的草圖,看看它是如何工作的。這是來自示例文件夾的IRsendDemo草圖。
下載:文件
復(fù)制代碼
#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時,我們都會發(fā)送代碼以打開和關(guān)閉Sony DVD播放器。字符插入串行監(jiān)視器。我們創(chuàng)建一個發(fā)送對象mySender。除了初始化串行端口外,沒有其他設(shè)置。在循環(huán)中,我們檢查輸入的字符,如果有,請發(fā)送代碼。
send方法具有三個參數(shù):協(xié)議類型,數(shù)據(jù)和位數(shù)。
我們創(chuàng)建的IRsend對象是一個支持所有11種支持協(xié)議的通用例程。但是在這種情況下,由于我們僅使用一種協(xié)議,因此可以使用以下對象創(chuàng)建對象:
下載:文件
復(fù)制代碼
IRsendSony mySender; IRsendSony mySender;
在循環(huán)內(nèi),發(fā)送命令將為:
下載:文件
復(fù)制代碼
mySender.send(0xa8bca, 20); mySender.send(0xa8bca, 20);
某些協(xié)議(例如NEC)始終使用相同的位數(shù),因此您無需將其指定為附加參數(shù)。請參閱用戶手冊以了解是否需要extra bits參數(shù)。
用戶手冊還為您提供有關(guān)如何創(chuàng)建僅使用受支持協(xié)議的特定子集的解碼和發(fā)送例程的信息。在IRLib 2.0中,這比原始版本要容易得多。
在同一程序中發(fā)送和接收
在同一程序中進(jìn)行發(fā)送和接收時,有一些特殊注意事項。發(fā)送和接收都使用建筑物硬件計時器。但是,計時器用于兩個不同的目的。發(fā)送代碼時,它將重新配置計時器并禁用接收。因此,您必須在每次發(fā)送后重新啟用接收器。例如:
下載:文件
復(fù)制代碼
mySender.send(Protocol, Data, Bits);
myReceiver.enableIRIn(); // Re-enable receiver mySender.send(Protocol, Data, Bits);
myReceiver.enableIRIn(); // Re-enable receiver
通常,您只需要調(diào)用myReceiver.enableIRIn();即可。在設(shè)置例程中一次,但是如果您同時在發(fā)送和接收,則必須在每次發(fā)送之后調(diào)用它。
有關(guān)如何在同一程序中發(fā)送和接收的完整示例,請查看record.ino “ IRLib2/examples”文件夾中的示例草圖。加載草圖時,請打開串行監(jiān)視器,將遙控器指向接收器,然后按一個按鈕。該程序?qū)⒉东@該代碼。然后,每當(dāng)字符類型進(jìn)入串行監(jiān)視器時,它將通過LED重復(fù)該代碼。
責(zé)任編輯:wv
-
Arduino
+關(guān)注
關(guān)注
188文章
6471瀏覽量
187293
發(fā)布評論請先 登錄
相關(guān)推薦
評論