ビュートローバーH8をテレビリモコンで動かす

ビュートローバーH8を、既存のテレビリモコンで動かします。
これを実現するために、以下のことをおこないます。
また、回路はブレットボードを使用して制作します。

ビュートローバーH8に赤外線受信回路を制作する

■ 全景

まず赤外線ロボットカーにするため、赤外線受信回路を作成します。
この図では、以下の物を使用しました。

・ビュートローバーH8本体
・ブレットボード
・電子回路パーツ 赤外線受信モジュール(OSRB38C9AA)
・電子回路パーツ 抵抗・コンデンサ

■ テレビリモコン

市販のマルチテレビリモコンです。
この手の機種は、各メーカーのテレビリモコンとして、 使用するために、 ボタンを押下したときの送信コードをカスタマイズできます。 今回はNECのアナログテレビに設定しました。 (メーカーコード 009)
ボタン押下時に送信されるコード

・[2] 04fb12xx
・[4] 04fb14xx
・[5] 04fb15xx
・[6] 04fb16xx
・[8] 04fb18xx

■ 赤外線受信回路

赤外線受信モジュール(OSRB38C9AA)を、ポートP14、P12に接続します。 P14は割り込み用、P12はレベル判定に使用します。

■ 回路配置図(上部から)

■ 回路配置図(側面から)

■ 赤外線の37.9Hzの周波数

リモコンに使用される赤外線の周波数は、 37.9KHzから38KHzです。 この素子(OSRB38C9AA)は、37.9HHzでした。 また、波長は940nmです。
そして、デューティは1/3です。

■ 赤外線送信フォーマット

赤外線リモコンのフォーマットは主なもので3種類あります

・NECフォーマット
・家電協フォーマット
・Sonyフォーマット

赤外線通信のフォーマットは、送信・受信で同じものであればよく
完全オリジナルでも通信できました。
今回は既存のテレビリモコンを使用している為、
今回のテレビリモコンで使用できるNCEフォーマットを使用しています。

全体は、以下のような構成です。
・リーダー部
・データ(4byte)
・ストップビット(2bit)
リーダー部は、9msの波形と4.5msの無信号部です。
データは、4byteで、カスタムコード2byte, データ、 反転データで構成されています。

1 byte目 カスタムコード1byte(2byteでメーカーコードを構成)
2 byte目 カスタムコード2byte
3 byte目 送信データ
4 byte目 送信データを全bit反転したもの

今回は、リモコンメーカーコードは、04fbでした。

■ 赤外線受信フォーマット

受信モジュールでは、波形の出力時はLOW、 無信号部はHIGHの出力をします。

データ部の '0'および'1'の判断を、 受信モジュールの出力の値で判断します。
波形立ち上がり('0'から'1'になる部分)から、 1ms後にLOWならば '0'、HIGHならば '1' と判断します。

■ 赤外線受信のコードの抜粋(C言語)


/* ********************************* */
/*  赤外受信                       */
/* ********************************* */
void IR_Recive(void)
{
    volatile unsigned long wcnt ;       //波形時間計測カウンター

    //割り込み初期処理
    IENR1.BIT.IEN0  =   0;          // 割り込み禁止(IRQ0)
    ////////////////////////////////////////
    // リーダ部のチェックを行う
    if (IO.PDR1.BIT.B2 == 0) {
        wcnt = 0 ;      //波形時間計測カウンタークリア
        while (IO.PDR1.BIT.B2 == 0) {   // HIGHになるまで繰返す(9ms)
            ir_wait_11us() ;            // ----LOW---->
            wcnt++ ;                    // 波形時間計測カウンターUP
        }
    }
    // リーダ部でないデータなら終了(9ms以下)
     if (wcnt < 300) { //実測値で修正 
                       // ir_wait_11us() は11usウエイト
        IRR1.BIT.IRRI0  =   0;          // 割り込みフラグクリア
        IENR1.BIT.IEN0  =   1;          // 割り込み可(IRQ0)
        return;
     }
            
    //データ部取得処理
    IR_ReciveProc();

    //割り込み終了処理
    IRR1.BIT.IRRI0  =   0;          // 割り込みフラグクリア
    IENR1.BIT.IEN0  =   1;          // 割り込み可(IRQ0)
}

/* ********************************* */
/*  赤外受信                       */
/* ********************************* */
void IR_ReciveProc(void)
{
    volatile unsigned long wcnt ;       //波形時間計測カウンター
    volatile unsigned char IRData;      //受信データ(bit単位で受信)
    volatile unsigned char bitData;     //受信データmask値
    volatile int DataCnt;               //データ部受信ビット数
    
    volatile int  iPackCnt;             // 受信バイト数 

    wcnt    = 0;    // 波形時間計測カウンタークリア
    
    while(IO.PDR1.BIT.B2 == 1) {        // LOWになるまで繰返す(4.5ms)
        ;                               // ---- HIGH ----
    }   
    
    ////////////////////////////////////////
    // データ部をバイト数分繰り返す
    iPackCnt = 0;   // 受信バイト数0クリア
    memset(IRBuff, '\0', sizeof(IRBuff));   //受信バッファクリア
    IRBuffCnt = 0;  // 受信バッファカウントクリア
    for( ;iPackCnt < 4  ; iPackCnt++ ) {

        ////////////////////////////////////////
        // データ部の読み込み(LSBから受信する)
        IRData  = 0x00;             // 受信データクリア
        bitData = 0x01;             // LSBから順に受信するmask値 
        DataCnt = 0;                // データ部受信ビット数クリア 
        while (1) {
            while(IO.PDR1.BIT.B2 == 0) { // LOW部分は読み飛ばす(560us)
                ;                        // ---- LOW ----
            }
            wcnt = 0 ;
            while(IO.PDR1.BIT.B2 == 1) { // HIGH部分の長さをはかる
                ir_wait_11us() ;         // ---- LOW ----
                wcnt++ ;
            }
            if (wcnt >= 50) {       // HIGHの部分が1ms以上あれば 92
                IRData |= bitData;  //データ1
            }
            bitData <<= 1;   // LSBからMSBへシフトしながらデータ設定
            DataCnt++ ;      // データ部受信ビット数カウントアップ
        
            if (DataCnt == 8){ 
                ir_wait_11us() ;
                break ;      // 8bit読込んだら終了
            }
        }
        IRBuff[iPackCnt] = IRData;
        if (ToutFlg == 1) {   //タイムアウトしたら8bit以下でも終了
            break;
        }
    }
    //Stopビット読み込み
    // Highでストップビット読み込みとする
    
    wcnt = 0 ;
    while(IO.PDR1.BIT.B2 == 0) {    // LOW部分は読み飛ばす(560us)
        ir_wait_11us() ;            // ---- LOW ----
        wcnt++ ;
    }
    wcnt = 0 ;
    while(IO.PDR1.BIT.B2 == 0) {    // HIGH部分は読み飛ばす(560us)
        ir_wait_11us() ;            // ---- LOW ----
        wcnt++ ;
    }   
    main_IRData = IRBuff[2];        //3バイト目をデータとして設定   
    iPackCnt = 0;   // 受信バイト数0クリア 
}

波形立ち下がり('1'から'0'になる部分)に、 P14の割り込み(IRQ0)が発生します。

直後にP12のレベルを判断して、LOWの時間が9ms以下ならば、 処理を終了します。 これは、誤信号の時に処理をしない為に用いられているようです。

その後、4byte(32bit)分受信して、2bitのストップビットを受信します。
4byteのカスタムコードの内、3byte目にデータがあるので、
今回は手を抜いて、3byte目だけを取り出しています。
メーカーコード(1,2byte)のチェックや、反転コードのチェックをして、 誤信号を受け付けない処理は省略します。