2-5.赤外線リモコン受信《Remo》
電気回路と電子工作
赤外線リモコンの信号を読み取るモジュールを利用して電子工作を行います。赤外線受信モジュールの外観を以下に示します。
受信モジュールには3つの端子があり、VCC端子には3.3Vを接続しGND端子にはGNDを接続します。Vout端子は赤外線信号を受信している間はHIGH(3.3V)を出力し赤外線信号がない場合はLOW(GND)を出力します。以下の通り端子はGPI36を利用し赤外線受信状態を検知します。
【ESP32-DevKitCの入出力端子はこちらを参照下さい】
スケッチ(制御ソフトウェア)
GPI36で赤外線受信モジュールの信号を読み取り、読み取った信号をシリアル通信でパソコンに表示させるスケッチを以下に示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
// IoT電子工作キット // 2-5.赤外線リモコン受信 const byte IR_R_PIN = 36; // ①IO36でリモコン受信 // 起動時の初期設定 void setup() { Serial.begin(115200); Serial.println(); Serial.println("IrRecvStart"); pinMode(IR_R_PIN, INPUT); } // 赤外線受信処理の繰り返し void loop() { if ( irRecv () ) { // ②赤外線受信処理の実行 Serial.println(); Serial.println("RcvOK"); // ③信号を正常に受信した場合に表示 } else { Serial.println(); Serial.println("NoSig"); // ④30秒間信号がない場合に表示 } } // ⑤赤外線受信(信号受信 or 15秒間を処理) bool irRecv () { // ⑥irRecv関数内で利用する変数(ローカル変数)を定義 unsigned short irCount = 0; // HIGH,LOWの信号数 unsigned long lastt = 0; // 1つ前の経過時間を保持 unsigned long deltt = 0; // 1つ前の経過時間を保持 unsigned long sMilli; // 本処理の開始時間 unsigned long sMicro; // 処理の開始時間 unsigned long wMicro; // 待ち開始時間 bool rState = 0; // 赤外線受信モジュールの状態 0:LOW,1:HIGH sMilli = millis(); // ⑤現在のシステム時間を取得(ミリ秒で取得) // ⑦特定条件(信号受信 or 15秒経過)するまで無限ループ while(1) { // ⑧Ir受信を待つ開始時間を取得 wMicro = micros(); // 現在のシステム時間を取得(マイクロ秒で取得) // ⑨反転信号の受信待ち while (digitalRead(IR_R_PIN) == rState) { // ⑩待ち始めて0.5秒以上経過したら if (micros() - wMicro > 500000) { // ⑪待ち始めて0.5秒以上経過したら if ( irCount > 10 ) { return true; // ⑫正常に完了 } // ⑬0,1信号が10個以上ない場合は雑音のため再度ゼロから受信 irCount = 0; } // ⑭処理が15秒以上経過したらT.O. if ( millis() - sMilli > 15000 ) { return false; // ⑮15秒経過で終了(受信なし) } } // ⑯信号受信開始時の現在の時間や経過時間を取得 if ( irCount == 0 ) { sMicro = micros(); lastt = 0; irCount++; Serial.println("ir:"); // ⑰信号受信処理開始後の処理(irCountが1以上) } else { // ⑱赤外線受信部の状態変化が最後に変化した時間からの経過時間を計算 deltt = ( (micros() - sMicro)/ 10 ) - lastt; // ⑲次回経過時間計算のため最後に変化した経過時間を保存 lastt = lastt + deltt; irCount++; Serial.print(deltt); Serial.print(","); } // ⑳次回While内で状態変化を検知する値を変更 rState = !rState; } } |
①は赤外線受信モジュールを接続する端子番号を定義しています。setup関数内はシリアル通信でパソコンにシリアルモニタできる環境を設定しています。
loop関数内は②のirRecv関数の呼び出しで赤外線受信処理を実行しています。irRecv関数の処理結果により受信成功時は⑱「RcvOK」、信号がなかった場合は⑲「NoSig」をシリアルモニタに表示し結果がわかるようになっています。
irRecv関数は信号を受信するまで15秒信号を待ち受け状態となります。15秒以内に正常に信号を受信した場合は戻り値として「true」(⑫)を返答し終了します。15秒経過しても信号を受信しなかった場合は「false」(⑮)を返答します。返答(戻り)値はreturnで返すことが可能です。また、returnはその関数がその時点で処理を終了し、呼び出し元に処理が戻ることを意味しています。
⑦のwhile(1)はbreakやreturnがあるまで繰り返し処理を行います。このWhile文により信号を受信するか15秒経過するまで処理を繰り返します。
⑧で受信処理の開始時間を保持しています。経過時間を利用する場合、マイクロ秒単位かミリ秒単位によりmicros()、millis()を利用できます。開始時間は15秒経過を管理するためのものなので、マイクロ秒は細かすぎるのでミリ秒単位で値を保持します。
⑨のWhile分では状態が変化するまで繰り返し処理します。digitalRead(IR_R_PIN)はGPI36の端子状態となります。赤外線信号の受信時に赤外線受信モジュールは信号受信時に3.3VをGPI36に入力するため、digitalReadはHIGH(数値の1)となります。逆に信号がない時はGND(0V)となりdigitalRead はLOW(数値の0)となります。
⑩はリモコン信号の終わりを判定しています。0.5秒間信号がなかった場合に終わりと判定しています。ただ、⑪で0/1の信号数が10個以上の場合のみ正常に信号が受信できたと判定しています。これは自然界に多くの赤外線が流れていますので数回の信号はリモコン信号がなくても受信してしまいます。リモコン信号であれば0/1の信号数が10個以上あるため10個以上の場合のみ正常完了と判定し⑫returnでtrueを呼び出し側に返答し、irRecv関数はは終了します。
⑭は⑧で取得した時間から15秒以上経過しているかを判定して経過している場合はIF文内が処理され⑮returnで戻り値falseを返答し関数を終了します。
リモコン信号を受信した場合に最初に⑯の処理をします。リモコン信号の最初の信号を受信したタイミングはirCountが0なので⑯のIF文内の処理を実施し、開始タイミング時間(sMicro)を取得し信号先頭からの経過時間(lastt)を0に設定します。
リモコンの2つ目の信号からはirCountが1以上なので⑰else内の処理を実施します。⑱と⑲で0/1の信号の継続時間を計算しています。以下に計算の考え方を示します。⑲の計算で前回信号までの経過時間(lastt)を保存しているため、現在時間micros()との差分を⑱で計算しdelttを取得しています。計算したdelttはシリアルモニターへ出力しています。⑱では1/10に計算していますが多くは0,1のパルス幅(継続時間長さ)は100μ以上の長さで数μ秒の精度は必要ないことから扱いやすいように1/10で計算しています。
⑳でrStateの状態を反転させます。「!」は状態を反転できますのでTrueをFalseへ、FlaseをTrueへ値を反転できます。本変数の反転により信号待ち状態を変更しHIGH/LOWの次に変化するタイミングまで⑦while内を処理します。
スケッチを書き込み、プログラム起動後に赤外線受信モジュールに向けてリモコン信号を送信すると、シリアルモニタは以下のように表示されます。
受信信号は「348,172,45,42,45・・・・」のように表示され、次の行に「RcvOK」と表示されていればリモコン信号が受信完了しています。ただ、雑音を受信している場合もありますので、正常に受信できていない可能性もあります。この348,172,45・・・はマイクロ秒を1/10にしていますので、実際には3480μs,1720μs,450μs・・・となり、これらは赤外線信号ONとOFFの状態を交互に時間間隔を表示しています。今回の場合、最初の3480μsが赤外線信号ON状態の時間間隔で、その次に信号OFF時間間隔1720μsが続き、次に信号ONが450μs間続くというように信号ONと信号OFFの時間が交互に表示されます。
《リモコン信号について》
(1)フォーマットについて
一般的なリモコン信号のフォーマット例を以下に示します。
リモコン信号の初めは認識しやすい長めのリーダコードのONとOFF信号があり、その後にデータが続きます。
データコード内での信号1、0(信号あり、なし)は信号長さの違いで判定するのが一般的で、通常0信号の場合に比べて3倍の長さがある場合に1の信号というイメージです。もちろんメーカや機種により判定方法に違いがありますので、一つの例と考えて下さい。このように赤外線送信あり・なし(信号あり・なし)を繰り返すことでデータ伝送を実現しています。
信号はキャリア周波数で伝送されます。通常、38KHzの周波数が用いられ下図のように約26μSec(1÷38,000)単位にON・OFFが繰り返されています。38KHz信号で信号ON/OFFの繰り返しが発生している場合に赤外線受信モジュールにおいても信号ありと判定されVout端子からHIGHで出力されます。赤外線信号なしの場合はキャリア周波数の信号も何もなく、赤外線受信モジュールからVout端子もLOWとなります。
光で考える方が理解しやすいかもしれませんので赤外線を光とした場合に言い換えて説明します。
上記の説明は、信号ありの場合は26μs単位に光をつけたり消したりして繰り返している状態で、信号なしは光を常に消している状態ということになります。
(赤外線も光(可視光)も周波数が異なる電磁波の一種ですので光で仕組みを考えることができます。)
また、赤外線リモコンの周波数が仕様に「波長:940nm」などと記載されていますがこれは電磁波自体の周波数を表しています。
一般的な赤外線リモコンの多くは940nmの電磁波を用いて38KHzのキャリア周波数を用いて信号の送受信を行なっています。