« 2009年10月18日 - 2009年10月24日 | トップページ | 2009年11月1日 - 2009年11月7日 »

2009年10月25日 - 2009年10月31日の2件の記事

2009年10月30日 (金)

Xbee電力ロガー親機のAPIフレーム表示に苦労する

プログラムは考えたようには動かない(10/27/09)
 プログラムは考えたようには動かない、書いたようにしか動かないというのは言い古されたプログラミングの格言だが、まさしくこれを地で行くデバッグだった。Xbeeの親機の開発第2 ステップ、APIフレームの表示にえらい時間を食ってしまった。

 たいした開発量でないからと、簡単なメモを書くくらいでコーディングに入ると大抵うまくいかないものである。今度もそうだった。Xbeeから送られたAPIフレームを一旦バッファーに溜めて、画面に人間が見てすぐわかるAPIデータを表示するのが第二ステップの目的である。Apiformat

 前の第一ステップのPCのUART画面に同時にデータを表示するより構造的には、はるかに簡単だ。フレームが送り終わるのを待って、フレームフォーマットに従って、送信モジュールアドレスや、受信サンプル数、データを表示していく。造作のない話である。

 ところがこれがうまく動かないのである。コーディングを楽にするため、バッファーを文字配列にし、添字を使ってフレームからデータを抜き出すのだが、書式付の出力関数が思ったような数値を出してくれない。16進でだしたり、2バイトの整数で出したり、ビット表示だったりするので結構やっかいなのだが、出力されるのが、これが全くでたらめの値である。

 おかしいな。ChaNさんの書式付出力関数xprintfはprintfのサブセットで軽いので愛用させてもらっている。慣れているはずなのにどうしてだろう。あんまりおかしいので、元に戻って、送られてきたフレームを16進表示してみた。

 うひゃあ、これが全く似ても似つかぬAPIフレームが出力された。何だこれは。リセットしたり電源を入り切りすると、時々元の見慣れたAPIフレームが表示される時がある。何だ、何だ。ハードは何もいじっていないぞ。しかし、またすぐにおかしなデータに戻る。元のデータがこれでは、xprintfの書式どころではない。X-CTUを取り出してXbeeを確かめる。いや、何も問題ない。いつものデータを間違いなくはきだしている。

 Mega128のVccを3.3Vに落とした副作用だろうか。いや、もうひとつのファイルモニター機能は何事もなく動く、ハードの問題ではない。新しくUARTを追加したMega128のPE0,PE1ピンに何か特殊な機能があるのだろうか。いやデータシートには何もない。するとソフトか。コードを確かめる。間違いなく、Xbeeからの受信バッファーが空になるのを待ち、データ処理に入っている。暴走もしていない。データが入っているところもある。

 途方に暮れて、その日の開発はあきらめ寝床についた。次の日は仕事のない日で、朝寝坊して、うつらうつら昨夜のトラブルを思い出していた。このあいだは2つのUARTを同時に動かしたためバッファーをいくら大きくしても取りこぼした。今度はどうだ。今度は間違いがないように、受信バッファーをwhileループで監視し、空になるのを確かめて次のステップに行くようになっている。その間は別のUARTは動かしていない。

 ちょっと待て。UARTが1文字を読む時間は、いくら早くても数百マイクロ秒のオーダーだ(38.4kbpsでバイト当たり208μs)。これに対してCPUの処理速度は8Mhzで1ステップ0.125マイクロ秒。千倍以上のスピード差だ。ループの中に別のUARTが入っていないということは、このwhileループはUARTの早さに較べれば猛烈な速さで回転する。

あああ、これだ、これだ。このwhileループは下部のUART関数がデータをバッファーに入れている間に、あっという間にバッファーを読みつくし、余裕で抜けてしまう。そのあとはデータが読み込まれたものとして、まだ殆ど何も入っていないデータ処理バッファーを書き出す。これだ。これが目茶目茶なデータになる原因だ。

 やれやれ、わかってしまえば至極当然のことなのだが、思い込みというのは恐ろしい。最初のトラブルだったバッファーオーバーフローが頭に残っていて、UARTのデータはバッファーに溜まって行くばかりと考え、バッファーにデータが入っていることを前提にロジックを組んでいた。今度はある意味でのバッファーアンダーランである。疑ったMega128さん、Xbeeのみなさんごめんなさい。みんなこんなソフトを書いた自分が悪いのです。

このあとも泥沼(10/29/09)Xbeeavr
 飛び起きて、朝食をとるのももどかしく開発を再開した。しかし、このあとも苦戦が続いたのである。考えてみたら、APIフォーマットでADCデータが10秒ごと(現在の設定)に送られてくるが、データの終わりを判定する条件がない。データが来た時、バッファーに溜まるまで、少し待ち時間を入れれば良いのだろうが、こういう対症療法的なロジックは一番避けたいロジックである(巷にはこういうソフトが蔓延しているが)。これまでの経験からろくなことにはならない。とりあえずは良くてもたいてい後で破綻する。是が非でもしっかりとした終了条件が欲しい。robustness(堅牢さ)というやつである。

 データフレームには、普通、そのフレームの長さのデータが入っているものである。このAPIフレームにも勿論ある。これを使えば良いのだが、データを読み始めてから終了条件をダイナミック(読んでいる間)に設定する処理が必要だ。これを安全に確実に暴走しないよう、しっかり作るのは結構神経を遣う。もし、不幸にしてデータサイズが入らなくてもハングしない構造にしなければならない。色々考える。プログラムは最初考えていたよりずっと複雑なものになりそうである。

 それにバイト配列のデータから2バイト長のデータを連続して取り出すコードがなかなかスマートに書けない。アセンブラー育ちで、ポインターとキャストを完全に使いこなせていない。試行錯誤である。

uint16_t    * ptr;         //   2バイト整数のポインター
uint8_t   Array[80];   //    1バイト配列(データバッファー)

と定義しておいて、Array[nn]のところにある2バイト長のデータをprintfなどで10進数で表示したいときは、配列のアドレス表現&を使って、

 ptr = (uint16_t *) &Array[nn];

としてキャストし2バイト整数のポインターに替え、

   printf( "%u", *ptr );

で良い筈なのだが、どうしても1バイトずれてしまう。しかもうまく行くところと行かないところが出て益々混乱する。安易にコーディングを始めたことを後悔する。よほど最初から書き直そうかと考えたが、しかしもう遅すぎる。何とかするしかない。どうしても入らないところは、ひとつづつ入れて8ビットシフトし強引に2バイト整数にする。Xbeemonitor

 少しづつ手を入れては結果を確かめ、正しく表示されるデータを増やしていく。しかしチェックサムが最後まで残った。送られてきたデータとなかなか一致しない。配列番号、アドレス、チェックサムしないデータ数、このあたりの計算はいわゆる並木算で昔からいつも悩まされてきた。紙に何度も図を描いてチェックサムの始めと終わりのアドレスを確認する。無精して++を式の中に入れたりしているので余計厄介だ。

 悪戦苦闘、数時間。データフレームにあるチェックサム値と、プログラムで計算した値がぴったり一致した時は、思わず端末の前で一人で拍手をしてしまった。思うように動かない時は、何を好んでこんなことをやっているのか、自分の不甲斐なさに情けなくなるばかりだが、出来たとなると、この充実感が何ともたまらない。実に安上がりな娯楽だ。それにしてもこんな小さなプログラミングでも、ちゃんとした計画を立て、準備を十分にしないと痛い目にあうということを今さらのように学んだ。自戒、自戒である。

| | コメント (0) | トラックバック (0)

2009年10月26日 (月)

Xbeeワイヤレス電力ロガー親機(データログ)の開発

 Xbeeを使ったワイヤレス電力ロガーの制作は、省電力設計を取り入れた(スリープ機能)子機の開発がとりあえず一段落し、次の親機の開発を考える段階に来た。子機の電源の定電圧化をどうするかの課題は残っているが、これはケースや電池フォルダーなどの外装とからむのであとで考えることにする。

Xbee子機の仕様をまとめておく(10/23/09)

 親機の開発の前に、これまでいくつかの記事に分散して書いたXbee子機の仕様を、これから同じようなことをしようと考えている人や、近頃とみに忘れやすくなった自分のために(冗談ではなくて、このブログのバックナンバーが頼りのときがある)、ここでまとめてみた。

 今回のXbee子機は、AC100VのCT電流センサー(U_RD社製 CTL-10-CLS 秋葉原 東邦無線で入手 ¥1600)のAC入力電流(負荷抵抗で電圧に変換)を20ピンのADC0に入れ、所定の時間間隔で、親機にデータを送り出す。当面インテリジェントな機能は持たない。電源を入れれば果てしなくデータを送り続ける。時間間隔や、測定サンプル数などの変更は、XbeeモジュールをPC側のユーティリティX-CTUで設定し差し替える。

 CTセンサーの出力はACなのでオペアンプ(LM358)で全波整流し、LPF(ローパスフィルター)で平滑化している。オペアンプの電源は、Xbeeモジュールの持つ、SLEEP/ACTIVEピン(13)をトリガーにトランジスター2つのドライバーで制御し省電力仕様とする(待機時50μA)。

 ADCの基準電圧は、XbeeモジュールのVccとし、Vccは3端子レギュレーターで定電圧化する。CTセンサーの負荷抵抗は、ICソケットで変更が可能なようにしてある。

 スリープから目覚めた時、同時に整流回路にも電源が入る。平滑化のため最初の安定しないサンプルは捨て、一定になった時の値を採用する。

 上記の仕様のためにデフォルトから変更したXbeeのパラメーターは以下ですべてである。ただし時間間隔などはテストのために適当に決めたもので本番時のものではない。X-CTUのコンフィギュレーション画面ですべて設定できる。なお、Xbeeのファームウエアのバージョンは販売元のサイトで最新バージョンに上げておくこと(現在時点で10C8)。市販されているXbeeモジュール(OEM版と呼ばれる一番安価なもの)のファームウエアはかなり古い。

ATDH=0000          16 bitアドレスの時は0
ATDL=1111            送付先(親)アドレス 0~FFFFまで任意。適当に1111と設定
ATMY=2222          自分のアドレス 親はこれをATDLに設定する

ATSP =3E8 1000×10ms   10秒間隔でADCデータを送る
ATST=12C     300×1ms     0.3秒 測定が終わってから少し余裕を持ってスリープに入
                      る。(コマンドを受け入れるため)
ATD0=2   ADC0(20)ピンをADC(=2)にする
ATIR=14       20×1ms      20ms間隔でADデータを収集
ATIT=20        32回測定してからまとめて送信

 この設定で子機は順調にデータを出し始めた。Xbeeadc 親機側のXbeeの設定はアドレスだけで他はいじらない。親機はまだX-CTUのターミナルモードで16進表示である。CTセンサーの電圧が指数カーブを描いて定常状態になる様子がはっきり記録された。この回路では、前のオシロで見たとおり200~250msで安定するようである。

 調子に乗って、横にあったレーザープリンターの電流消費量も測ってみた。数値はいきなり4A以上(ADC値で500以上)を示すが、一分程度の初期動作を終えるとこのあとは瞬間的に5Aを超える(恐らくヒーターの間歇作動)ときを除いて、白熱電球(40W)のスタンドなみの0.03A(ADC値で40)に下がる。印刷時はもっと流れるだろうが、この測定は出来たときのお楽しみに残しておく。

 ついでに子機の消費電流を念のため測定する。動作時Xbeeadc_2 は、55mA少々、これはLEDをつけているためで、オペアンプの消費電流は1mA以下のはずだ。さあ、スリープ時はどうだ、よし、1mA以下を指した。レンジを換えてマイクロアンペアモードにする。ピッタリ50μAを指した。うむ、スペックどおりだ。これで10秒に1秒程度の動作で、一週間の連続運転が1000mAHのバッテリーで可能になる。

ワイヤレス電力ロガーの親機の開発に着手する(10/24/09)
 そろそろデータをログする親機の開発にとりかかろう。これまでに数々作った基板を納めたガラスの引き出しから、久しぶりに以前の電光掲示板のコントローラーに使ったMega128のCPU基板を取り出した。Aa252398 こいつはこれから実装しなければならないRTCもSDカードもついており、今度の実験にはうってつけだ。実際の親機はこれほどのスペックは要らないし、Mega168クラスで十分なはずだが、わざわざブレッドボードでハードを組む手間が省けるのが有難い。

 今度の開発は、逐次開発方式でやろうと思っている。AVRを紹介するウェブで検索すれば必ずヒットするkumanさん(AVR試用記)が愛用されている方式だ。少しづつ組んでは、部分的なテストをし、確認しながら大きなシステムにしていくやりかたである。大型システムの開発では極く当たり前の方法だが、こういう電子工作でも効果があるとは思わなかった。実際にやってみるとこれが具合が良いのである。手戻りが少ない。つい横着してすべてを組んでから頭を抱えるということがない。

 このサイトの主は、恐らく70 を超えておられる方だと思うが、失礼ながら年に似合わぬ電子工作へのあくなき探究心と好奇心に大変感動し、AVRを始めたころはとても参考にさせてもらった。何しろ説明が丁寧で初心者には心強い。初心者というのは、何が重要で何がそうでないか常に不安にかられているものである。そのあたりを丁寧に調べ、克服していく過程が、とても力づけられた記憶がある。このブログを始めた動機もこのサイトに刺激されたところが大きい。

 今度の電力ロガーの親機も次のようなステップで少しづつ組み上げていくことにする。

1. PCでXbeeの親機とお話し(UART)し、その結果をPC側にすべて伝える。

2. Xbeeの出力メッセージは、APIフレームというデータフォーマットなので、これを解析し、フレームの内容をわかりやすく、PC側に出力する。

3. 必要なデータをSDカードのファイルに貯めて行く機能を開発し、あわせてSDカードのファイルの内容を表示する機能を開発する。

4. RTCを組み込み、データに時分秒を追加する機能を付加する。

5. 子機が送ってくるデータを自動的にファイルに書き出し、複数のファイルを管理する機能を作る。

6. 子機の設定がリモートから行えるようにする。

当面は2.のところまでと、4.を作りこみ、3. 以降の仕様は、得られたデータをどう役に立てるかを考えながら作っていく。5. がとりあえずの完成形。6.は面白そうだが次期バージョンだろう。とりあえずはX-CTUでこれは出来る。

UART2つを動かすのは難しい(10/25/09)
 親機(データログ)をテストするハードウエアは、自作したMega128のCPU基板である。SDカードスロットと、USB-UART、RTCがついている。ChaNさんのFatFSのMMC/SDカードデモプログラムが動く。この基板は、SDカードの漢字フォントを読んでLEDマトリックスに7ドット日本語を表示する電光掲示板のCPU基板として使っていた。この電光掲示板は本人の知らないうちに以前、Make-JAPANで紹介され、ここのブログのアクセス急増に寄与したことがある。

 それはとにかく、Xbee電力ロガーの親機はXbeeとPCをつなぐためUARTが2つ必要だ。もちろんMega128は2つ持っている。ただ、このCPU基板は5VベースでSDカードのために3.3Vのレギュレーターを使い、レベルシフターのICでつないでいる。Xbeeは3.3VがVccなので、TTL-UARTでつなぐときまたレベルシフトが必要になってしまう。面倒なので、Mega128のVccも3.3Vにする。問題なく動いた。レベルシフターが余計だが別に困らない。

 次の作業は、Mega128のもうひとつのUARTのピン出しである。半田付け数本で済んだ。これでXbee電力ロガーのテスト用の親機のハードの準備は終わりである。あっけない。Aa262404

 次はいよいよソフトである。ChaNさんのデモプログラムをベースにモニター部分を残しXbeeとの会話の部分を追加する。Xbee親モジュールから受け取ったデータを単にPCへのUARTに送るだけである。擬似コーディングを書くまでもない。

 ChaNさんのモニタープログラムのUARTは読んでみると全部割込みベースで書かれていることがわかった。これは助かった。2つのUARTを同時に動かすのは、フロー制御なしだと、リングバッファーなどを使わないとデータをとりこぼす可能性が高い。

 既にあるUART関係のコードをそっくりコピーし、別の名前をつけてもうひとつのUARTをでっちあげる。とりあえずは、前に決めた手順の1が目標である。キャラクターコードでは送られている内容が見えないので、16進で出力することにする。これもありあわせのコードで間に合う。コーディングは数時間もかからなかった。動かしてみる。Xbeehost

 おお、動いた。フレームのヘッダーコードの0X7Eで行換えしているので、X-CTUより読みやすい。おやあ、データが途中で切れているぞ。バッファーサイズが小さすぎるのか。少しづつ増やすが改善されない。結局、Xbeeが送ってくるデータ量だけのバッファーサイズがないと、とりこぼすことがわかった。うーむ、何かおかしい。これはもう少し解析しなければ。

 夜も遅いので、作業を切り上げ風呂に入っているときに突然気が付いた。バイナリデータ1バイトを受け取って、16進キャラクターで送り出す。送信データ量は3倍になる(キャラクター2バイトとブランク)。UARTの速度は同じだ。あああ、何と言うお馬鹿な設計だ。フロー制御しなければバッファーは無尽蔵あってもたらない。2 車線が1車線になった道路のようなもので渋滞は際限なく広がるだけだ。

 木を見て森を見ずということわざと同じである。一生懸命、リングバッファーの仕様や、回線速度と処理速度を計算していたりしていたけれど、最も基本的なデータの流量の違いを見落としていた。いやあ、UART2つの設計というのは軽く考えていたけれど、そんな簡単なものではなかった。何らかのフロー制御を入力側(Xbee)でしない限り、今のたかだか100バイト程度のデータでも簡単にとりこぼしてしまう。

 しかし、考えてみれば幸いなことに今度の仕様はデータ量や、時間間隔が決まっている。XbeeにはRTSピンがついているのでフロー制御が出来るし、ちょっとやってみたい気もするが、当面はバッファーを最大フレームサイズにしておけば、フロー制御はしないですむ。それに次のステップはAPIフレームの処理だ。これは一旦バッファーにデータを取り込んでおく必要がある。当面はバッファーサイズを広げて対処することにする。

とにかくこれでステップ1はとりあえずクリアした。次はステップ2のAPIフレームの表示だ。

| | コメント (6) | トラックバック (0)

« 2009年10月18日 - 2009年10月24日 | トップページ | 2009年11月1日 - 2009年11月7日 »