SSブログ

赤外線リモコン (解析の友) [Arduino]

赤外線リモコンの信号を可視化してデータを抽出する手助けをするスケッチです。
初心者の汚いソースですみません。
ATmega328 でないとRAMが足りないみたいです。
霧ヶ峰のリモコンも家電協フォーマットで読み込めました。
なるべくリピート信号を読み込まないようにリモコンのボタンはポンッと瞬間的に押すといいみたいです。
irkirigamine.jpg
赤外線リモコン受信モジュールは写真のようにArduinoに直刺しとしました。
// IR解析スケッチ
#define IR_IN   2          // IR Receiver

#define NEC    1
#define AEHA   2
#define SONY   3

#define BUF_SIZE   (512)    // ATmega168だと 128くらいにしないと不具合

void setup()  { 
  pinMode( IR_IN , INPUT );                        // Vout  ->   digital 2
  pinMode( 3, OUTPUT );  digitalWrite( 3,  LOW );  // GND   ->   digital 3 LOW
  pinMode( 4, OUTPUT );  digitalWrite( 4, HIGH );  // Vcc   ->   digital 4 HIGH
  Serial.begin(115200);
}

void loop() {
  unsigned long usec, nec_data = 0;
  unsigned int i, n, irOffTime, minTime, aveCnt = 0, aveAdd = 0;
  unsigned int irdata[ BUF_SIZE ], timeunit, leaderH, leaderL, datalen;
  unsigned int format = 0, hex = 0, sony_data = 0, sony_adrs = 0,  sony_adrs_bit = 0;
  boolean isvalid = true;
  // ● 赤外線を感知するまで待つ
  while( digitalRead( IR_IN ) == HIGH );
  // ● 生データの取得
  for( i=0; i < BUF_SIZE; ) {
    usec = micros();
    while( digitalRead( IR_IN ) == LOW );           // IR信号がONの時間を測定
    irdata[  i] = micros() - usec;
    irdata[++i] = 0;
    usec = micros();
    while( digitalRead( IR_IN ) == HIGH ) {         // IR信号がOFFの時間を測定
      irOffTime = micros() - usec;
      if( irOffTime > 65000 ) goto ir_exit;         // 信号途絶なら終了
    }
    irdata[i++] = irOffTime;
  }
  ir_exit:
  Serial.println( "<< IR data analyser >>" );
  // ● 時間単位を調べる
  minTime = irdata[0];                    // まず最小値を確認
  for( i=0; irdata[i]; i++) minTime = min( minTime, irdata[i]);
  for( i=0; irdata[i]; i++) {             // 最小値の+50%までを時間単位とする
    if( minTime * 3 / 2 > irdata[i] ) { aveAdd += irdata[i] - minTime;  aveCnt++; }
  }
  timeunit = aveAdd / aveCnt + minTime;
  if( timeunit < 300 ) return;            // 時間単位が短すぎるときは異常と判断
  // ● 時間単位でのデータに変換
  for( i=0; irdata[i]; i++) irdata[i] = ( irdata[i] + timeunit / 2 ) / timeunit;
  // ● 赤外線の波形を表示
  for( i=0; irdata[i]; i++) for( n=0; n < irdata[i]; n++) Serial.print( (i % 2) ? "_":"|" );
  Serial.println( "." );  
  // ● 解析しやすくするためにデータの整理
  leaderH = irdata[0];                // リーダ部Highの長さ
  leaderL = irdata[1];                // リーダ部Low の長さ
  for( i=0;; i+=2) {                  // データ解析用にリーダ部とリピートを除去・整理
    irdata[i] = irdata[i+2];  irdata[i+1] = irdata[i+3];
    if( irdata[i+1] > 10 || irdata[i+1] == 0 ) { irdata[i+1] = 0;  datalen = i / 2 + 1;  break;  }
  }
  // ● 各種基本データを表示
  Serial.print( "Time Unit (usec) : ");  Serial.println( timeunit , DEC );
  Serial.print( "Leader  (On/Off) : ");
  Serial.print( leaderH, DEC );  Serial.print(  " / " );  Serial.println( leaderL, DEC );
  // ● リーダ部の長さでフォーマットを判断
  Serial.print( "Format           : ");
  if((leaderH > 14 || leaderH < 18) && leaderL == 8 ) { format = NEC;  Serial.println( "NEC"  ); }
  else if           ( leaderH == 8  && leaderL == 4 ) { format = AEHA; Serial.println( "AEHA" ); }
  else if           ( leaderH == 4  && leaderL == 1 ) { format = SONY; Serial.println( "SONY" ); }
  else  Serial.println( "???" );
  // ● フォーマット毎に結果を表示
  switch( format ) {                
    case 0:        // ■ 不明な形式の場合
      Serial.println( " !! Analysing as NEC format !!");
    case NEC:      // ■ NECフォーマット
      Serial.print( "Binary data      : (LSB)");
      for( n=0; n < datalen - 1; n++) {  // ストップビット手前まで繰り返し
        if( n % 8 == 0) Serial.print(" ");
        if( irdata[n*2]   != 1)                       { Serial.print("?"); isvalid = false; continue; }
        if( irdata[n*2+1] != 1 && irdata[n*2+1] != 3) { Serial.print("?"); isvalid = false; continue; }
        Serial.print((irdata[n*2+1]==1) ? "0" : "1" );
        nec_data |= ( (irdata[n*2+1]==1) ? 0UL : 1UL ) << n;
      }
      Serial.println(" (MSB)");
      if( !isvalid ) break;    // データに不具合があれば以降は表示しない
      Serial.print( "Custom code      : ");  printlnHexcode(  nec_data        % 256 );
      Serial.print( "Custom code '    : ");  printlnHexcode( (nec_data >>  8) % 256 );
      Serial.print( "Data code        : ");  printlnHexcode( (nec_data >> 16) % 256 );
      Serial.print( "Data code (nega) : ");  printlnHexcode( (nec_data >> 24) % 256 );
      break;
    case AEHA:     // ■ 家電協フォーマット
      Serial.print( "Binary data      : (LSB)");
      for( n=0; n < datalen - 1; n++) {  // ストップビット手前まで繰り返し
        if( n % 4 == 0) Serial.print(" ");
        if( irdata[n*2]   != 1)                       { Serial.print("?"); isvalid = false; continue; }
        if( irdata[n*2+1] != 1 && irdata[n*2+1] != 3) { Serial.print("?"); isvalid = false; continue; }
        Serial.print((irdata[n*2+1]==1) ? "0" : "1");
      }
      Serial.println(" (MSB)");
      if( !isvalid ) break;    // データに不具合があれば以降は表示しない
      Serial.print( "Hexadecimal data : (LSB) ");
      for( n=0; n < datalen; n++) {
        hex |= ((irdata[n*2+1]==1)? 0:1) << (n%4);
        if( n % 4 == 3) {  Serial.print(hex, HEX); Serial.print("    "); hex = 0; }
      }
      Serial.println("(MSB)");
      break;
    case SONY:     // ■ SONYフォーマット
      Serial.print( "Binary data      : (LSB) ");
      for( n=0; n < datalen; n++) {
        if( irdata[n*2+1] != 0 && irdata[n*2+1] != 1) { Serial.print("?"); isvalid = false; continue; }
        if( irdata[n*2]   != 1 && irdata[n*2]   != 2) { Serial.print("?"); isvalid = false; continue; }
        Serial.print( irdata[n*2]-1 );
        if( n == 6 ) Serial.print(" ");
        if( n <  7 ) sony_data |= (irdata[n*2]-1) << n;
        else         sony_adrs |= (irdata[n*2]-1) << sony_adrs_bit++;
      }
      Serial.println(" (MSB)");
      if( !isvalid ) break;    // データに不具合があれば以降は表示しない
      Serial.print( "Data (7bit)      : ");  printlnHexcode( sony_data );
      Serial.print( "Adress bits (bit): ");  Serial.print( sony_adrs_bit ); Serial.println( " bit" );
      Serial.print( "Adress           : ");  printlnHexcode( sony_adrs );
      break;
  }
  // ● 以上で終了
  Serial.println("");
}

void printlnHexcode(unsigned int d) {    // 16進数を見栄えよく表示、改行
  Serial.print( ( d < 0x10 ) ? "0x0" : "0x" );
  Serial.print( ( d < 0x1000 && d > 0xff ) ? "0" : "" );
  Serial.println( d, HEX);
}

シリアルモニターに結果を表示します。
kirigamine.png



nice!(1)  コメント(3)  トラックバック(1) 

nice! 1

コメント 3

たくぼん

はじめまして。たくぼんともうします。
Arduino Pro Mini 328でコードの一部を使わせていただきまして,
apple remoteの解析をすることができました。
SD TransというSDカードプレーヤーに赤外線リモコンをつけようと思います。
こちらのwebのプログラムを引用した旨を明記しまして私のapple remoteのスケッチをblogに公開させていただいてもよろしいでしょうか。
by たくぼん (2012-10-01 23:14) 

kenkenpa

どうもこんにちは。
お見苦しいスケッチですが、使っていただいてありがとうございます。
自由に使っていただいて結構です。
by kenkenpa (2012-10-10 18:16) 

お名前(必須)んんん

みやみりゆり
by お名前(必須)んんん (2017-04-29 21:32) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 1

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。