Release 2018.7.14

IR code captureスケッチ 家電リモコンでArduinoを操作

IR Remoteを使って、も少し具体的に活用出来るような「IRコード受信」スケッチを書いてみました。

任意のIR信号を記憶・判定し、それによって指定アクションを行います。また、取得したIRコードはEEPROMへ保存されるので、再度電源を入れたときにも覚えている、といった構成です。今回は物理的なスイッチの代わりにシリアルモニタを利用しているので、必要なものは、家電リモコンとIR受信機、(あればLED)だけです。

最終的なスケッチは最後にありますが、自分が普段スケッチを構築してく過程で書いているので、そこら辺を楽しんで読んで頂ければ幸いです。

回路図

  • D11 pin : IR Reciever
  • D13 pin : normal LED

リモコンコードを取得する

前回の記事に追記しましたが、”decode_type”の返り値でメーカーが分かるので、とりあえず、下記のような文字配列を用意しておきます。

で、前回の学習を踏まえた上での基本スケッチはこんな感じになります。

メーカー番号を“ir_id”変数、IRコードは“ir_code”変数としています。赤外線コードが受信されたら、その情報をこれら変数に投げ込みシリアルモニタに表示するという流れになってます。

“ir_id”は取得時に+1しています。これは、最小の返り値‘UNKNOWN’が「-1」から始まっているため、decode_typeは正負型の変数に入れておく必要があるんですが、後のEEPROMへの書き込みを考慮すると、マイナスの数値では面倒なので、こうしてます。

行動分岐

上記のままだと、ただただ赤外線コードを取得するだけです。なので、通常では「受信モード」で、シリアルモニタから任意の文字が入力されると「キャプチャモード」に切り替わるように分岐させます。

シリアルモニタから‘g’を送ると“CAPTURE_IR”を実行。それ以外の時にIR受信した場合、それが取得済みの”IRメーカー・IRコード”に合致すると、任意のアクションをします。

更に、これを関数化。

RECV_CMD()関数に受信コードの真偽をさせることで、分岐がスッキリします。

キャプチャーモードを作る

上記のままだと、数値を取得しないので、反応はしません(LED点滅はする)。“CAPTURE_IR()”関数にそこら辺のタスクを書きます。で、中身はこんな感じに。

5秒間の待ち受け時間を設け、その間に受信したIRメーカーとIRコードを取得します。

ただし、この形だと、受け取った順に取得コードが更新されていってしまいます。

市販リモコンには、複数回発信したり、長く押すと「リピートコード」を出すタイプもあるそうで、この場合、そっちが最終取得にされてしまうためかと思います(更に、メーカー名も上手く識別出来ない場合も…)。

一度に複数取得

これをなるべく回避するためには、取得直後に長いdelayを挟むのが単純ですが、もう一歩進めて、2つ拾うことにします。

“ir_id”と“ir_code”を配列に変更しました。

で、キャプチャ中、“keepin”変数で取得回数を覚えておき、DUB_SIZEで定義した回数を越えたらWhileループを離脱。その後、取得の有無判定によってLED点滅とシリアルプリントで、取得コードをまとめて示します。

また、シリアルプリントするPRINT_CODE()関数も、配列別に表示するよう変更を入れました。

それに伴い他の関数も修正。

有効コードの選択

2個のコマンドコードを拾うことで、より反応が良くなりますが、逆に意図しないコードにも反応してしまう場合があります。なので、片方だけに反応出来るよう設定を組み込みます。

シリアルモニタで0~9の数字を受けた場合、それを数値として“pickup_num”変数に投げ込みます。その番号の配列だけで判別させる事にします。この場合、「1~2」ならそれぞれの変数配列番号、「0」は「全て有効」という形にしました。

受信判定の関数内で有効かどうかを見るんですが、for文が「0」の場合はDUB_SIZE分(全部)、「1~2」なら1回ずつになるようにしています。

ちなみに、“current_num”変数はシリアルプリントで目印を着けるために設けました。

EEPROMで記憶・読み込み

キャプチャしたIRコードをEEPROMへread・writeすることで、電源が落ちても保持できるようにします。

EEPROMへ保存

指定メモリーアドレスを引数とする“IR_SAVE”関数を作ります。保存するのは、有効配列用番号の“pickup_num”に1バイト。IRメーカーの1バイト分とIRコードの4バイト分で5バイト。それがDUB_SIZEで定義した2個ということで、計11バイトとなります。

無駄に上書きしないよう、EEPROM.write()ではなく、EEPROM.update()を使いました。

EEPROMのアドレス指定用に“bank”変数を作り、1バイト保存するごとに++1で順当に増分させています。最初の指定アドレスには“pickup_num”。

次にIRメーカー用1バイトを書き込み、その後、4バイトlong型の“ir_code”数値を、ビットシフト&ビットマスクして、1バイト分ずつ順当アドレスに投げ込んでいます。あと、書き込むデータを“PRINT_DATA”、“PRINT_ACTIVE”関数に投げることで、一応確認出来るようにしてます。更に、5バイト分は配列にした2つ分行うので、“dub”で括って反復しています。

ちなみに、EEPROM.update()内の引数は、直接数式のかたちだと上手く対応してくれないので、せつな的な変数(temp~)を作って計算させてから指定しています。

EEPROMから読み込み

読み込みは上記の工程を行います。

ロードした“pickup_num”が規定のDUB_SIZEを越えてしまった場合、「0」にして再保存するようにしました。また、SAVE同様、EEPROMから読み込んだ値をそのまま足すと変になるので、一旦、変数‘temp’に投げ込んでから、それぞれの変数へ加算していってます。

これらの関数を使うために、再度修正。

まとめ:“IRコードキャプチャ” スケッチ

というわけで、諸々まとめた完成スケッチです。

シリアルモニタから‘g’を入力すると、5秒間IRコードの「キャプチャモード」になるので、任意のリモコンのボタンを押して取得させる。取得するとEEPROMに保存。電源再投入時に保存したデータを読み込み。

取得は2個セットで行われるので、有効にしたい方をシリアルモニタで指定できる。「1~2」で具体的な指定。「0」だと全て有効に。

  • WAIT_TIME — 受信後等の待ち時間。大きいほど反復を拾いにくくなるが、反応は鈍くなる。
  • EEPROM_ADRES — EEPROMの保存・読み出し先頭アドレス。
  • DUB_SIZE — キャプチャしておくデータのセット数。リピートコード等不要なら「1」でもOKかも。

if(RECV_CMD()){}内を変更すれば、簡単にやりたいことへのカスタマイズ出来るかと思います。ただ、今更ですが、こういった場合にこそ構造体みたいなものを使うべきでしたね、と…。

参考リンク

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください