1. 程式人生 > >12.紅外線遙控與間隔拍攝控制器

12.紅外線遙控與間隔拍攝控制器

認識紅外線

可見光、紅外線和電波,都是電磁波的一種,
遠紅外線和近紅外線,人體在常溫下所釋放的紅外線波長約10um(微米)。靠近可見光部分的近紅外線,幾乎不會散發熱能,通常用於紅外線通訊、遙控和距離感測器。

人體紅外線感測器

感測器上頭的白色半透明PE透鏡黏在電路板上,裡面有一個熱釋電型感測器,熱釋電(pyroelectric)代表該模組會隨著溫度變化產生電子訊號。感測器模組上的IC電路將會接收並處理感測器訊號,以高電位或低電位的形式輸出。人體紅外線偵測模組,相當於電子開關,平常輸出低電位(0V),偵測到人體移動時,變成高電位(3.3V)。
此感測器全名為被動式(Passive)紅外移動感測器

,紅外線(Infrared)英文簡稱IR,所以此感測器又稱為PIR移動感測器,一般通稱為“人體紅外線感測器”,所謂“被動式”偵測,代表這種感測器跟超聲波感測器不同,它不會發出偵測訊號,而是被動地接收紅外線源。這種感測器內部有兩個偵測“視窗”,被偵測物體必須要水平移動,它才能比較出紅外線的變化,若朝向它的正面移動,就比較不容易被偵測到。
熱釋電型感測器,熱釋電(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!");
    }
}