H8 MCUボードにイロイロつないでみる/1 - マザーボード?にMCUボードを乗せる
H8 MCUボードにイロイロつないでみる/2 - I/Oポートを増やす+温度センサーを付ける
H8 MCUボードにイロイロつないでみる/3 - ロータリーエンコーダをつけてみる
H8 MCUボードにイロイロつないでみる/4 - 赤外線リモコン受信素子をつけてみる
H8 MCUボードにイロイロつないでみる/5 - 周波数カウンタにしてみる
H8 MCUボードにイロイロつないでみる/6 - 赤外線リモコン送信
赤外線リモコンのデータ取得~解析まで出来たので、それを元に、今度は逆にデータ送信をしてみることにしました。
現在、PCでTV録画*1を行っているのですが、地デジ化という事で、やむをえず、外部にチューナーを付けさせられる事になりました。
…が、PC側では、時間が来ると自動で録画が始まるのですが、チューナーまで制御できないので、
事前にチャンネルを合わせておかないと、同じ時間帯の別の番組を録画する事になったりしてます。
そんな訳で、最終的にはPC側と連動して、録画時にチューナーへチャンネル設定データを送信できれば…という事なんです*2。
以下の図のような、簡単なもので実験してみました。
部品の値は、手持ちのものを使った為、必ずしも適切ではないと思います。
また、LEDは、パルスで点灯させますので、普通よりも小さな値の電流制限抵抗を使います。
で、何かの手違いでLEDがONになりっぱなし*3にならないように、入力にコンデンサを
入れてパルスだけ通すようにしています*4。
PORT-A6からの信号は、TIOCA3を他と共有しているので付けているだけなので、普通は要りません。
信号の作り方は、いろいろあると思いますが、今回は以下のようにしました。
と、以下の図のようになります。
今回も、ほとんど割り込み処理内で処理をしています。
処理は・・・
のように、各状態に応じて処理するようになっています。
以下にプログラムを載せますので、詳細は書きません。
■ 以下、ヘッダ
/* 送信処理管理領域 */ 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) */ }