ビュートローバーH8をテレビリモコンで動かす
ビュートローバー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)のチェックや、反転コードのチェックをして、
誤信号を受け付けない処理は省略します。