ホーム > カテゴリ > ロボット・電子工作・マイコン >

赤外線リモコンを学習して送信する [Arduino]

テレビなどのリモコンの赤外線信号を「赤外線リモコン受信モジュール」(PL-IRM1261-C438)で取得して、ブレッドボードのボタンを押した時にその赤外線を「赤外線LED」(OSI5LA5113A)で送信します。

[TVを操作する例]

2017/7/6に記事を修正しました。

1. 使用部品・材料

総額で約500円です。(Arduino本体の値段を除く)

部品/材料値段備考
ブレッドボード¥270秋月電子の通販コード(P-00315)
赤外線リモコン受信モジュール PL-IRM1261-C438¥100秋月電子の通販コード(I-04169)
5mm赤外線LED OSI5LA5113A¥100秋月電子の通販コード(I-04311)
5mm赤色LED OSDR5113A¥20秋月電子の通販コード(I-11655)
タクトスイッチ¥10秋月電子の通販コード(P-03647)
カーボン抵抗器数円10kΩ(1個)、220Ω(2個)、47Ω(1個)を使用。
コネクタ付コード(みの虫×ジャンパーワイヤ)任意赤外線LEDの延長用。

秋月電子の通販コード(C-08916)
LED光拡散キャップ(5mm) 白 日本製任意赤外線LEDの送信用。(なくてもOK!)

秋月電子の通販コード(I-00641)

[上記外で動作確認済みの部品]

5mm赤外線LED OSI5FU5111C-40(5個入)¥100秋月電子の通販コード(I-03261)
GaAs赤外LED NJL1104B¥30秋月電子の通販コード(I-11570)

赤外線リモコン受信モジュール PL-IRM2121(38kHz)¥100秋月電子の通販コード(I-01570)

[動作しなかった部品]

5mm赤外線LED OSI3CA5111A¥150ピーク波長が原因(?)。使い方次第で動作するかも知れません。

秋月電子の通販コード(I-04779)
赤外線リモコン受信モジュール SPS-448-1(38kHz)¥30なんらかのデータは受信できますが、受信データがおかしいです。このSPSシリーズは相性が悪いのかも知れません。

秋月電子の通販コード(I-00872)
大面積Si PINフォトダイオードS6775-01(可視光カット)¥200これは上級者が使用する部品のようです。(今の私にはまだ扱えません)

秋月電子の通販コード(I-06183)

2. 配線図

3. スケッチ(プログラム)

今回はオープンソースの「Arduino-IRremote」という赤外線のライブラリを使用しますのでダウンロードします。

Arduino-IRremote (ダウンロード)

インストールする前に...

C:Program Files (x86)Arduinolibraries

にある「RobotIRremote」というライブラリのフォルダを丸ごと別のフォルダに移動します。これは同じ作者が作成しているので「IRremote.h」というヘッダファイルが重複してしまうからです。

インストール方法

Arduino IDEのメニューの[スケッチ][ライブラリをインクルード][ZIP形式のライブラリをインストール]を選択して、ダウンロードしたファイルを指定するだけです。

スケッチ

今回のスケッチはArduino IDEのメニューの[ファイル][スケッチ例][IRremote][IRrecord]を使用します。

...

なんですが、このスケッチ例には「送信処理に不具合」がありましたので修正版を公開します。

※元のコードは崩さずに160,170-172,175,181,182行目を追加。180行目のdelay(50)をdelay(100)に変更。

/*
 * IRrecord: record and play back IR signals as a minimal 
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * An IR LED must be connected to the output PWM pin 3.
 * A button must be connected to the input BUTTON_PIN; this is the
 * send button.
 * A visible LED can be connected to STATUS_PIN to provide status.
 *
 * The logic is:
 * If the button is pressed, send the IR code.
 * If an IR code is received, record it.
 *
 * Version 0.11 September, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = 11;
int BUTTON_PIN = 12;
int STATUS_PIN = 13;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(BUTTON_PIN, INPUT);
  pinMode(STATUS_PIN, OUTPUT);
}

// Storage for the recorded code
int codeType = -1; // The type of code
unsigned long codeValue; // The code value if not raw
unsigned int rawCodes[RAWBUF]; // The durations if raw
int codeLen; // The length of the code
int toggle = 0; // The RC5/6 toggle state

// Stores the code for later playback
// Most of this code is just logging
void storeCode(decode_results *results) {
  codeType = results->decode_type;
  int count = results->rawlen;
  if (codeType == UNKNOWN) {
    Serial.println("Received unknown code, saving as raw");
    codeLen = results->rawlen - 1;
    // To store raw codes:
    // Drop first value (gap)
    // Convert from ticks to microseconds
    // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
    for (int i = 1; i <= codeLen; i++) {
      if (i % 2) {
        // Mark
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
        Serial.print(" m");
      } 
      else {
        // Space
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
        Serial.print(" s");
      }
      Serial.print(rawCodes[i - 1], DEC);
    }
    Serial.println("");
  }
  else {
    if (codeType == NEC) {
      Serial.print("Received NEC: ");
      if (results->value == REPEAT) {
        // Don't record a NEC repeat value as that's useless.
        Serial.println("repeat; ignoring.");
        return;
      }
    } 
    else if (codeType == SONY) {
      Serial.print("Received SONY: ");
    } 
    else if (codeType == PANASONIC) {
      Serial.print("Received PANASONIC: ");
    }
    else if (codeType == JVC) {
      Serial.print("Received JVC: ");
    }
    else if (codeType == RC5) {
      Serial.print("Received RC5: ");
    } 
    else if (codeType == RC6) {
      Serial.print("Received RC6: ");
    } 
    else {
      Serial.print("Unexpected codeType ");
      Serial.print(codeType, DEC);
      Serial.println("");
    }
    Serial.println(results->value, HEX);
    codeValue = results->value;
    codeLen = results->bits;
  }
}

void sendCode(int repeat) {
  if (codeType == NEC) {
    if (repeat) {
      irsend.sendNEC(REPEAT, codeLen);
      Serial.println("Sent NEC repeat");
    } 
    else {
      irsend.sendNEC(codeValue, codeLen);
      Serial.print("Sent NEC ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == SONY) {
    irsend.sendSony(codeValue, codeLen);
    Serial.print("Sent Sony ");
    Serial.println(codeValue, HEX);
  } 
  else if (codeType == PANASONIC) {
    irsend.sendPanasonic(codeValue, codeLen);
    Serial.print("Sent Panasonic");
    Serial.println(codeValue, HEX);
  }
  else if (codeType == JVC) {
    irsend.sendJVC(codeValue, codeLen, false);
    Serial.print("Sent JVC");
    Serial.println(codeValue, HEX);
  }
  else if (codeType == RC5 || codeType == RC6) {
    if (!repeat) {
      // Flip the toggle bit for a new button press
      toggle = 1 - toggle;
    }
    // Put the toggle bit into the code to send
    codeValue = codeValue & ~(1 << (codeLen - 1));
    codeValue = codeValue | (toggle << (codeLen - 1));
    if (codeType == RC5) {
      Serial.print("Sent RC5 ");
      Serial.println(codeValue, HEX);
      irsend.sendRC5(codeValue, codeLen);
    } 
    else {
      irsend.sendRC6(codeValue, codeLen);
      Serial.print("Sent RC6 ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == UNKNOWN /* i.e. raw */) {
    // Assume 38 KHz
    irsend.sendRaw(rawCodes, codeLen, 38);
    Serial.println("Sent raw");
  }
}

int lastButtonState;
bool readyState = true;

void loop() {
  // If button pressed, send the code.
  int buttonState = digitalRead(BUTTON_PIN);
  if (lastButtonState == HIGH && buttonState == LOW) {
    Serial.println("Released");
    irrecv.enableIRIn(); // Re-enable receiver
  }

  if (!buttonState) {    
    readyState = true;  
  }
  
  if (buttonState) {
    if(readyState){
      Serial.println("Pressed, sending");
      digitalWrite(STATUS_PIN, HIGH);
      sendCode(lastButtonState == buttonState);
      digitalWrite(STATUS_PIN, LOW);
      delay(100); // Wait a bit between retransmissions
    }
    readyState = false;    
  } else if (irrecv.decode(&results)) {
    digitalWrite(STATUS_PIN, HIGH);
    storeCode(&results);
    irrecv.resume(); // resume receiver
    digitalWrite(STATUS_PIN, LOW);
  }
  lastButtonState = buttonState;

}

180行目のdelay()の時間は送信処理の要ですので、環境に合わせて適宜、変更してください。また、全ての形式の赤外線に対応しているわけではありませんのでご注意ください。

4. 抵抗値の計算(5mm赤外線LED)

Arduinoの電源は5V(V)。データシートに記載されている順方向電圧(DC Forward Voltage/VF)は標準1.35V。絶対最大定格(Absolute Maximum Rating)の最大電流(DC Forward Current)は100mA(IF)。電流を最大より少し下げて90mAとするとオームの法則で40.5Ωになります。

40.5Ω = (5V - 1.35V) / 0.090A

※今回は大きめに47Ωを使用しています。

5. 抵抗器の電力計算(5mm赤外線LED)

[公式]

抵抗が消費する電力(W) = I(A) x I(A) x R(Ω)

を元に計算すると

0.38W = 0.09A x 0.09A x 47Ω

0.38Wですので「1/2W」(0.5W)の抵抗器で良いように思えますが、実際はその2倍以上の1Wの抵抗器を使った方が安全です。





掲示板

ArduinoやRaspberry Piなどの電子工作の掲示板を作成しました。質問やわからない事は電子工作 (Arduino・ラズパイ等)でユーザー同士で情報を共有して下さい。

関連記事



公開日:2017年06月01日 最終更新日:2017年08月20日
記事NO:02407