赤外線リモコン (解析の友)
赤外線リモコンの信号を可視化してデータを抽出する手助けをするスケッチです。
初心者の汚いソースですみません。
ATmega328 でないとRAMが足りないみたいです。
霧ヶ峰のリモコンも家電協フォーマットで読み込めました。
なるべくリピート信号を読み込まないようにリモコンのボタンはポンッと瞬間的に押すといいみたいです。

赤外線リモコン受信モジュールは写真のようにArduinoに直刺しとしました。
シリアルモニターに結果を表示します。

初心者の汚いソースですみません。
ATmega328 でないとRAMが足りないみたいです。
霧ヶ峰のリモコンも家電協フォーマットで読み込めました。
なるべくリピート信号を読み込まないようにリモコンのボタンはポンッと瞬間的に押すといいみたいです。

赤外線リモコン受信モジュールは写真のように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);
}
シリアルモニターに結果を表示します。

この記事へのコメント
Arduino Pro Mini 328でコードの一部を使わせていただきまして,
apple remoteの解析をすることができました。
SD TransというSDカードプレーヤーに赤外線リモコンをつけようと思います。
こちらのwebのプログラムを引用した旨を明記しまして私のapple remoteのスケッチをblogに公開させていただいてもよろしいでしょうか。
お見苦しいスケッチですが、使っていただいてありがとうございます。
自由に使っていただいて結構です。