2014年8月29日金曜日

リモコン受信 AVRマイコン編 その1

以前RaspberryPiでリモコン受信するやり方を書きましたが、今回はHA2module上のAVRマイコンでリモコン受信してコード化する方法について書きます。色々とあって長いので3回に分けて書きます。

赤外線リモコンのフォーマットは色々あって全てに対応するのは難しいですが、国内の一般的な赤外線リモコンはサブキャリアが38kHz前後で、AV機器は数十bit程度の長さが多いようです。エアコンの中にはかなり長く300bitを超えるものも存在しています。
赤外線受信モジュールはサブキャリアをフィルターしてパルスデータだけを出力してくれるので、GPIOで受けてパルスの変化のタイミングの間隔を見ていけばデコードできます。今回はAVRのPinChangeInterruptでTimerのCounter値を読んで前回の変化からの時間を記録するようにしました。
最初は自宅にある機器をメインに考えていたためAEHA,NEC,SONYのリモコンだけ対応すればよかったので、この割込みの処理の中でフォーマットの解釈もする実装にしていました。
ところが色々なリモコンを検討し始めたところ、このやり方ではダイキンやパナソニックのエアコンコードなどが対応出来ないため再度実装しなおしました。
新しい実装では、まずはじめにPinChange割込み処理中にHigh区間幅、Low区間幅のペアの頻度統計を取りながらコード化して記録します。
全体を記録し終えたところで押し続けることによる繰り返しパターンの判別をし、AEHA,NEC,SONYのフォーマットを解釈していずれかであればそのフォーマット、何れでもなければ記録したフォーマットをXBee経由で送るようにしています。
以下、実際の処理の詳細です。

□PinChange割込み中の処理
パルスをHigh区間、Low区間(実際の受光モジュールの出力は逆ですが、わかりやすいように無信号状態をLowとしています)をそれぞれ76kHzのカウント値で数えペアの値とします。このペアの値をPatternTableを検索し近い値があればそのPatternとして、なければ新規に登録して、そのPattern番号を求めます。
その番号を記録バッファに記録していくのですがそのまま番号を記録していくと4bit単位で記録していったとしても300bit越えのエアコンフォーマットだと余裕をみて196byte位必要になってしまいます。
普通のリモコンコードはデータを表すパターン2種類が0と1を表していて頻出するはずなのでこの2つを1bitの値として扱い、それ以外のパターンを特殊扱いすれば全体として短くすることが出来るはずです。ところがリモコンを受信し始めたタイミングではどのパターンがデータを表す2種類のパターンなのかは判りません。
そこで出現頻度を判断できるように先頭の64パルスを圧縮処理を遅らせるためにFIFOに登録しながら統計をとり、64パルス揃ったところで出現率の多いPatternを2つ選び、2つのうちHigh+Lowが小さい、等しい場合はHighが小さい方をパターン番号0、大きい方をパターン番号1とします。それ以外のパターンは出現順にパターン番号2から順番に登録します。普通のリモコンコードの場合、大体5〜6種類程度に収まります。
64パルス目以降はFIFOにパルス幅を登録しながらFIFOの先頭から順番に値を取り出します。
この時64パルス目のタイミングでそれまでのデータをまとめて処理してしまうと割込み中の処理が重すぎて取りこぼしが発生するので、FIFOでずらしたその割込みの64パルス前のパルスの処理だけを行うようにしています。
この説明だけでは判りにくいかと思いますが、あとで実際のエアコンのフォーマットを使って説明します。

□Timeout割込み
PinChange割込みのたびにTimerに100msのTimeoutを登録、更新します。
最後のPinChange割込みから100ms経つとTimeout割込みが入り、最終ビットパターンの処理を行い、通常Threadに処理を渡します。

長くなってきたので、一旦ここで切ります。
次回は通常Threadで後処理をするところからです。

2014年8月21日木曜日

子供用のスイッチボックス

1歳の息子が壁の電気のスイッチに興味をもって、頻繁にスイッチを押すために抱っこをせがむので子供用にスイッチボックスを作りました。 



よく、自治体の子育て施設とかに行くと壁にスイッチを沢山つけたものとか設置してあるので、子供は興味を持つものなのですね。
押してもなにも反応しないとすぐ飽きられてしまうので、中にモジュールをいれて単1電池で電源を取るようにしました。
これをコントロールサーバーとXBee経由で接続しLEDテープをランダムな色で光らせるようにしました。
中身はこんな感じです。


XBeeを間欠モードで動かすことで消費電力を抑えているので多分半年ほどは電池交換なしで行けるかと思います。
投げられても電池が外れないように固定して、新聞紙で間を埋めてガムテープで箱を閉じてます。
一見、ただ段ボール箱にスイッチを付けただけでどこにも繋がってないように見えるのに実際にスイッチとして動くのが面白いかと思ったのですが1歳の子供には理解できないですね。


2014年8月17日日曜日

LEDTape

PHILIPSのHueのライトリボンをみて作ってみようと思い部品を探してみました。
スイッチサイエンスにフルカラーシリアルLEDがあったので試しに購入。簡単に点くかと思ったら意外とタイミングが厳しく、8MHz動作のAVRの場合割り込み禁止してアセンブラでクロック数を数えながら無駄なく書かないとうまく点きませんでした。
写真は明るいキッチンカウンターの上でとっていますが、LEDが強すぎてLED以外の部分が真っ暗になってしまってうまく撮れなかったので見た目に合わせて色補正かけています。実際に見るとかなり眩しいです。



このLEDは1m60個のフルカラーLEDで、今回は半分に切って50cm30個で使っています。
本当は1灯ずつフルカラーで色を指定できるのですが、実際に使うとなると全体を同じ色で光らせれば十分なのでLEDの個数とR,G,Bを指定してPORTC4につないだシリアルLED を光らせる関数を作りました。
この関数を呼ぶと30us x LEDの個数分割り込み禁止になります。
1m品の場合60個なので1.8msの間blockされます。UARTでフロー制御していない場合、AVRはFIFOが1段しかないので4800bps以下に設定しないと通信を取りこぼします。
HA2moduleで接続しているので、XBeeを4800bpsで接続してコントロールサーバー経由で制御するようにしています。

void SetLED(unsigned char count, unsigned char r, unsigned char g, unsigned char b) {

  asm volatile(
               "  in __tmp_reg__,__SREG__ \n" // interrupt block 30us x count
               "  cli                     \n"
               "  in r6, %[port]          \n"
               "  or r6, %[tmp]           \n"
               "  mov r5, r6              \n"
               "  eor r5, %[tmp]          \n"
               "  mov r2, %[byteg]        \n"
               "loop:                     \n"
               "  ldi %[tmp], 8           \n" // 1
               "loopg:                    \n"
               "  out %[port], r5         \n" // 1
               "  nop                     \n" // 1
               "  sbrs r2, 7              \n" // 1 - 2
               "  out %[port], r6         \n" // 1
               "  lsl r2                  \n" // 1
               "  mov r3, %[byter]        \n" // 1
               "  dec %[tmp]              \n" // 1
               "  out %[port], r6         \n" // 1
               "  brne loopg              \n" // 2
               "                          \n"
               "  ldi %[tmp], 8           \n" // 1
               "loopr:                    \n"
               "  out %[port], r5         \n" // 1
               "  nop                     \n" // 1
               "  sbrs r3, 7              \n" // 1 - 2
               "  out %[port], r6         \n" // 1
               "  lsl r3                  \n" // 1
               "  mov r4 , %[byteb]       \n" // 1
               "  dec %[tmp]              \n" // 1
               "  out %[port], r6         \n" // 1
               "  brne loopr              \n" // 2
               "                          \n"
               "  ldi %[tmp], 8           \n" // 1
               "loopb:                    \n"
               "  out %[port], r5         \n" // 1
               "  nop                     \n" // 1
               "  sbrs r4, 7              \n" // 1 - 2
               "  out %[port], r6         \n" // 1
               "  lsl r4                  \n" // 1
               "  mov r2, %[byteg]        \n" // 1
               "  dec %[tmp]              \n" // 1
               "  out %[port], r6         \n" // 1
               "  brne loopb              \n" // 2
               "  dec %[count]            \n" // 1
               "  brne loop               \n" // 2
               "  out __SREG__,__tmp_reg__\n"
               : 
               : [count] "r" (count),
                 [byter]  "r" (r),
                 [byteg]  "r" (g),
                 [byteb]  "r" (b),
                 [tmp]    "r" ((1 << PORTC4)),
                 [port]   "I" (_SFR_IO_ADDR(PORTC))
               : "r0", "r2", "r3", "r4", "r5", "r6");
}

2014年8月9日土曜日

bootの書き込みツール(AVR USB-ISP)



HA2モジュールは大きさの関係で特殊なコネクタを使用していますが、コネクタを変換すれば3.3V対応のAVR用のwriterを使用できます。
AtmelのAVR ISP mkIIが一番無難ですが、嵩張るのでaitendo AVR-USBasp-Bを改造して(5V->3.3V)使用していました。最近もう1つ必要で購入しようとしたら在庫切れで買えなくなっていたので、同じくaitendoのUSB-ASPの方を買って改造しました。




このUSB-ASPはFWが公開されておらずそのままではMacで使えないので、こちらのページ

を参考にFWを書き換え、B面に3端子レギュレータを載せて5VとVCCをつないでいるパターンをカットして3.3Vに変更しています。小型でなかなか便利なので最近の愛用品です。


2014年7月31日木曜日

XBeeSetup

XBeeのFW書き換えや各種設定をするのにX-CTUやmoltosenso Network Managerを使用するのが普通のやり方なのですが、terminalから設定ファイルを読み込むコマンドの形で使いたかったのでFW更新して設定するプログラムを作りました。
FWはDigi Internationalのページからダウンロードしてきて下さい。
 XBee / XBee-Pro ZB (S2) Modulesを選択、次のページでFirmware Updatesを開いてXBee / XBee-PRO ZB firmware ver. 2xA7を選ぶと82001817_G.zipがダウンロードされるので展開し、82001817_G/ebl_files/のXB24-ZB_21A7.eblからXB24-ZB_29A7.eblをXBeeSetupのdirectoryにコピーします。

configファイルの記述方法はsample.confを参考にしてもらえばわかると思いますが、
書き込むfirmwareのversion(XBeeの動作モード毎にfirmwareが違う。例えばCoordinator APIで使う場合は21A7)をfirmware:の行に記述
setup:以降の行はXBeeに送るATコマンドを記述します。
./XBeeSetup -c sample.conf -d /dev/cu.usbserial (serialのdeviceファイルは環境に合わせて下さい)
を実行するとFWのverisonを確認し、必要ならupdateして設定を書き込みます。
setupの最後にWRを書いておくことでXBeeの不揮発性メモリに設定が記録されます。

ソースコードはここにあります。

2014年7月25日金曜日

HA2module

HA2bootから起動されるHA-2/FC、RP-1/RIR用のプログラムです。
基本的なXBeeとの通信機能の他、赤外線リモコンの送信、受信、HA端子の制御、監視、接点スイッチの制御と監視、ADCの監視などの機能を実装してあります。
赤外線リモコンの送受信は今のところNEC,SONY,家製協フォーマットのみ対応です。
赤外線リモコン受信、HA端子、接点スイッチの監視はイベントが発生するとホスト宛に通知が出るようにしています。
プログラムの構成はScheduler,Timer,XBee,Queue,Usartでシステムとしてのスケジュール管理とXBee経由の通信管理を行い、それ以外の物が各種コマンド実行とそれに付随するデバイスドライバになっています。
このプログラムはXBeeからのコマンドでそれぞれの機能が動作するだけの物なので単独では役に立ちません。
ホスト側のControlDaemonとの組み合わせで機能するようになっています。
ソースコードはこちらにあります。
makeするとha2module.haファイルが出来上がります。

落雷

昨日の夕方、かなり強烈な落雷がありました。
家の中で色々リセットされてました。
対策を入れてあったので今回は壊れたモジュールは有りませんでした。
対策が有効だったということかと思います。

2014年7月17日木曜日

elf2ha

avr-gccで生成された.elfファイルをHA2bootで書き込める.haファイルに変換するためのツールです。
.haフォーマットは先頭16byteのヘッダーとプログラムの先頭からの連続領域のイメージからなる単純なフォーマットです。
ヘッダーの中身はBigEndianで
struct HeaderSt {
  longword Magic; // 'HAUP'の文字列
  word SetId; // moduleの種類を表す16bitの値
  word Version; // プログラムのバージョンを表す16bitの値
  word Addr; // 先頭アドレスだがリセットベクタがあるので必然的に0x0000
  word Size; // プログラムの先頭からのサイズ
  word Reserve;
  word CRC; // プログラムの先頭から終わりまでのCRC
};
です。

HA1Controlプログラムのconfigファイルでこの.haファイルを指定しておくと起動時に各moduleのバージョンチェックをして必要なら更新作業をします。
sudo make installすると/usr/local/binにelf2haが作られます。
HA2moduleのイメージを作るのに必要になります。

ソースコードはここにあります。

2014年7月11日金曜日

HA2boot

HA-2/FCモジュールのAVRのFWをFW更新用のbootプログラムと通常使用時に動く本体FWの2つに分離しました。
bootプログラムは一番最初にAVRのboot領域に書き込みツールで書き込みます。
本体FWはbootプログラムによってXBee経由でAVRのアプリケーション領域に書き込まれます。
通常動作時は本体FWが動作しており、bootに遷移するコマンドを受けるとbootプログラムにjumpします。
bootの書き込みツールは色々あるので別途書きます。
bootは起動するとボーレートを変えながらXBeeにバージョン問い合わせのパケットを投げて帰ってきたパケットを確認することでXBeeとAVR間のボーレートを認識します。
現在のコードでは2400bps, 4800bps, 9600bps, 19200bps, 38400bps, 76800bps, 250000bpsを確認しています。この値はAVRを8MHzで動かした場合に誤差が少なくてちゃんと通信が成立しそうな値を選択しています。
boot自体はアプリケーション領域の本体FWを受け取って書き込む機能に特化しているので、それに必要なコマンドが届くのを待ち続けコマンドが来たら実行するだけの単純なものですが実装して見ると意外と大きくなってしまいATMega328のboot領域ギリギリまで使用してしまいました。
コードをgithubに置きました。

2014年7月3日木曜日

HA-2/FCモジュールの回路修正

1年ほど使ってきて色々回路修正が入ってきたので修正内容をまとめました。

-落雷対策で問題になりそうな端子にバリスタを追加しました。
昨年落雷でモジュールが壊れてバリスタを入れる対策をしたことで、それ以降近所で一度落雷がありましたが壊れること無く動いています。このまま今年の夏も乗り切れれば大丈夫かとおもいます。
-外部端子のAD1,2をAVRのADCからも使えるようにしました。
温度センサーと雨センサーを読み取るのにXBeeのADCを使用してきましたが、XBeeのADCは1.2Vまでしか対応できません。他のセンサーをつなごうとすると3.3Vまでのものも多いためAVR側のADCも接続できるようにしました。
HA-2/FCモジュールはXBee側のADCをoffにして使用します。offになっていれば端子に3.3Vが掛かっても問題ありません。
-外部端子のGPIO1,2をAVRのGPIOからも使えるようにしました。
将来の拡張用としてAVRのGPIOも2本出せるようにしました。
-外部端子に赤外線出力が強弱2系統出していたのを片方赤外線入力に変更しました。
AEHA,NEC,SONYフォーマットの赤外線リモコンコードのみ受信可能です。
解釈後Header部(4byte)を含めて64byteまでのコードを受信できるはずです。(そんなに長いコードを吐くリモコンが手元にないので未確認です)
-XBeeからAVRをリセット出来るようにしました。
AVRのFW updateを出来るようにしたため、bugありのFWを送って同仕様も無くなった時の対策としてXBeeからAVRをリセット出来るようにしました。

修正後の回路図です。