12.紅外線遙控與間隔拍攝控制器
認識紅外線
可見光、紅外線和電波,都是電磁波的一種,
遠紅外線和近紅外線,人體在常溫下所釋放的紅外線波長約10um(微米)。靠近可見光部分的近紅外線,幾乎不會散發熱能,通常用於紅外線通訊、遙控和距離感測器。
人體紅外線感測器
感測器上頭的白色半透明PE透鏡黏在電路板上,裡面有一個熱釋電型感測器,熱釋電(pyroelectric)代表該模組會隨著溫度變化產生電子訊號。感測器模組上的IC電路將會接收並處理感測器訊號,以高電位或低電位的形式輸出。人體紅外線偵測模組,相當於電子開關,平常輸出低電位(0V),偵測到人體移動時,變成高電位(3.3V)。
此感測器全名為被動式(Passive)紅外移動感測器
熱釋電型感測器,熱釋電(pyroelectric)代表該模組會隨著溫度變化產生電子訊號。感測器模組上的IC電路將會接收並處理感測器的訊號,以高電位或低電位的形式輸出。總之,人體紅外線偵測模組,相當於電子開關,平常輸出低電位(0V),偵測到人體移動時,變成高電位(3.3V)。
動手做12-1 監測人體移動
實驗說明: 使用人體紅外線感測器來點亮位於Arduino板子13埠的LED
**程式:**由於人體紅外線感測器模組只會返回0與1兩種狀態值。
const byte pirPin = 12; //紅外線感測器訊號埠 const byte ledPin = 13; //LED埠 void setup() { pinMode(pirPin, INPUT); pinMode(ledPin, OUTPUT); //LED埠設定成“輸出” } void loop(){ boolean val = digitalRead(pirPin); //讀取感測器值 if (val) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } }
紅外線遙控
紅外線遙控接收器,都只對特定的頻率訊號(正確的名字叫做載波,通常是36kHZ或38kHZ)和“通關密語”有反應。這個“通關密語”稱為協議。
紅外線遙控接收元器件
紅外線遙控接收元器件,它的內部包含紅外線接收元器件以及訊號處理IC,常見的型號是TSOP4836和TSOP4838(後面兩個數字代表載波頻率)。
普通的紅外線接收元器件不含訊號處理IC,其主要規格是感應的紅外線波長範圍。
紅外線接收元器件的外觀像一般的LED,通常用在障礙物檢測及距離感測,
動手做12-2 使用IRremote擴充套件庫解析紅外線遙控值
實驗說明: 將組裝一個Arduino萬用紅外線遙控接收器,並通過Ken Shirriff寫的IRremote擴充套件庫(網址:https://github.com/shirriff/Arduino-IRremote),讀取各大品牌的紅外線遙控器訊號。
程式: 請先把“IRremote”擴充套件庫檔案複製到Arduino的libraries資料夾。選擇檔案→示例→IRremote→IRrecvDemo。
#include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN); //宣告一個紅外接收物件,名叫irrecv,接收埠是11
decode_results results; // 宣告一個儲存接收值得變數
void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); //啟動紅外接收功能
}
void loop() {
//解析紅外接收值,若decode()返回true,代表有收到新的資料。
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX); //讀取解析後的數字,並以16進位格式輸出。
irrecv.resume(); //準備進行接收下一組資料
}
}
讀取紅外線原始(raw)格式
IRremote擴充套件庫提供另一個“IRrecvDump”示例程式,能辨別並顯示紅外線遙控訊號的格式名稱,並輸出接收器所收到的原始資料。
//------------------------------------------------------------------------------
// Include the IRremote library header
//
#include <IRremote.h>
//------------------------------------------------------------------------------
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
//
int recvPin = 11;
IRrecv irrecv(recvPin);
//+=============================================================================
// Configure the Arduino
//
void setup ( )
{
Serial.begin(9600); // Status message will be sent to PC at 9600 baud
irrecv.enableIRIn(); // Start the receiver
}
//+=============================================================================
// Display IR code
//
void ircode (decode_results *results)
{
// Panasonic has an Address
if (results->decode_type == PANASONIC) {
Serial.print(results->address, HEX);
Serial.print(":");
}
// Print Code
Serial.print(results->value, HEX);
}
//+=============================================================================
// Display encoding type
//
void encoding (decode_results *results)
{
switch (results->decode_type) {
default:
case UNKNOWN: Serial.print("UNKNOWN"); break ;
case NEC: Serial.print("NEC"); break ;
case SONY: Serial.print("SONY"); break ;
case RC5: Serial.print("RC5"); break ;
case RC6: Serial.print("RC6"); break ;
case DISH: Serial.print("DISH"); break ;
case SHARP: Serial.print("SHARP"); break ;
case JVC: Serial.print("JVC"); break ;
case SANYO: Serial.print("SANYO"); break ;
case MITSUBISHI: Serial.print("MITSUBISHI"); break ;
case SAMSUNG: Serial.print("SAMSUNG"); break ;
case LG: Serial.print("LG"); break ;
case WHYNTER: Serial.print("WHYNTER"); break ;
case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break ;
case PANASONIC: Serial.print("PANASONIC"); break ;
case DENON: Serial.print("Denon"); break ;
}
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpInfo (decode_results *results)
{
// Check if the buffer overflowed
if (results->overflow) {
Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF");
return;
}
// Show Encoding standard
Serial.print("Encoding : ");
encoding(results);
Serial.println("");
// Show Code & length
Serial.print("Code : ");
ircode(results);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpRaw (decode_results *results)
{
// Print Raw data
Serial.print("Timing[");
Serial.print(results->rawlen-1, DEC);
Serial.println("]: ");
for (int i = 1; i < results->rawlen; i++) {
unsigned long x = results->rawbuf[i] * USECPERTICK;
if (!(i & 1)) { // even
Serial.print("-");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
} else { // odd
Serial.print(" ");
Serial.print("+");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
if (i < results->rawlen-1) Serial.print(", "); //',' not needed for last one
}
if (!(i % 8)) Serial.println("");
}
Serial.println(""); // Newline
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpCode (decode_results *results)
{
// Start declaration
Serial.print("unsigned int "); // variable type
Serial.print("rawData["); // array name
Serial.print(results->rawlen - 1, DEC); // array size
Serial.print("] = {"); // Start declaration
// Dump data
for (int i = 1; i < results->rawlen; i++) {
Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one
if (!(i & 1)) Serial.print(" ");
}
// End declaration
Serial.print("};"); //
// Comment
Serial.print(" // ");
encoding(results);
Serial.print(" ");
ircode(results);
// Newline
Serial.println("");
// Now dump "known" codes
if (results->decode_type != UNKNOWN) {
// Some protocols have an address
if (results->decode_type == PANASONIC) {
Serial.print("unsigned int addr = 0x");
Serial.print(results->address, HEX);
Serial.println(";");
}
// All protocols have data
Serial.print("unsigned int data = 0x");
Serial.print(results->value, HEX);
Serial.println(";");
}
}
//+=============================================================================
// The repeating section of the code
//
void loop ( )
{
decode_results results; // Somewhere to store the results
if (irrecv.decode(&results)) { // Grab an IR code
dumpInfo(&results); // Output the results
dumpRaw(&results); // Output the results in RAW format
dumpCode(&results); // Output the results as source code
Serial.println(""); // Blank line between entries
irrecv.resume(); // Prepare for the next value
}
}
動手做12-3 使用紅外線遙控器控制舵機
實驗說明:取得紅外線遙控器的控制代碼之後,你就可以用遙控器來控制Arduino,本例將示範通過紅外線遙控舵機。
實驗程式:將依據遙控器的左、右箭頭鍵,調整舵機的旋轉角度,以及“錄影”按鍵開啟或關閉板子上第13腳的LED。
#include <IRremote.h>
#include <Servo.h>
Servo servo;
const byte RECV_PIN = 11; //
const byte LED_PIN = 13; //
const byte SERVO_PIN = 8; //
boolean sw = false; //
byte servoPos = 90; //
IRrecv irrecv(RECV_PIN); //
decode_results results; //
void setup() {
irrecv.enableIRIn(); //
pinMode(LED_PIN, OUTPUT); //
servo.attach(SERVO_PIN); //
servo.write(servoPos); //
}
void loop() {
if (irrecv.decode(&results)) { //
switch (results.value) { //
case 0xC1C7C03F: //若此數值等於“錄影”
sw = !sw; //
digitalWrite(LED_PIN, sw); //
break;
case 0xC1C7C43B: //
if (servoPos > 10) { //
servoPos -= 10; //
servo.write(servoPos); //
}
break;
case 0xC1C744BB:
if (servoPos < 170) {
servoPos += 10; //
servo.write(servoPos); //
}
break;
}
irrecv.resume(); //
}
}
動手做12-4 從Arduino發射紅外線遙控電器
實驗說明: IRremote擴充套件庫也具備發射紅外線遙控訊號的功能,本單元將組裝一個Arduino紅外線遙控發射器,並從“串列埠監視器”指揮它來遙控家電
實驗電路: 根據IRremote擴充套件庫的設定,紅外線發射LED必須接在第3埠,而且最好先串聯一個330Ω電阻保護LED。
實驗程式: 使用IRremote擴張庫發射紅外線訊號之前,必須先宣告一個“I”型別的物件IRsend irsend;
,程式將通過此物件發射制定格式的訊號,以發出NEC紅外線為例,指令:irsend.sendNEC(紅外線編碼, 位數);
示例: 從串列埠獲得任何字元時,Arduino發射紅外線上面的訊號;
#include <IRremote.h>
IRsend irsend;
void setup(){
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
irsend.sendNEC(0xC1C7C03F, 32);
Serial.println("Action!");
}
}