2019年8月8日木曜日

[Elegoo:14] 赤外線ワイヤレスリモコンと
赤外線受信モジュール


概要 (Overview)
  • 赤外線リモコンのコードフォーマットについて学ぶ
  • 赤外線ワイヤレスリモコンからのコードを赤外線受信モジュールで受信し、
    シリアルモニタに表示する



参照 (Reference)
赤外線とは
  • 可視光線の赤色より波長が長く電波より波長の短い電磁波の一種
  • ヒトの目では見られない光
  • 分光学などの分野で IR (infrared) と略称される
波長による電磁波の分類(nm:ナノメートル)
マイクロ波・短波・ラジオ波・携帯通信網 等
1,000nm
|赤外線
760nm
可視光線 (光の3原色(青/緑/赤)の波長範囲)

紫外線(10-380nm)
380nm

X線(0.01-10nm)
短ガンマ線(0.01nm以下)
0nm

赤外線リモコン
  • 赤外線LEDの点灯・消灯を切り替えて命令を送っている
  • また太陽や照明など他の光と区別するために、 大抵の赤外線リモコンは発光する周波数を38KHzと設定している
  • 国内製のほとんどの家電の赤外線リモコンは下記3種類の代表的な
    赤外線リモコンコードフォーマットを採用している
    1. NEC方式(映像音響機器)
      => NEC,TOSHIBA,HITACHI,SANYO,JVCなど
    2. 家電製品協会(AEHA)方式(生活家電機器)
      => PANASONIC,SHARP,YAMAHAなど
    3. 独自方式
      => SONYなど
  • 赤外線リモートライブラリ を利用すると国内・海外製の家電フォーマットを使用できる
    =>NEC, SONY, SANYO, MITSUBISHI, RC5, RC6, DISH, SHARP, PANASONIC, JVC, LG, AIWA_RC_T501
  • 国内製ではフォーマットやベンダーコードが重複しないよう配慮され、信号内容の違いにより混信や誤動作を防いでいる。海外製ではこのフォーマットに配慮しないで製造されたものもあり、輸入された家電品が日本製の別の機器に付属するリモコンの信号で誤動作するものがある



使用する電子部品 (Component Required)
電子種別電子部品個数
マイコン Elegoo UNO R3 マイコンボード1
USBケーブル1
能動 赤外線ワイヤレスリモコン1
赤外線受信モジュール1
機構 赤外線ジャンプワイヤ(赤)[オス-メス]1
赤外線ジャンプワイヤ(黒)[オス-メス]1
赤外線ジャンプワイヤ(黄)[オス-メス]1



電子部品について (Component Introduction)
赤外線受信モジュール

  • IR受信機は赤外線を受信するように調整されたフォトセルを備えており、 赤外線リモコンコードをデコードする。殆どリモコンの検出に使用される
  • 38KHzで変調された赤外線を探す復調器があり太陽光や照明等他の光と区別する
  • 周波数のピークは38HkzでLED色のピークは940nm(900-1000)
  • IR LEDのデータシートで波長を確認すること
《ピン》
GND(G)GND
Vcc(R)電源入力(5V or 3V)
DATA(Y)DATA



電子回路 (Electronic Circuit)
回路図 (Schematic)


実体配線図 (Wiring Diagram)





実践 (To Practice)
配線写真 (Example Picture)


プログラム (Code)

赤外線リモコンコードフォーマット[国内製]
IR_Receiver.ino:日本国内の殆どの家電をカバー [nT]:パルスON/OFFの長さ(変調単位時間T)
方式時間(T) リーダー部/ リピート送信 DATA[BIT]0の時1の時 STOP(データ終了)
NEC562u[sec] ON(16T)+OFF(8T)/ ON(16T)+OFF(4T) ON(1T)+OFF(1T)/ ON(1T)+OFF(3T) ON(1T)
AEHA425u[sec] ON( 8T)+OFF(4T)/ ON( 8T)+OFF(8T) ON(1T)+OFF(1T)/ ON(1T)+OFF(3T) ON(1T)
SONY600u[sec] ON( 4T)[+OFF(1T)]/ - ON(1T)+OFF(1T)/ ON(2T)+OFF(1T) -

DATA[]:
NEC :32ビット固定長(データ送信時)、なし(リピート送信時)
AEHA :可変長(データ送信時)、なし(リピート送信時)
SONY :可変長, ヘッダー部を含め同じコードを3回送る(間隔:45ms)

スケッチ
/*************************************************************/
/* 【 Elegoo:14 】赤外線ワイヤレスリモコンと赤外線受信モジュール */
/*    赤外線ワイヤレスリモコンからのコードを                     */
/*    赤外線受信モジュールで受信し、                            */
/*    シリアルモニタに表示する                                 */
/*                                                           */
/*   赤外線リモコンコードフォーマット使用 [国内製]               */
/*************************************************************/

int pin = 11;           //受信モジュール出力の信号入力ピン
int num = 0;
unsigned long st;       //計測開始時間μs
unsigned long dur;      //時間μs
int num_max = 400;      //配列要素数
long time[400];         //num_maxと同じに
boolean mode = HIGH;    //赤外線モジュール出力がHIGHの待機から始まる
long timeout = 120000;  //無受信時のタイムアウトμs

/*********/
/* setup */
/*********/
void setup() {
  Serial.begin(9600);
  pinMode(pin, INPUT);
}

/********/
/* loop */
/********/
void loop() {

  // --------------------------------------------------
  //計測開始の時間を記憶
  st = micros();
  //LOW,HIGHが変化するまでループで待機
  while(digitalRead(pin) == mode){    
    //無受信時のタイムアウトでループを抜ける
    if(micros() - st > timeout){
      break;
    }
  }

  // --------------------------------------------------
  // 時間を計算
  dur = micros() - st;
  if(mode == LOW){
    time[num] = dur;
  }
  else{
    //LEDオフの時間(受信センサー出力はHIGH)はマイナス符号をつける
    time[num] = dur * -1;
  }

  // --------------------------------------------------
  // タイムアウトした時
  if(dur > timeout){
    //配列に格納されていれば、シリアル出力
    if(num > 0){
      ser_pri();
    }
    //タイムアウトかつデータ無しなので変数リセット
    num = -1;
    mode = LOW;
  }

  // --------------------------------------------------
  // データが多すぎた時の処理
  num += 1;
  mode =! mode;
  if(num == num_max){
    Serial.println("Too Many Data");
    delay(2000);
    ser_pri();
    num = 0;
    mode = HIGH;
  }
}

/*********************/
//受信データのシリアル出力
/*********************/
void ser_pri(){
  int data = 0;
  Serial.println("");

//  //配列のデータをそのまま出力
//  for(int i = 0; i < num; i++){
//    Serial.print(i);
//    Serial.print("\t");
//    Serial.println(time[i]);
//  }

  // --------------------------------------------------
  // メーカーフォーマットを判別
  // リーダー部のON-OFF時間+-1Tの範囲で判別
  // [ 1:NECフォーマット2:家電製品協会(AEHA)フォーマット3:ソニーフォーマット0:不明 ]
  // NEC:T=562 leader 16T+8T repeat 16T+4T
  // 家電製品協会:T=425 leader 8T+4T repeat 8T+8T
  // ソニー:T=600 leader 4T
  // --------------------------------------------------
  Serial.println("");
  byte data_f = 0;

  // --------------------------------------------------
  // NECフォーマット
  if(time[1] >= 8430 && time[1] < 9554 && time[2]*-1 >= 3934 && time[2]*-1 < 5058){
    Serial.println("NEC Format");
    data_f = 1;
  }
  // --------------------------------------------------
  // 家電製品協会フォーマット
  if(time[1] >= 2975 && time[1] < 3825 && time[2]*-1 >= 1275 && time[2]*-1 < 2125){
    Serial.println("AEHA Format");
    data_f = 2;
  }
  // --------------------------------------------------
  // SONYフォーマット
  if(time[1] >= 1800 && time[1] < 3000 && time[2]*-1 < 600){
    Serial.println("SONY Format");
    data_f = 3;
  }
  // --------------------------------------------------
  // フォーマット不明
  if(data_f == 0){
    Serial.println("UNKNOWN Format");
  }
 
 // --------------------------------------------------
  //NECフォーマットの時
  // --------------------------------------------------
  if(data_f == 1){
    byte dig = 0;
    for(int j = 4; j < num; j=j+2){
      if(time[j]* -1  < 1000){
        Serial.print("0");
      }
      if(time[j]* -1 >=1000 && time[j]* -1 <1800 ){
        Serial.print("1");
        bitSet(data,dig);
      }

      //リピートコード
      if(time[j]* -1 >=1800 && time[j]* -1 <2500){
        //4つ前のデータもリピートコードかどうか
        if((time[j-4]* -1 >=1800) && (time[j-4]* -1 <2500)){
          Serial.print(" .");
        }
        else{
          Serial.print("REPEAT CODE");
        }
        dig = 0;
      }
      dig += 1;

      //8ビットごとに区切り
      if(dig == 8){
        Serial.print("\t");
        Serial.print(data,HEX);
        Serial.println("");
        dig = 0;
        data = 0;
      }
    }
  }

  // --------------------------------------------------
  // 家電製品協会フォーマットの時
  // --------------------------------------------------
  if(data_f == 2){
    byte dig = 0;
    for(int j = 4; j < num; j=j+2){
      if(time[j]* -1  < 1000){
        Serial.print("0");
      }
      if(time[j]* -1 >=1000 && time[j]* -1 <1800 ){
        Serial.print("1");
        bitSet(data,dig);
      }
      
      //リピートコード
      if(time[j]* -1 >=2975 && time[j]* -1 <3825){
        //4つ前のデータもリピートコードかどうか
        if((time[j-4]* -1 >=2975) && (time[j-4]* -1 <3825)){
          Serial.print(" .");
        }
        else{
          Serial.print("REPEAT CODE");
        }
        dig = 0;
      }

      //同信号繰り返し
      if(time[j]* -1 >=2000){
        Serial.println("REPEAT");
        j += 2;
        dig = -1;
      }
      dig += 1;

      //8ビットごとに区切り
      if(dig == 8){
        Serial.print("\t");
        Serial.print(data,HEX);
        Serial.println("");
        dig = 0;
        data = 0;
      }
    }
  }

  // --------------------------------------------------
  // ソニーフォーマットの時
  // --------------------------------------------------
  if(data_f == 3){
    byte dig = 0;
    boolean sony_func = 0;
    for(int j = 3; j < num; j=j+2){
      if(time[j]  < 1000){
        Serial.print("0");
      }
      if(time[j] >=1000 && time[j] < 1800 ){
        Serial.print("1");
        bitSet(data,dig);
      }

      //同信号繰り返し
      if(time[j] >= 2000){
        Serial.print("\t");
        Serial.print(data,HEX);
        Serial.println("");
        Serial.println("REPEAT");
        dig = -1;
        data = 0;
        sony_func = 0;
      }
      dig += 1;

      //最初の7ビットが機能コード、以下5~13ビットは機器識別コード
      if(dig == 7 && sony_func == 0){
        sony_func = 1;
        Serial.print("\t");
        Serial.print(data,HEX);
        Serial.println("");
        dig = 0;
        data = 0;
      }
    }
    Serial.print("\t");
    Serial.print(data,HEX);
    data = 0;
  }

  // --------------------------------------------------
  // フォーマット不明の時
  // --------------------------------------------------
  if(data_f == 0){
  }

  Serial.println("");
}

赤外線リモートライブラリ使用 [国内・海外製]

書式引数説明
IRrecv objIRrecv(int PinNO) objIRrecv:IRrecvオブジェクト
PinNO:ピンNO
IRrecvオブジェクトを作成してピンを割り当てる
objIRrecv.enableIRIn() - 受信を開始
objIRRecv.blink13(true/false) true/false:許可/不可 受信時にLEDの点灯を許可する
decode_results results results :受信結果 受信結果の格納先を作成
受信結果
decode_typeメーカー名
value受信データ
bits受信ビット数
rawbuf[]赤外線ON/OFFの切替時間(μ秒)の配列
rawlen赤外線のON/OFF回数
int objIRrecv.decode(&results) &results :受信結果 受信したコードがある場合は1を返しそれ以外の場合は0を返す
int objIRrecv.resume() .decode()の返り値をリセット

スケッチ
/*************************************************************/
/* 【 Elegoo:14 】赤外線ワイヤレスリモコンと赤外線受信モジュール */
/*    赤外線ワイヤレスリモコンからのコードを                     */
/*    赤外線受信モジュールで受信し、                            */
/*    シリアルモニタに表示する                                 */
/*                                                           */
/*   赤外線リモートライブラリ使用 [国内・海外製]                */
/*************************************************************/

/*--------------------------------------------*/
/* 赤外線リモートライブラリ                     */
/*--------------------------------------------*/
#include <irremote .h> //Ver2.0.1 June, 2015 Panasonic受信不安定

/*--------------------------------------------*/
// 受信用
#define PIN_RECEIVER 11           // 赤外線受信用ピン 
IRrecv objIRRecv(PIN_RECEIVER);   // 赤外線受信用オブジェクトを作成
decode_results objResults;        // 赤外線受信結果を格納する


/**************************************/
/* 関数名:getDecodeTypeValue          */
/*  内容:受信したType(メーカー)を取得する */
/*  引数:無し                         */
/* 戻り値:無し                         */
/**************************************/
void  getDecodeTypeValue(){

  Serial.print(objResults.decode_type); Serial.print(" : ");

  // --------------------------------------------------
  switch (objResults.decode_type) {
    default:
    case UNKNOWN:      Serial.print("UNKNOWN");       break ;
    case NEC:          Serial.print("NEC");           dispIRcodeNEC(); 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 : Address[");
                       Serial.print(objResults.address, HEX);
                       Serial.print("]");             break ;
    case DENON:        Serial.print("Denon");         break ;
//    case AEHA:          Serial.print("AEHA");           break ;
//    case AEHA:         Serial.print("AEHA : Address[");
//                       Serial.print(objResults.address, HEX);
//                       Serial.print("]");             break ;
  }

}

/*************************************************/
/* 関数名:dispIRcodeNEC                          */
/*  内容:受信したType[NEC]のValue(IRcode)を表示する */
/*  引数:無し                                    */
/* 戻り値:無し                                    */
/*************************************************/
void dispIRcodeNEC() {
  Serial.print(" : "); Serial.print(objResults.value, HEX);
  Serial.print(" ==> ");

  if( objResults.decode_type == NEC ){
    // 受信したValue(IRcode)
    switch(objResults.value){
      case 0xFFA25D:    Serial.println("POWER");        break;
      case 0xFFE21D:    Serial.println("FUNC/STOP");    break;
      case 0xFF629D:    Serial.println("VOL+");         break;
      case 0xFF22DD:    Serial.println("FAST BACK");    break;
      case 0xFF02FD:    Serial.println("PAUSE");        break;
      case 0xFFC23D:    Serial.println("FAST FORWARD"); break;
      case 0xFFE01F:    Serial.println("DOWN");         break;
      case 0xFFA857:    Serial.println("VOL-");         break;
      case 0xFF906F:    Serial.println("UP");           break;
      case 0xFF9867:    Serial.println("EQ");           break;
      case 0xFFB04F:    Serial.println("ST/REPT");      break;
      case 0xFF6897:    Serial.println("0");            break;
      case 0xFF30CF:    Serial.println("1");            break;
      case 0xFF18E7:    Serial.println("2");            break;
      case 0xFF7A85:    Serial.println("3");            break;
      case 0xFF10EF:    Serial.println("4");            break;
      case 0xFF38C7:    Serial.println("5");            break;
      case 0xFF5AA5:    Serial.println("6");            break;
      case 0xFF42BD:    Serial.println("7");            break;
      case 0xFF4AB5:    Serial.println("8");            break;
      case 0xFF52AD:    Serial.println("9");            break;
      case 0xFFFFFFFF:  Serial.println(" REPEAT");      break;  
      default:          Serial.println(" other button");
    }
  }

  Serial.println(" ");
  delay(500);
}

/********/
/* loop */
/********/
void loop() {

  // 赤外線を受信
  if (objIRRecv.decode(&objResults)) {
    // 受信したType(メーカー)とValue(ボタン)を表示する
    getDecodeTypeValue();
    // 受信機をリセット
    objIRRecv.resume(); 
  }  
}

/*********/
/* setup */
/*********/
void setup() {
  // --------------------------------------------------
  // シリアルモニタ開始
  Serial.begin(9600);

  // --------------------------------------------------
  // 受信を開始
  objIRRecv.enableIRIn();
  // 受信時にLEDの点灯を許可する
  objIRRecv.blink13(true);
}

結果(動画)・モニタリング
リモコンの上段①POWER②VOL+③FUNC/STOPボタン押下


赤外線リモコンコードフォーマット[国内製]

赤外線リモートライブラリ使用 [国内・海外製]
  • 他のメーカーのリモコンも試したが、メーカーとフォーマットが一致するとは限らない様子
  • 電子工作でリモコンによる赤外線通信を行う場合は以下の手順が良さそう
    ①上記スケッチで使用するリモコンのメーカーとIR Codeを調査
    ②その結果(メーカーとIR Code)を利用して制御する

0 件のコメント:

コメントを投稿