コンテンツ

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

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

赤外線リモコンのデータ取得~解析まで出来たので、それを元に、今度は逆にデータ送信をしてみることにしました。
現在、PCでTV録画*1を行っているのですが、地デジ化という事で、やむをえず、外部にチューナーを付けさせられる事になりました。
…が、PC側では、時間が来ると自動で録画が始まるのですが、チューナーまで制御できないので、
事前にチャンネルを合わせておかないと、同じ時間帯の別の番組を録画する事になったりしてます。
そんな訳で、最終的にはPC側と連動して、録画時にチューナーへチャンネル設定データを送信できれば…という事なんです*2

ハードウェア

以下の図のような、簡単なもので実験してみました。
部品の値は、手持ちのものを使った為、必ずしも適切ではないと思います。
また、LEDは、パルスで点灯させますので、普通よりも小さな値の電流制限抵抗を使います。
で、何かの手違いでLEDがONになりっぱなし*3にならないように、入力にコンデンサを 入れてパルスだけ通すようにしています*4
PORT-A6からの信号は、TIOCA3を他と共有しているので付けているだけなので、普通は要りません。

赤外線送信部の回路図

ファームウェア

信号の作り方は、いろいろあると思いますが、今回は以下のようにしました。

  1. 各パルスの幅は、タイマー0を使って作成する(パルス幅で割込みが入るようにする)。
  2. 信号は、タイマー3のPWMで38KHzのキャリアを発生させ、それを、上記の割込みタイミングでON/OFFする。

と、以下の図のようになります。

赤外線送信部のタイミング

今回も、ほとんど割り込み処理内で処理をしています。
処理は・・・

  1. リーダーH中
  2. リーダーL中
  3. データH中
  4. データL中
  5. トレーラーH中
  6. トレーラーL中

のように、各状態に応じて処理するようになっています。
以下にプログラムを載せますので、詳細は書きません。

■ 以下、ヘッダ

/* 送信処理管理領域 */
struct E_IR_SEND {
    ushort  state;      /* 動作状態                 */
    ushort  pctr;       /* パルスカウント           */
    ushort  dctr;       /* データビットカウント     */
    ulong   datah;      /* データH                  */
    ulong   datal;      /* データL                  */
};

extern struct E_IR_SEND e_ir_send;

/* 送信状態 */
enum E_IR_SEND_STATUS {
    IR_S_BEGIN = 1,     /* 処理開始                 */
    IR_S_LEADER_H,      /* リーダー部 H             */
    IR_S_LEADER_L,      /* リーダー部 L             */
    IR_S_DATA_H,        /* データ部 H 出力中        */
    IR_S_DATA_L,        /* データ部 L 出力中        */
    IR_S_TRAILER_H,     /* トレーラ H 出力中        */
    IR_S_TRAILER_L,     /* トレーラ L 出力中        */
    IR_S_DONE           /* 送信完了                 */
};


■ 以下、初期化~送信開始部分

/************************************************************************/
/*                                                                      */
/************************************************************************/
struct E_IR_SEND e_ir_send;

/************************************************************************/
/*                                                                      */
/* 赤外線送信の準備~送信                                               */
/*                                                                      */
/************************************************************************/
void init_irsend(void)
{
    /* 使用するポートの初期化 */
    BSC.BRCR.BYTE = 0xfe;           /* A23..A21 Disable                 */
    PA.DR.BIT.B5  = 0;              /* 外部カウンタへのパルス用ポート   */
    PA.DR.BIT.B6  = 1;              /* 赤外線LED OFF                    */
    PA.DDR        = 0xE0;           /* PA5, PA6 出力                    */

    /* ITU3を38KHz出力にする */
    ITU3.TCR.BYTE       = 0xC3;     /* クロック=φ÷8、GRBでリセット  */
    ITU3.GRA            = 41;       /* パルス立上り                     */
    ITU3.GRB            = 82;       /* パルス立下り                     */
    ITU3.TIOR.BYTE      = 0x88;     /* TIOCB3 出力禁止                  */
    ITU3.TIER.BYTE      = 0;        /* 割込みなし                       */
    ITU.TMDR.BIT.PWM3   = 1;        /* PWM モード                       */
    ITU3.TCNT           = 82;       /* カウンタ値                       */

    /*------------------------------------------------------------
        ITU-0をφ÷8でフリーラン動作。
        GRAでリセットと割り込みで1パルス分。
    ------------------------------------------------------------*/
    ITU0.TCR.BYTE       = 0xa3;     /* クロックφ÷8、GRAリセット      */
    ITU0.GRA            = 1750;     /* 周期 (560uS)                     */
    ITU0.TIER.BIT.IMIEA = 1;        /* GRA マッチで割込み               */
    ITU0.TCNT           = 0;        /* カウンタ値                       */


    /*------------------------------------------------------------
        送信するデータの情報などを管理テーブルに設定。
        テスト用なので決め打ち。
    ------------------------------------------------------------*/
    e_ir_send.state = IR_S_BEGIN;
    e_ir_send.pctr  = 0;
    e_ir_send.dctr  = 32;
    e_ir_send.datah = 0x009f906fL;
    e_ir_send.datal = 0x00000000L;

    /* 動作開始 */
    ITU.TSTR.BIT.STR3   = 1;
    ITU.TSTR.BIT.STR0   = 1;
    PA.DR.BIT.B6        = 1; /* 赤外線LED OFF */

    /* 後は、割込み処理内で送信処理の全てを行う */
}

/************************************************************************/
/*                                                                      */
/* 赤外線送信終了か?                                                   */
/*                                                                      */
/************************************************************************/
bool is_irsend_done(void)
{
    return (e_ir_send.state == IR_S_DONE);
}


■ 以下、割込み処理

/************************************************************************/
/*  vector 24 IMIA0                                                     */
/************************************************************************/
__interrupt(vect=24) void INT_IMIA0(void)
{
register struct E_IR_SEND *p;

    /* TSRのIA0をクリア(読み込んでから書き込む) */
    if(ITU0.TSR.BIT.IMFA) ITU0.TSR.BIT.IMFA = 0;

    /* 管理領域のアドレス */
    p = &e_ir_send;

    /* 同じ状態が続くかどうか */
    if(p->pctr && (--(p->pctr))) { return ; }

    /* パルスの反転を行う */
    if((p->state != IR_S_BEGIN) && (p->state != IR_S_TRAILER_L)) {
        if(ITU.TSTR.BIT.STR3) {
            ITU3.TCNT         = 41;
            ITU.TSTR.BIT.STR3 = 0;
        } else {
            ITU.TSTR.BIT.STR3 = 1;
            ITU3.TCNT         = 41;
        }
    }

    /* 現在の状態によって処理を振り分ける */
    switch(p->state) {
        case IR_S_BEGIN:
            /* 赤外線LED ON */
            PA.DR.BIT.B6 = 0;
            /* パルスオン */
            ITU.TSTR.BIT.STR3 = 1;
            ITU3.TCNT = 41;
            /* リーダーパルスONの時間 */
            p->pctr = 16;
            /* 次の状態 */
            p->state = IR_S_LEADER_H;
            break;

        case IR_S_LEADER_H:
            /* リーダーパルスOFFの時間 */
            p->pctr  = 8;
            /* 次の状態 */
            p->state = IR_S_LEADER_L;
            break;

        case IR_S_LEADER_L:
            /* 次の状態 */
            p->state = IR_S_DATA_H;
            break;

        case IR_S_DATA_H:
            /* パルスオフ時間 */
            if(p->datah & 0x80000000L) p->pctr = 3;
            else p->pctr = 1;
            /* データビットをシフト */
            p->datah <<= 1;
            if(p->datal & 0x80000000L) ++(p->datah);
            p->datal <<= 1;
            /* 次の状態 */
            p->state = IR_S_DATA_L;
            break;

        case IR_S_DATA_L:
            /* 出力するデータがあるか? */
            if(--(p->dctr)) {
                p->state = IR_S_DATA_H;
                break;
            }
            /* 次の状態 */
            p->state = IR_S_TRAILER_H;
            break;

        case IR_S_TRAILER_H:
            /* トレーラーのOFF時間分(長めに…) */
            p->pctr  = 49;
            /* 次の状態 */
            p->state = IR_S_TRAILER_L;
            break;

        case IR_S_TRAILER_L:
            /* パルス・カウンタ停止 */
            ITU.TSTR.BIT.STR0 = 0;
            /* キャリア停止 */
            ITU.TSTR.BIT.STR3 = 0;
            /* 赤外線LED OFF */
            PA.DR.BIT.B6      = 1;
            /* 終了 */
            p->state = IR_S_DONE;
    } /* switch(p->state) */
}


*1 キャプチャカードはアナログ対応のものなのです。
*2 TVは、めったに観ないですし、録画するのは映画のみとかなので、わざわざ地デジ対応のキャプチャカードを買う気にはならないので・・・。
*3 ONになり続けると、電流制限抵抗が小さいのでLEDが壊れます。
*4 普通は、ゲートを2個~使って回路を組んだりします
最終更新のRSS
Last-modified: 2010-08-20 (金) 20:36:58 4959日前
HTML convert time: 0.009 sec.