コンテンツ

H8 MCUボードにイロイロつないでみる/1 - マザーボード?にMCUボードを乗せる
H8 MCUボードにイロイロつないでみる/2 - I/Oポートを増やす+温度センサーを付ける
H8 MCUボードにイロイロつないでみる/3 - ロータリーエンコーダをつけてみる
H8 MCUボードにイロイロつないでみる/4 - 赤外線リモコン受信素子をつけてみる
H8 MCUボードにイロイロつないでみる/5 - 周波数カウンタにしてみる
H8 MCUボードにイロイロつないでみる/6 - ・・・

H8 MCUボードにイロイロつないでみる/4

ここまで、既にNET上に出尽くしたようなモノをつないできた訳で、いたずらにページを増やしているようにも見えてきましたが…
そもそも、このカテゴリでやってみたい事があったのですが、それには部品箱のパーツでは賄えない*1ので、只今、部品を注文中となっています。
で、先日、赤外線リモコン受光部で書いたように、赤外線受信素子を見つけましたので、ついでにつないでみようとなりました。
当該記事の通り、結構、出力に余計なパルスが出るみたいな感じなので、どうなる事やら?でのスタートです。

つないでみる

つなぐと言っても、Vcc、GND、OUTしか信号がないので、どうという事もないのですが、ソフト側でどう処理するか?によって、つなぐポートも変わってきます。
今回は、読み込みを割込み処理で行おうと考えましたので、以下のとおり、空いている割込みポートへ接続しました。

回路図

上図の電源に入っている100Ωと47μFは、入れないと余計なノイズで動作不能になる可能性があります。
また、以下の画像のとおり、受光素子にはフィルタを装着した方が良いです。

基板上のIR素子

赤外線リモコンの波形について

詳しいことは、NET上にいっぱいありますし、また、メーカーによってもイロイロなので、キチンとしたい場合は、別に情報を探してください。

ざっくりと基本的な感じは以下の図のとおりになります。

リモコンの基本的な波形
  1. データを送信する前に、長いリーダー部分がある。
  2. データは 1T 時間の L レベルパルスの後に
    1. 1T 時間Hレベルの場合は"0"(上図、黄色部分)
    2. 3T 時間Hレベルの場合は"1"(上図、水色部分)
  3. データの終わりは、長いHレベルのトレーラーとなる。
  4. データ部の長さは、リモコンやデータの種類によってさまざまある。

という決まりです。
尚、送信は38KHzで変調された信号*2ですが、受光素子の出力は、単にLパルスとHパルスに整形されたものになります。

受信ソフトを考える

さて、受光素子をつないで、リモコンから受信される波形が分かったところで、送られてきた信号をデータに直す方法を考えます。
これは、ソフトで行う訳ですが、今回は割込みを使う事にしたので、各パルスの始まりは割込みで検出、パルスの長さはタイマーを1個利用して計ってみます。

赤外線波形と処理

① 初期化

② IRQ処理

  1. 「最初の割込み待ち」の場合
    1. タイマーのカウンタを0クリアし、フリーランさせる。
    2. 処理状況をサンプリング中にする。
  2. 「サンプリング中」の場合
    1. 現在のカウンタ値を記憶する。
    2. カウンタを0に戻して計測を続ける。
    3. カウンタ値を記憶する領域が無くなったら、割込み禁止・タイマー停止し、状態を「取得終了」にする。

③ タイマー・オーバーフロー割込み

データ取り込みは、割込み処理で行う為、メイン処理は、①初期化を行い、状態が「取得終了」になるのを待てば良い。
再度、受信したい場合は、①初期化を行うだけで良い。

動作フローを貼り付けておきます(クリックで拡大)。

処理フロー図

プログラム・ソース

初期化部分と、割込み処理を中心に載せます。メイン処理は、一例です。

■ ヘッダ
※ ir_cdata[] を short から ushortに変更しました。

#define IR_MAX_CDATA_NUM    (48)

extern short  ir_state;                     /* 処理状態フラグ           */
extern short  ir_ovfct;                     /* オーバーフローカウンタ   */
extern short  ir_wrptr;                     /* データ書込みポインタ     */
extern ushort ir_cdata[IR_MAX_CDATA_NUM];   /* データ格納領域           */

enum {
    IR_WAIT,        /* 最初のパルス待ち状態     */
    IR_SAMPLE,      /* パルス取得中             */
    IR_DONE         /* データ取得終了           */
};

void init_irrecv(void);
bool is_irrecv_done(void);


■ 初期化処理

/*
    赤外線素子ポート P94/#IRQ4
    ITU-4を使用
*/
short  ir_state;                    /* 受信状態フラグ           */
short  ir_ovfct;                    /* オーバーフローカウンタ   */
short  ir_wrptr;                    /* データ書込みポインタ     */
ushort ir_cdata[IR_MAX_CDATA_NUM];  /* データ格納領域           */

/************************************************************************/
/*                                                                      */
/* 赤外線受信の初期化                                                   */
/*                                                                      */
/************************************************************************/
void init_irrecv(void)
{
    ir_state = IR_WAIT;             /* 受信状態フラグ           */
    ir_ovfct = 0;                   /* オーバーフローカウンタ   */
    ir_wrptr = 0;                   /* データ書込みポインタ     */

    /*------------------------------------------------------------
        ITU-4をφ÷8でフリーラン(3.125MHz 20mSでOVF)で動作
        するように準備しておく。
    ------------------------------------------------------------*/
    ITU4.TCR.BYTE      = 0x83;      /* クロック選択 1000 0011   */
    ITU4.TIER.BIT.OVIE = 1;         /* オーバーフローで割り込み */
    ITU4.TCNT          = 0;         /* カウンタ値               */

    /*------------------------------------------------------------
        IRQ4を受付可能にして最初のパルスを待つ
    ------------------------------------------------------------*/
    INTC.ISCR.BIT.IRQ4SC = 1;       /* 立下りエッジで割り込む   */
    INTC.IER.BIT.IRQ4E   = 1;       /* IRQ4割り込み許可         */
}


/************************************************************************/
/*                                                                      */
/* 赤外線受信終了か?                                                   */
/*                                                                      */
/************************************************************************/
bool is_irrecv_done(void)
{
    return (ir_state == IR_DONE);
}


■ 割込み処理

/************************************************************************/
/*  vector 16 IRQ4                                                      */
/************************************************************************/
__interrupt(vect=16) void INT_IRQ4(void)
{
    /* 割り込み要因フラグクリア(読み込んでから"0"を書き込む) */
    if(INTC.ISR.BIT.IRQ4F) INTC.ISR.BIT.IRQ4F = 0;

    /* 最初のパルス待ちの場合 */
    if(ir_state == IR_WAIT) {
        ITU4.TCNT = 0;          /* カウンタ値   */
        ITU.TSTR.BIT.STR4 = 1;  /* カウント開始 */
        ir_state = IR_SAMPLE;   /* 受信中       */
        // 受信中のLED ON
    }
    /* 受信中の場合 */
    else if(ir_state == IR_SAMPLE) {
        ir_cdata[ir_wrptr++] = ITU4.TCNT;   /* カウンタ値取得 */
        ITU4.TCNT = 0;                      /* カウンタクリア */

        /* データが書き込めなくなったら終わり */
        if(ir_wrptr >= IR_MAX_CDATA_NUM) {
            INTC.IER.BIT.IRQ4E = 1;         /* IRQ4 Disable     */
            ITU.TSTR.BIT.STR4  = 0;         /* カウンタ停止     */
            ir_state = IR_DONE;             /* 受信完了         */
            // 受信中のLED OFF
        }
    }

    /* オーバーフローカウンタをクリア */
    ir_ovfct = 0;
}


/************************************************************************/
/*  vector 42 OVI4                                                      */
/************************************************************************/
__interrupt(vect=42) void INT_OVI4(void)
{
    /* TSRのOVFをクリア(読み込んでから書き込む) */
    if(ITU4.TSR.BIT.OVF) ITU4.TSR.BIT.OVF = 0;

    /* OVFカウンタを+1した結果、OVFカウンタが2を超えていた場合 */
    if(++ir_ovfct >= 2) {
        ITU.TSTR.BIT.STR4  = 0;     /* カウンタ停止 */
        INTC.IER.BIT.IRQ4E = 1;     /* IRQ4 Disable*/
        ir_state = IR_DONE;         /* 受信完了 */
        // 受信中のLED OFF
    }
}


■ メイン処理例

#include "irrecv.h" /* IR recieve */

void main(void)
{
short ii;

    init_irrecv();  /* IR RECV 初期化*/

    while(1) {
        /* IR受信 */
        if(is_irrecv_done()) {
            if(ir_wrptr > 16) {
                printf("\r\nLeader = %d", ir_cdata[0]);
                for(ii = 1 ; ii < ir_wrptr ; ++ii) {
                    /* テストでは、しきい値が4500となった */
                    if(ir_cdata[ii] < 4500) printf("0");
                    else printf("1");
                }
            }
            init_irrecv();
        }

        /* 他にメインループで行う処理を書く */
    }
}
データ

以下に、手元にあったリモコン4種で取得したデータを載せます。
L は、リーダー部、その後のデータは、"0"か"1"の判断とカウント値です。
リーダー部の長さが違いますが、データとしては、ほぼ理屈通りとなっているようです。

OriPanaLCD TVCATV
L = 41550L = 16412L = 42096L = 16385
0 - 34820 - 27420 - 35200 - 2746
0 - 34781 - 54610 - 35161 - 5394
0 - 34780 - 27411 - 70040 - 2745
0 - 34780 - 27380 - 35200 - 2741
0 - 34780 - 27370 - 35160 - 2741
0 - 34780 - 27380 - 35150 - 2740
0 - 34790 - 27380 - 35150 - 2741
0 - 34800 - 27381 - 70040 - 2741
1 - 69210 - 27390 - 35180 - 2741
0 - 34820 - 27390 - 35160 - 2741
0 - 34790 - 27380 - 35150 - 2741
1 - 69210 - 27380 - 35160 - 2741
1 - 69250 - 27390 - 35160 - 2740
1 - 69241 - 54601 - 70051 - 5395
1 - 69250 - 27421 - 70080 - 2743
1 - 69900 - 27391 - 70080 - 2741
1 - 69240 - 27381 - 70090 - 2740
0 - 34810 - 27390 - 35200 - 2742
0 - 34800 - 27380 - 35150 - 2741
1 - 69200 - 27390 - 35150 - 2740
0 - 34821 - 54590 - 35160 - 2741
0 - 34781 - 54640 - 35150 - 2741
0 - 34790 - 27430 - 35150 - 2741
0 - 35551 - 54600 - 35141 - 5394
0 - 34800 - 27410 - 35160 - 2745
1 - 69220 - 27391 - 70041 - 5394
1 - 69240 - 27371 - 70091 - 5398
0 - 34820 - 27391 - 70090 - 2745
1 - 69210 - 27371 - 70080 - 2741
1 - 69250 - 27401 - 70081 - 5394
1 - 69250 - 27381 - 70090 - 2745
1 - 69330 - 27391 - 70090 - 2742
1 - 633980 - 27380 - 2741
1 - 346010 - 27380 - 2741
0 - 27380 - 2742
0 - 27370 - 2741
1 - 54610 - 2741
0 - 27411 - 5394
0 - 27391 - 5399
0 - 27380 - 2745
0 - 27380 - 2740
0 - 27381 - 5394
0 - 27381 - 5398
0 - 27380 - 2745
0 - 27370 - 2742
1 - 54610 - 2741
0 - 27421 - 5395



H8 MCUボードにイロイロつないでみる/5

*1 普通のロジックICなのですが、74ACシリーズを使いたいので・・・
*2 Lの時間分LEDを光らせている訳ではなく、Lの時間分、38KHzの周波数でON/OFFを繰り返す方法になっている
*3 MCUクロック=25MHzの場合、3.125MHzでカウント、オーバーフローは、320nS×65536=20.97mS で発生
最終更新のRSS
Last-modified: 2010-07-27 (火) 17:39:15 2825日前
HTML convert time: 0.059 sec.