赤外線リモコン
UNO

概要

Arduinoに赤外線LEDをつないで、赤外線リモコンの動作をまねてみる実験です。

この実験はArduino Unoを利用しています。ESP-WROOM-32での実験はこちら。ESP-WROOM-32とTFTタッチシールドを使った赤外線リモコンはこちら

目的

赤外線LEDを買ったので、赤外線リモコンでも作ろうと思っていますが、その前段階として、リモコンの出す信号をArduinoを使ってうまく出せるかを実験します。うちにある東芝のDVDプレイヤーを題材として取り上げます。とりあえず、チャンネルアップの信号を出せることを目的にしますが、できるだけ、汎用のプログラムにしていきます。

東芝のDVDプレイヤーのリモコンは、NECフォーマットと呼ばれるフォーマットを利用しています。NECフォーマットの解析用のプログラムはこちらを参照してください。

NECフォーマット

NECフォーマットのページを参照して、赤外線をどのように出せばいいのかを調べました。

概要

NECフォーマットの概要は以下の通りです。

リーダーコードは、リモコンコードの開始を表す信号で、9msのONの後、4.5msのOFFが続きます。

カスタムコードは、機器に割り当てられた16ビットのコードです。テレビのチャンネルを変えたいときに、DVDプレイヤーが反応したりしないようにするためのものでしょう。自宅のDVDプレイヤーには、0x45 0xbcというコードが割り当てられていました。

データコードは、機器の操作を行うための8ビットのコードです。その後、データコードの0と1とを反転させたコードが続きます。

最後に、ストップビットが1ビット送信されます。

カスタムコードとデータコードの形式

カスタムコードとデータコードは、0と1の組み合わせを送信します。0と1との違いは、LEDをOFFにする時間の違いで表現しています。以下の表に示します。

データ 全体の長さ ONの長さ OFFの長さ
1 2.25ms 0.56ms 1.69ms
0 1.125ms 0.56ms 0.565ms

また、LEDがONとなっている部分は、LEDをつけっぱなしにしているのではなく、38kHzのキャリア周波数で変調をかけていて、そのデューティー比は1/3と書いてあります。つまり、1秒間に38000回点滅していて、点灯している時間は点灯していない時間の2分の1ということです。これらを、まとめると、以下のような図であらわすことができます。

プログラムの考え方

将来のことを考えて、C++のクラスをとりあえず作成しました。

38kHzのキャリア周波数の実現

38kHzのキャリア周波数で、1/3のデューティー比を実現するには、前述の図の通り、赤外線LEDを、8.8μsのONと17.5μsのOFFを繰り返すことで実現できます。Arduinoで制御できる時間は、マイクロ秒までなので、9μsのONと17μsのOFFで近似することにします。これにより、周期が26μsとなるので、38.46kHzのキャリア周波数での変調となります。実際には、プログラムの実行に時間がかかるので、もう少し低い周波数になるのではと思います。

一番いいのは、PWMを使って、所定の周波数とデューティ比を実現する方法だと思います。ただ、Arduinoでは、周波数とデューティ比を変更するためのAPIは用意されていません。 このため、今回はポートレジスタを利用しました。これは、変数(レジスタ)を介してポートの入出力を制御するための機構です。

今回は簡易版のため、PORTDだけを固定的に利用しています。このため、デジタルピンの0から7番ピンでしか制御できません。スケッチの例では、3番ピンを使っています。他のピンを使う場合は注意してください。また、ハードウェアの機構をそのまま使っているので、異なるアーキテクチャのハードウェアを利用すると、使えなくなってしまいます。

プログラムの、void irControlNecFormat::on(int num)の部分で実現しています。

0と1の出力

0と1とは、赤外線LEDがONとなっている時間はどちらも0.56msで、OFFになっている時間が0.565msか1.69msかの違いです。

0.56msのONは、38kHzのキャリア周波数の出力の21.5回分となることから、22回出力することにします。このため、実際には、0.572秒間ONが出力されることになります。

OFFの部分は、delayMicroseconds()を使って、何もせずに待つことにします。

データの出力

データは、8ビット単位で出力します。フォーマットの規定により、データの下位ビットから出力することに注意します。

0と1の出力と合わせて、プログラムでは、void irControlNecFormat::sendData(byte data)で実現しています。

リーダの出力

リーダは、9msのONと4.5msのOFFと規定されているので、38kHzのキャリア周波数を346回出力し、その後、4.5ms待ちます。こちらも、void irControlNecFormat::sendData(byte data)の先頭部分で出力しています。

回路図

今回利用した赤外線LEDは、OSI5FU5111C-40というものです。このLEDは、1.35Vの順電圧で50mAの電流を流します(100mAまでは大丈夫なようです)。Arduinoの5Vの出力に接続するためには、(5-1.35)/0.05=73Ωの抵抗を接続すればいいことになります。

実際には手元にあった100Ωの抵抗を接続し、デジタルピンの3番に接続しました。

注意:Arduinoのデジタルピンに50mA流すと、Arduinoが壊れます。抵抗の値は自己責任でお願いします。

赤外線LEDは、光っているのかどうかは人間の目では見えませんが、デジカメで見ると光っているかどうかがわかるので、まずは、単純に電源につなげてみて光ることを確認するのがいいかもしれません。

スケッチ

以下にスケッチを示します。実行する際には、リモコン用オブジェクト生成の際の引数と実際のコマンドを各自のリモコンに合わせてカスタマイズしてください。

irControlNecFormat controller(3, 0x45, 0xbc);という行で、オブジェクトを定義しています。第一引数が、赤外線LEDを接続するデジタルピンの番号(0から7)、第2引数と第3引数が、リモコンのカスタムコードです。

loop()の中で、2秒ごとに、コマンドを送信しています。手元のリモコンのチャンネルアップのコードが0x1eなので、そのように書いています。音量調整のコマンドとかを出す場合は気を付けてください。

sendCommand(data)がデータを送信するためのメソッドです。引数には送信したいデータ(8ビット)を指定します。

 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
class irControlNecFormat {
  public:
    // constructor
    irControlNecFormat(byte ledPin, byte custom0, byte custom1);
    void sendCommand(byte data);
  private:
    byte _ledPin;   // the pin number which the LED is connected
    byte _custom0;  // custom code 
    byte _custom1;  // custom code
     
    void sendData(byte date);
    void on(int num);
};
 
irControlNecFormat::irControlNecFormat(byte ledPin, byte custom0, byte custom1) {
  _ledPin = 1 << ledPin;
  _custom0 = custom0;
  _custom1 = custom1;
   
  pinMode(ledPin, OUTPUT);  // set the ledPin as an OUTPUT
}
 
void irControlNecFormat::sendCommand(byte data){
  on(346);                  // leader code(ON)
  delayMicroseconds(4500);  // leader code(OFF)
   
  sendData(_custom0);       // custom code
  sendData(_custom1);       // custom code
   
  sendData(data);           // data
  sendData(~data);          // ~data
   
  on(22);                   // stop bit
}
 
void irControlNecFormat::sendData(byte data) {
  for(int i = 0; i < 8; i++) {
    on(22);
    switch(data & 1) {
    case 0:
      delayMicroseconds(565);
      break;
    case 1:
      delayMicroseconds(1690);
      break;
    }
    data = data >> 1;
  }
}
 
void irControlNecFormat::on(int num) {
  for(int i = 0; i < num; i++) {
    PORTD |= _ledPin;
    delayMicroseconds(9);
    PORTD &= ~_ledPin;
    delayMicroseconds(17);
  }
}
 
// Connect an LED to the No.3 pin.
// Custom code: 0x45 0xbc
irControlNecFormat controller(3, 0x45, 0xbc);
 
void setup() {
}
 
void loop() {
  // Channel increment: 0x1e
  controller.sendCommand(0x1e);
  delay(2000);
}

バージョン

Hardware:Arduino Uno
Software:Arduino 0022

最終更新日

November 1, 2022

inserted by FC2 system