概要
世に中に広く使われている赤外線リモコン。どんな理屈で動くのか、分かったような分からないような、何とかせにゃ、と挑戦することにした。波形を見なければ、どうにもならんと、ナノ秒 (ns) まで解析できるUSBデジタルオシロ(PicoScope 2105)を、大枚3万5千円をはたいて秋月で入手(Fig. 1)。相変わらず、一貫して使っているPicBasic Pro (PBP) でプログラムを作成していこうというもの。ちなみに、このオシロを選んだ理由は、
1) USB 接続、別電源いらず、そして本体の取扱いは、大変簡単である。
2) ソフト(すべて英語であるが)が大変充実している。以前に入手した同社の Dr.DAQ で馴染がある。常にアップグレードを続けていて、初心者から、マニアまで満足させる。
3) 同社のHPの内容が充実していて、分かりやすい。
Fig. 1
プログラムがアッセンブリで書かれた赤外線リモコンの関連情報は五万とあるが、BASIC党員は、出来るだけBASICで書くのが基本。しかし、Web上で探してみたが、BASICで書かれたものは、あまり無く、あっても難し過ぎ。そうしているうち、PBPのコマンドの1つ、COUNT (一定時間の間のパルスの数を数える)を使ってアプローチしているものが見つかり(peterdeco1, 19th Aug.2005, in MELabs PICBASIC Forums)、面白そうなので実験してみることにした。動作原理は、発信側で3つのスイッチから、それぞれ違った数のパルスを送り、それを受信側で数えて、発信側のスイッチを区別しようというものである。ほんとに動作するのか?
回路
送信側(Fig. 2):
回路は簡単で、12F629 に、Push-On SWを3個、赤外線LED (TLN103と互換のGL538)、電源ON状態を知らせ赤色LED、それに、電池ボックス(単三2−3本)をつないだだけ。電源3Vの時、SW1、SW2、SW3を押すと、それぞれ0.28mA、0.25 mA、0.17 mAほどの電流が赤外線LEDに流れる。待機時(赤色LED®ON)には、1.6 mAほどの電流が消費される。
受信側(Fig. 3):
こちらの回路も簡単で、12F629 に、赤外線受信モジュール(HC-312)、PICへの通電を知らせるLEDと、それに、送信側から受信した3種類の信号を点灯時間の違いで表示させるためのLEDが組込んであるだけ。
Fig. 2 Fig. 3
プログラム
下にフローチャートとプログラムを示す。
-送信側-
送信側のフローチャートとプログラムリストは以下のようである。要はスイッチ(SW1, SW2, SW3)の入力を待ち、入力があった場合、対応する一定のスペースを途中に有する変調波を連続的に発生させ、赤外線LEDより発信する、というものである。
******************** '送信側プログラミング備忘録 *******************
'38KHz4.bas
'38KHz3.bas 2007.5.12 New Key entry routine added
'38KHz2.bas 2007.5.12 Key entry added
'38KHz1.bas 2007.5.10
'Modified from 38KHz.bas
'peterdeco1 2007.5.7
'************** Pin connection **********************
‘12F629, 4MHz Internal Clock used
'Pin 1: Vdd (5.0V)
'Pin 8: Vss (GND)
'Pin 7: GPIO.0: input - connected to SW1
'Pin 6: GPIO.1: input - connected to SW2
'Pin 5: GPIO.2: input - connected to SW3
'Pin 3: GPIO.4: output - connected to IR LED via 100 ohm resistor
‘*********** ここからプログラム本体******************
CMCON=7 'Comparator not used
TRISIO=%000111 'GPIO.0, GPIO.1 and GPIO.2 = Input, others = Output
GPIO=0 'ALL LOW
OPTION_REG.7=0 'Pull-up for GPIO.0, GPIO.1 and GPIO.2
WPU=%000111
DEFINE OSCCAL_1K 1 'Set OSCCAL for 1K device
X var byte
SW1 var GPIO.0
SW2 var GPIO.1
SW3 var GPIO.2
X = 0
START:
SWFIND: Key search routine
If SW1=0 Then CHANNEL1
If SW2=0 Then CHANNEL2
If SW3=0 Then CHANNEL3
Goto SWFIND
CHANNEL1:
High GPIO.4 'Generating 38KHz square wave
High GPIO.4
@Nop 'For pulse freq. adjustment
@Nop
Low GPIO.4
X=X+1
IF X > 100 Then SPACE1 '100 give a 2.6 ms-long modulated-wave length.
Goto START
SPACE1:
X=0
Pause 20 '20 ms as space between two modulated wave lengths
Goto START
CHANNEL2:
High GPIO.4
High GPIO.4
Low GPIO.4
X=X+1
IF X > 66 Then SPACE2 '66 = 1.8 ms-long modulated-wave length
Goto START
SPACE2:
X=0
Pause 10 '10 ms
Goto START
CHANNEL3:
High GPIO.4
@Nop
Low GPIO.4
X=X+1
IF X > 45 Then SPACE3 '45 = 1.2 ms-long modulated-wave length
Goto START
SPACE3:
X=0
Pause 7 '7 ms as space
Goto START
'********** ここまでがプログラム ***************
'Note:
'AKI Programmer's configurations:
'FOSC – INTOSC (GP4:I/O); WDTE - Enable; PWRTE - Enable
'MCLR - Internal ; BODEN - Enable; CD - Disable; CDP – Disable
<解説>
興味深いのは、変調波(38KHz、±3KHz許容というinfoもあり)と称するものの作成にPBPの最もポプラーなコマンドHigh、Lowが利用できることである。アッセンブラの@Nop(単なる時間つぶし)を適当に挿入すると、かなり38KHzに近づけることが出来る。例へば下の場合では、Highを2個、@Nopを2個("H"に相当)、次いで、Lowを1個("L"に相当)分(合計で1 cycle=約2.6ms)でほぼ38KHzの変調波を作り出している。その後、SPACE1に飛んで、Pause 10 で 10 ms の区切りのスペースを入れている。別途プログラムの中に複数のスイッチ入力を設け、各スイッチに対応するCHANNELに飛ばし、その中で途中に違った長さのスペース(“L”の部分に相当)を入れた38KHz変調波(”H” の部分に相当)を作り、出来た変調波パルス(長さに関係なく、両端をスペースで区切られた連続した変調波を1パルスとする)を受信側に発信する。
例:
CHANNEL1:
High GPIO.4 'Generating 38KHz square wave
High GPIO.4
@Nop 'For pulse freq. adjustment
@Nop
Low GPIO.4
X=X+1
IF X > 100 Then SPACE1 '100 give a 2.6 ms-long modulated-wave length.
Goto START
SPACE1:
X=0
Pause 20 '20 ms as space between two modulated wave lengths
Goto START
SW1, SW2、SW3を押すと、下図に示すような1サイクルあたり2.6ms前後の方形波がきれいに発生した。3つの波は、互いにDuty比が違うが、ちゃんと38KHzの波長を持つ波として認識された。
これらの波が“H”を出す時の搬送波として使われる。
SW1, SW2、SW3を押すと、下図に示すような棒状のパルスが連続的に出力される。個々のパルスが上記の38KHzの方形波の連続から形成されている。こうすると光のノイズに強くなるという。パルス間のスペースは、それぞれ、コマンドPAUSEを使って入れた20 ms, 10 ms, 7.7 msである。実測したパルス幅は、SW1=2.6 ms, SW2=1.8 ms, SW3=1.2 ms であった。
上記のような各信号を受信側の赤外線受信モジュールが受取ると、下図に示すように、発信側信号の棒状のパルス部分が逆転した方形波を出力する。発信側とかなり良く対応していることが分かる。そして、100 msあたりの、この棒状のパルスの数を受信側で数えてSW1, SW2, SW3の入力を区別する。
-受信側-
受信側のフローチャートとプログラムリストは以下のようである。信号を受取って、100ms当たりのパルスの数を数え、その数によってそれぞれ別のLED点灯ルーチンに飛ばし、LEDをそれぞれ違った時間(1、2、3秒間)だけ点灯させる、というものである。途中、パルス数を3−4回繰返して数えて、誤動作を減らす試みも取り入れられている。
******************** '受信側プログラミング備忘録 *******************
'38KHzRe6.bas 2007.5.31 Increased count check routines to cope with noise
'Namely, +2 count. check routines for ONCEMORE1,2 and +1 for ONCEMORE3
'38KHzRe5.bas 2007.5.25 Trying to prevent the noise from fluorescent light
'Using the fixed numbers 4 (SW1), 8 or 9 (SW2) and 12 (SW3) instead of
' "range values"
'IF X=8 OR X=9 Then ONCEMORE2 required but IF X=8 (or 9) didn't work.
'38KHzRe4 2007.5.19 Every ONCEMORE now includes a twice check routine.
'38KHzRe3 Reducing the nomber of CH3's peaks from 16-17 to 12-14 5.16
'38KHzRe2.bas 2007.5.15 To prevent the interference by TV key "TEISHI"
'2 check routines ("Count .. Endif) were added. Its effectiveness is unknown.
'38KHzRe2.bas 2007.5.12
'38KHzRe2.bas 2007.5.11 X >= 016 AND X <= 018 -> X=17
'38KHzRe1.bas 2007.5.11 X >= 015 AND X <= 017 -> X >= 016 AND X <= 018
'38KHzRe.bas 2007.5.11 Receiver software
'peterdeco1 19th Aug 2005
'************** Pin connection **********************
‘12F629, 4MHz Internal Clock used
'Pin 1: Vdd (5.0V)
'Pin 8: Vss (GND)
'Pin 7: GPIO.0: output - connected to LED via 470 ohm resistor
'Pin 4: GPIO.3: input - connected to IR Receiving Module’s output
'Pin 3: GPIO.4: output - connected to LED via 470 ohm resistor
‘*********** ここからプログラム本体******************
CMCON = 7 'Comparator not used
TRISIO = %00001000 'GPIO INPUT FROM IR RCVR
DEFINE OSCCAL_1K 1 ' Set OSCCAL for 1K device
X VAR BYTE
START:
Low GPIO.0 'Turn OFF LED.
MEASURE:
High GPIO.4 'ON RECEIVER
Count GPIO.3, 100, X 'demodulated pulses read into GPIO.3
IF = 4 Then ONCEMORE1
IF X = 8 OR X = 9 Then ONCEMORE2 ‘こうしないと動作せず。理由不明?
If X = 12 Then ONCEMORE3
Goto START
‘Increased count routines to eliminate false triggering – important
‘Takes more time but seems to lower erroneous functioning
ONCEMORE1:
Pause 10
Count GPIO.3, 100, X
IF X = 4 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 4 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 4 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 4 Then LED1SEC
Goto MEASURE
ONCEMORE2:
Pause 20
Count GPIO.3, 100, X
IF X = 8 OR X = 9 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X=8 OR X=9 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X=8 OR X=9 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 8 OR X = 9 Then LED2SEC
GoTo MEASURE
ONCEMORE3:
Pause 20
Count GPIO.3, 100, X
IF X = 12 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 12 Then
Pause 10
Else
GoTo MEASURE
Endif
Count GPIO.3, 100, X
IF X = 12 Then LED3SEC
GoTo MEASURE
LED1SEC:
X=0
High GPIO.0 'Turn ON LED for 1 second.
Pause 1000
Low GPIO.0
GoTo START
LED2SEC:
X=0
High GPIO.0 'Turn ON LED for 2 second2.
Pause 2000
Low GPIO.0
GoTo START
LED3SEC:
X=0
High GPIO.0 'Turn ON LED for 3 second2.
Pause 3000
Low GPIO.0
GoTo START
'********** ここまでがプログラム ***************
'Note:
'AKI Programmer's configurations:
'FOSC – INTOSC (GP4:I/O); WDTE - Enable; PWRTE - Enable
'MCLR - Internal ; BODEN - Enable; CD - Disable; CDP – Disable
<ノイズによる誤動作の問題>
夕暮れ時、受信側ボード上のLEDが突然点いたり消えたりし始めた。ノイズ源を検討したところ、ボードの2メートルほど斜め上で点灯している電球型蛍光灯からのノイズを拾っていることが分かった。赤外線受信モジュールの出力をオシロで見ると、下図のような具合であった。このような各種の赤外線ノイズの源が存在しているようで、それに打ち勝って赤外線通信を行うのは易しくないようだ。こんなノイズの中で、各SWを押すと、ノイズがきれいに消えて、本来の読まれるべきパルスの列が現れる。パルスの数が多いSW3からの出力は、数の少ないSW1からの出力よりノイズの影響が少ないようだ。また、プログラム(38KhzRe5.bas)でも、パルス数Xを、範囲ではなく、ある数値(X=4、 8 or 9、12)に一致した時に分岐する(IF..THEN文)ように改良した。つまり、分岐条件を厳しくしてノイズに強くなるようにした。多少効果はあると思われる。
結論
1) 実験目的のため発信用の赤外線LEDには、1mA以下の電流しか流していないが、それでも7 - 8 m 離れた受信側に信号が送れた。
2) 最初、時々送信エラーが出た。それらは、SW3の信号を、SW2、または、SW1と読取る、更に、TVリモコン(Victor RM-601)の「停止キー」や「8」などに、時々反応するというものであった。プログラムで、パルス数確認回数ルーチン(ONCEMOREの部分)を増やすことにより大分改善されたようだ。
3) ところが電球型蛍光灯からノイズを受信側が拾うことが後で分かった。プログラムの中身を変えて、つまり、 ONCEMORE1,2,3の部分を、それぞれ4、4、3回に増やすことで大分改善された。しかし、依然時々誤動作する。この方式の限界なのかもしれない。
4) 送信するパルス数を増やすと、時間を食うがノイズの影響を受け難くなる。
5) いずれにしても、単純に38KHzに変調されたパルスの数をカウントして、信号が送れるというのには、ちょっと驚いた。何かに使って、実用性を検討してみたい。
6) 12F629の内部クロックでも、まあまあ動作するようだ。
<4MHz内部クロックと4MHz XtalクロックX-tal(HC−49/S)の比較実験>
以下のような38KHz波発生ルーチン(38KHzXL.bas)を使って、上記2種のクロックで発生した波の波形や波長をオシロで測定した。その結果は表のようであった。内部クロックも結構正確であることが分かった。PICのデータシートでは、内部クロックの誤差は±2% 程度という。
|
4MHz内部クロック |
4MHz Xtal クロック |
H |
12.36 ms |
12.41 ms |
L |
15.23 ms |
15.50 ms |
H + L = 1 cycle |
27.59
ms |
27.91ms |
周波数 = 1 / (H + L) |
36.25
KHz |
35.83 KHz |
START: “38KHzの”H”、“L”の方形波を発生させるルーチン
High GPIO.2
High GPIO.2
'High GPIO.2
@nop
@nop
Low GPIO.2
Low GPIO.2
LET X= X + 001
IF X > 33 Then IROFF
GoTo START
余談
入手したUSBオシロで赤外線通信に使われている赤外線の波形、波長、周波数などを、いとも簡単に測定し、観察することが出来た。それに、測定したデータを容易に保存したり、印刷出来るのも素晴らしい。
何か、マイクロ秒(ms)単位の波の制御や作成も出来そう、ジイサン頑張れ!
<後で分かったこと−受信モジュールを換えて動作改善> 2007.6.1
今回使った赤外線受信モジュールHC-312 (メタルケース入り、5−6年前に購入)から、最近購入したPL-IRM0208-A538 (メタルケースなし、¥100)に換えてみたところ、誤動作しなくなった。受信モジュールからの出力をオシロで見たところ、電球型蛍光灯の電源を入れた時、一瞬ノイズによる乱れたパルスが出るが、点灯を始めるとノイズによるパルスが全く出なくなることが分かった。技術の進歩というものであろう。更に、検討を進める。教訓:パーツは出来るだけ新しいものを使え!
<さらに後で分かったこと−また電球型蛍光灯からノイズを拾う> 2007.6.8
2年くらい前に買った別の電球型蛍光灯(GAREAR EFA13ED、セーフボール13W)が、点灯して30分から1時間ぐらいすると、主としてSW2対応のLED(X=8 or 9)を点灯させることが分かった。オシロで見ると、やっぱりノイズによるパルスが赤外線受信モジュールの出力ピンから出ていた。また、ノイズを拾っている状態では、SW1を押しても対応するLEDが点灯しなくなる。つまり、電球型蛍光灯のあるものは赤外線ノイズを出すということ。ヤッパリ、このプログラムの限界なのかも?