おもちゃラボ

Unityで遊びを作っていきます

【Arduino】赤外線通信する(前編)

f:id:nn_hokuson:20210406214650j:plain

電子工作をしていると、作った機器を無線化したい場合が時々あります。方法としてはBLEや315Mhzの無線、Wifiを使うなどの方法があります。ただ、これらの方法は少し大掛かりになってしまうため、簡単に作れて取り回しの良い、赤外線通信の方法を紹介したいと思います。

この記事では、前編で赤外線通信で使用する38kHzの搬送波を作ります。また、後編では赤外線の送信機と、赤外線の受信機をそれぞれ作ることにします。目次は次のとおりです。

赤外線通信の概要

赤外線通信はTVのリモコンや、Nintendo DS、ガラケーなどの通信に使われている無線通信技術です。赤外線LEDを一定のパターンで光らせることでデータを送信します。

f:id:nn_hokuson:20210406192901p:plain:w400

このとき、単に赤外線LEDをON/OFFしてデータを送ることもできますが、通常手法は取られていません。これは太陽光やシーリングライトにも赤外線が含まれており、これらの外光がノイズになって機器が誤動作してしまうためです。

そのため、赤外線通信する場合は38kHzの搬送波で変調してデータを送信します。変調というと難しそうですが、ONのとき赤外線LEDを38kHzで発振させ、OFFのときは赤外線を消灯します。

f:id:nn_hokuson:20210406202700p:plain:w450

赤外線ONのときをデータの「1」、OFFのときをデータの「0」に割り当てることもできますが、これだと受信側でのデコードがシビアになります。どういうことかというと、次のようにデータのサンプリングのタイミングを厳密に合わせないと、データのデコードにミスってしまうのです。

そこで、少し冗長ではありますが、次のように最初にON、その後にOFFの期間を設けます。ONに続くOFFの時間が800us未満であればデータ「1」、800us以上であればデータ「0」とします。このようにすることで、受信側では確実にデータをデコードすることができるようになります。

f:id:nn_hokuson:20210406202746p:plain

最後にデータの最初と最後を定義するパターンも用意してやります。ここでは、ONの時間が3400us以上続くパターンをヘッダ、OFFの時間が10000us以上のパターンをストップビットとして使用します。

f:id:nn_hokuson:20210406204220p:plain:w500

Arduinoで赤外線通信をするために必要な基礎知識はこれでOKです。次は実際にArduinoで38kHzの搬送波を作っていくことにします。

38kHzの搬送波を作る

まずは最初に搬送波を作ります。ここで作る搬送波は38kHzでONとOFFを繰り返す矩形波になります。Arduinoを使ってこの矩形波を作るにはPWM(Pulse Width Modulation)という機能を使います。

PWMを使うには次の4つの手順に従って、それぞれのレジスタにパラメータを設定する必要があります。

  1. PWMに使うポート(出力ポート)を指定する
  2. TCCR1AとTCCR1Bのレジスタにパラメータをセットする
  3. OCR1Aのレジスタで周波数を決める
  4. OCR1Bでデューティ比を決める

それぞれの手順について、詳細に確認していきましょう。

PWMに使うポートを指定する

ArduinoのPWMで使用できるポートは9番と10番ポートです。ここでは10番ポートからPWMを出力して赤外線LEDを光らせるので、次のようにして10番ポートを出力に設定します。

pinMode(10, OUTPUT );    

TCCR1AとTCCR1Bのレジスタにパラメータをセットする

ここがPWM出力のキモになる設定です。TCCRx系のレジスタは、タイマーに使用するレジスタです。タイマーに使えるレジスタはTCCR0A/BとTCCR1A/Bがあるのですが、TCCR0系はArduinoの内部処理(delay関数など)に使われているので、プログラマが使えるのはTCCR1系になります。

TCCR1AとTCCR1Bの設定項目をまとめると下図のようになります。

f:id:nn_hokuson:20210406205437p:plain:w500

詳しくは公式のドキュメントを参照してください。
https://avr.jp/user/DS/PDF/megaXX8PA.pdf:image=https://avr.jp/user/DS/PDF/megaXX8PA.pdf

■ 使用ポートの設定
TCCR1Aの4〜7ビット目で使用するポートを宣言します。9番ポートを使う場合は6~7ビットを10に、使用しない場合は00に設定します。10番ポートを使う場合は4~5ビットを10に、使用しない場合は00に設定します。

■ タイマーモードの設定
TCCR1Aの0〜1ビット目とTCCR1Bの3〜4ビット目を使ってタイマーモードを設定します。主な設定項目には次のようなものがあります。ここではPWM出力をするため全ビットを1に設定します。

出力モード 設定値
標準 0000
CTC 0100
高速PWM 1111

■ 分周の設定
TCCR1Bの0〜1ビット目でシステムクロックの分周率を決めます。分周とは、システムクロック周波数を1/n倍して、より周波数の低いクロックを作成する仕組みです。

分周を使うことで、タイマーにシステムクロックよりも低い周波数を使うことができます。クロックを設定値は次の通りで、ここではArduino Unoのシステムクロック16Mhzを8分周して使いたいので「010」に設定します。

分周率 設定値
分周なし 000
分周1/8 010
分周1/64 011
分周1/256 100
分周1/1024 101

OCR1AとOCR1Bのレジスタにパラメータをセットする

OCR1Aのレジスタにはタイマーの上限値(=リセットする時間)を設定します。この上限値によって、下図のように生成するPWMの周波数が決まります。OCR1Bではデューティー比(PWMがONになっている期間とOFFになっている時間の比)を決めます。タイマーの値がOCR1Bで設定した値よりも小さい場合はON、大きい場合はOFFになります。

f:id:nn_hokuson:20210406210949p:plain:w500

赤外線通信では38kHzの搬送波を作りたいので、PWMで作成する波形の周期は1/38kHz=0.00002631578947秒となります。クロックの周期はシステムクロックを8分周しているため、1/(16Mhz/8)=1/2Mhz=0.00000005秒です。したがって、0.00002631578947÷0.00000005=51カウントしたときに、リセットがかかるようにOCR1Aには51を設定します。

f:id:nn_hokuson:20210406212052p:plain:w300

また、赤外線通信では電力消費を考えてデューティー比を3:1にします。そのためOCR1BにはOCR1Aで設定した値の1/3(=17)を設定します。

搬送波のプログラム

ここまでで38kHzの搬送波を作る方法がわかりました。これをふまえて、プログラムを作ってみましょう。

void setup() {
  pinMode(10, OUTPUT );    
  TCCR1A = B00100011;
  TCCR1B = B00011010;
  OCR1AL = F_CPU / 38000L / 8 - 1;  
  OCR1BL = OCR1AL / 3; 
}

上のプログラムでは10番ポートを出力に設定し、TCCR1A/BのレジスタでPWM出力を行うように設定しています。OCR1Aにはタイマの上限値を設定しています。F_CPUはArduinoで定義されている定数でシステムクロック周波数(Arduino Unoでは16Mhz)が格納されています。また、OCR1Bにはデューティー比が1/3になるように設定しています。

実行して、10番ポートにオシロスコープをあてて出力波形を見てみてください(ここでは赤外線LEDは接続しなくても大丈夫です)。次のように38kHzの矩形波が出力されていれば成功です。

f:id:nn_hokuson:20210406214949j:plain:w330

後編では、ここで作成した38kHzの搬送波を使って赤外線の送信機と、赤外線の受信機をそれぞれ作ることにします!

使用したパーツなど

今回のようにPWM出力を確認したいときにはオシロスコープがあると便利です。今回のように、観測したい周波数が100kHz程度でよければ安価な製品もあるので、チェックしてみてください!