電子工作初心者が赤外線リモコンの解析してみた


まずはこれを見てください.

これは,電子工作のスターターキットに入ってた赤外線リモコンです.
よし電子工作で使うぞと思ったら,通信フォーマットとやらがあるらしい.
調べてみても,このリモコンのデータや記事がでてこない.

スターターキットに入ってても初心者には扱えないわ!

と思いましたが,まあちょっとリモコンの仕組みを知りたくなったので,解析っぽいことをしてみました.
ちなみに,初心者でも赤外線リモコンを使えるようにしてくれるプログラムはネットで見つけたんですけど,自分は使い方わからなかったんでこうして面倒なことしてます.

使ったもの

  • Raspberry Pi3 model B+
  • 赤外線リモコン
  • 赤外線リモコン受光モジュール

これらを使って謎の赤外線リモコンの仕組みとフォーマットを明らかにしたいと思います.

赤外線リモコンの通信フォーマット

赤外線リモコンはリモコンについている赤外線LEDをON,OFFし,そのON,OFFの時間の長さを変化させることで通信を行います.
まず赤外線リモコンの通信フォーマットは,大きく分けて3つあるそうです.

  • NECフォーマット
    • 世界中で利用されている
  • 家電製品協会
    • 日本国内の家電の多くで利用されている
  • 独自のフォーマット
    • 企業が独自にフォーマットを作り,それを利用している(Sonyなど)

結論を言ってしまうと,今回使用したリモコンがNECフォーマットだったので,こちらに焦点を当てて見ていきます.
他の形式も似ているので,NECフォーマットが分かれば大丈夫かと思います.

NECフォーマット

NECフォーマットでは,T=562[μs]が1つの時間単位となっています.
データの'0'と'1'はこのようにして表しています.
※黒く塗りつぶされているのはONになっている時です.なにもしていない所はOFFです.

そして通信全体は,大きく分けて4つのコードからできています.

  • リーダ・コード
    • 16TのON,8TのOFF
  • カスタム・コード
    • '0'と'1'から成る16bitコード
  • データ・コード
    • '0'と'1'から成る8bitコード + その8bitの'0'と'1'を反転させたコード
  • リピート・コード
    • 同じコードを繰り返し送る

それでは実際にラズパイを使って,この通りになっているか確認してみます.

赤外線リモコンの解析

まずは回路を作っていきます.

1.回路の作成

今回使用する赤外線受光モジュールはVS1838Bです.これもスターターキットに入ってました.

VS1838Bのピンは左がOUT,真ん中がGND,右がVCCとなっています.
VCCのMinが2.7V,Maxが5.5Vのなので抵抗を挟まず3.3Vにつなぎます.
今回はOUTを21番PINに繋げます.

2.ソースコードの作成

信号がON,OFFとなっている時間(μs)を出力するソースコードです.

irAnalysis.py
import RPi.GPIO as GPIO
import time

IR_PIN = 21

def timeMeasure():
    maxTime = 1 #sec
    prevState = GPIO.input(IR_PIN)
    startTime = time.perf_counter()
    while time.perf_counter() - startTime < maxTime:
        nowState = GPIO.input(IR_PIN)
        if nowState != prevState:
            endTime = time.perf_counter()
            elapsedTime = (endTime - startTime) * 1000000 #microsec
            return round(elapsedTime)
    return None

def analysis():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(IR_PIN, GPIO.IN)
    GPIO.wait_for_edge(IR_PIN, GPIO.BOTH)
    try:
        while True:
            elapsedTime = timeMeasure()
            if elapsedTime is None:
                break
            else:
                print(elapsedTime)

    except KeyboardInterrupt:
        GPIO.cleanup(IR_PIN)
    GPIO.cleanup(IR_PIN)

if __name__ == '__main__':
    analysis()

3.出力の解析

先程のプログラムを実行し,赤外線リモコンの0番を押してみました.
リモコンはNECフォーマットだったため,フォーマットと照らし合わせながら出力を確認します.

※ONとOFFどちらの時間かの区別を出力では付けていかったのですが,ON,OFFの順で出力されています.少し見づらいですが堪忍して下さい.

まずNECフォーマットでは,初めにリーダ・コードを受信できます.

リーダ・コード

出力の最初の2行はこのようになりました.
1行目はONの時間,2行目はOFFの時間となっています.

9338
4294

リーダ・コードは,16TのON,8TのOFFでした.
Tは562[μs]となっているため
16Tは
16*562=8992(μs)

8Tは
8*562=4496(μs)
となるはずです.

出力と比較すると,きちんと近い値がでていることがわかります.

次にカスタム・コードです.

カスタム・コード

出力の3行目以降から途中まで
1行目はONの時間,2行目はOFFの時間とON,OFFの時間が繰り返し出力されています.

484 #'0'
461
543 #'0'
478 
546 #'0'
478
543 #'0'
480
545 #'0'
486
548 #'0'
471
538 #'0'
479
546 #'0'
478
544 #'1'
1604
546 #'1'
1596
544 #'1'
1600
544 #'1'
1600
536 #'1'
1602
544 #'1'
1601
485 #'1'
1578
496 #'1'
1596

カスタム・コードは,'0'と'1'から成る16bitコードでした.

'0':1TのON,1TのOFF
なので,'0'はONが562[μs], OFFが562[μs]となったとき

'1':1TのON,3TのOFF
なので,'1'はONが562[μs], OFFが1686[μs]となったとき

出力と照らし合わせると,今回はカスタム・コードが 0000 0000 1111 1111 のようです.
このリモコンでは,カスタム・コードは全部これになってそうですね.

次はデータ・コードです.

データ・コード

カスタム・コード以降の出力です.

520 #'0'
466
529 #'1'
1587
328 #'1'
1543
335 #'0'
426
449 #'1'
1589
527 #'0'
468
512 #'0'
442
463 #'0'
460
------ここから反転--------
521 #'1'
1573
506 #'0'
467
539 #'0'
484
532 #'1'
1586
460 #'0'
438
527 #'1'
1603
479 #'1'
1575
464 #'1'
1588

データコードは, '0'と'1'から成る8bitコード + その8bitの'0'と'1'を反転させたコード でした.

なのでデータ・コードは0110 1000で,反転した1001 01111が続いています.
ここは押したボタンで値が変化するので,このコードを記憶しておけば,どのボタンを押したか判別できます.
電子工作で使うとき一番重要になる部分ですね.

リピート・コード

最後の部分です.

472
40106 
9203
2024
---------------
234
96804
9194
2128
----繰り返し----
466
96856
9161
2097
----繰り返し----
451
96858
9212
2168

リピートコードはその名の通り,同じコードを繰り返し送ります.

初めに1T,71T,16T,4Tをした後,1T,172T,16T,4Tを繰り返しているように見えます.
ここはフォーマットと少し違いますが,製品ごとに差があるのかもしれません.
リピート・コード以外は数値に少しぶれがあるもののNECフォーマット通りに通信していることがわかりました.