« 2014年1月5日 - 2014年1月11日 | トップページ | 2014年1月26日 - 2014年2月1日 »

2014年1月12日 - 2014年1月18日の1件の記事

2014年1月15日 (水)

AquesTalkのマルチメーター(P-10)読み上げ装置が動いた

 久しぶりのソフト開発である。単体でのAquesTalkの発声(ステップ0)と、マルチメーターP-10の測定データ出力の確認(ステップ1)は済んでいる。前回の記事ではステップ2として、P-10の測定データをマイコンでASCII数値にデコードするところまで進んだ。これでPCコンソールにはP-10と同じ測定値表示が出るようになった。

 次はいよいよマイコンによるAquesTalkの初期化と発声シーケンスの制御である。これまでPCのコンソールに使っていたUART(ハードUART 19200bps)をAquesTalk側に回し、P-10のUART(ソフトUART 2400bps)をPCコンソール側に再度接続する。

 このステップ(ステップ3)の目的は、PCコンソールから入れた文字データをAquesTalkに送り、AquesTalkが喋るのを確認することである。ローマ字の発声だけでなく、数字の入力だけでAquesTalkが数字を読み上げるようにする。

 これが出来れば、前のステップで作ったP-10データのデコード(ステップ2)をつないでやればP-10の読み上げソフトは完成となる(ステップ4)。このように、いくつものステップに分けて開発しているのには理由がある。

 複数の通信がからむプログラムは、デバッグのしにくいソフトの代表格である。通信はいわゆるAll or Nothingの世界で、どこかのほんの少しの狂いだけで全体が全く動かない。動き出すまで一苦労するのが常である。

 慎重にステップを踏む方が結局早道であることを、電子工作をやる以前から身にしみて経験している。それでわざわざこんな回りくどい手順をとっているのだ。

ロジックアナライザーさまさま(1/9/2014)
 さらに、UARTなど通信系のソフトはメッセージが出たといっても、それだけで動きを把握するのは難しい。遅いと言っても1秒に何百字が行き来するのである。人間の感覚で判断していると、思い違いをすることが多い。今までに何度も苦い目にあっている(バッファーが一瞬で空になるのを見落とすとか)。

 しかし、こういうときに威力を発揮するのが、オッシロスコープや、ロジックアナライザーなどの測定器である。特に、ロジックアナライザーは強力で、今回も次々に問題を解決してくれていった。プローブ点の設定など、準備に少し手間がかかるが、動き出せば無敵である。

 最初のトラブルである。PCコンソールからの文字入力で無事AquesTalkは喋り始めた。それは良いのだがメッセージ発声の終了マークである'>'を待つ処理が上手く動いていないようだ。どうも、発声がはじまった途端に、'>'が帰ってくる。

 コンソールからの発声なら大した問題ではないが、P-10から立て続けに送られてくるデータを発声させるときに、ここが正常に動かないのはまずい。AquesTalkが誤動作する。しかし、原因が中々つきとめられなかった。

 ロジアナをつなぎ、双方のUART波形を画面にだし、チェックする。愛用しているロジアナ(秋月でもおなじみのLAP-Cシリーズ)には、UARTのデータをデコードしてくれるプロトコルアナライザーがついているので、データの中味を簡単に調べることができる。

Aques_badcr これを見ると原因がすぐわかった。送出データの最後を示す¥r(キャリッジリターン)がデータ列の中に2つもはいっていたのだ。

 つまり、PCコンソールからの文字入力データの末尾は必ず¥rで終わっているのに気づかず、¥rを追加していたのである。その結果、2番目の¥rの応答プロンプト(これは一瞬で返る)を最初のメッセージの応答と間違えて処理を終えていた。本来の'>'は1秒近くあと(発声が終わったあと)に出ている(AquesTalkは複数の発声申し込みが受け付けるのか、ある種の不具合)。

 次のトラブルは、もっと念が入っていた。1回目はちゃんとタイムアウトや、応答を待っているのだが、2番目以降は発声中に応答が戻ってしまう。せっかく直したところなのにまた同じようなことが起きている。ソースコードを検証するが特におかしなことはない。

 AquesTalkのピンにはbusyのデジタル出力(/PLAY)が出ているので、いざとなればこれを監視していれば確実に発声終了を把握できるのだが、少し意地になっている。この程度で引き下がるわけには行かない。

 これもロジアナの画面を見ているうちに原因が判明した。現在のルーチンの応答待ちタイムアウトは2秒で、発声はそれ以上かかることが多い。すると、タイムアウト後に送られてきた¥rは、読まれずに残ってしまう。受信バッファーに残ったデータが次の発声のときに読まれエラーとなる。

Aquesgood1 原因がわかれば解決はたやすい。発声メッセージを出す前に、念のため必ず受信バッファーをクリアしておけば良い。この問題もロジアナのおかげ一発で解決した。いやあ、ロジアナさまさまである。

 数字の入力で、AquesTalkが数字を読み上げるコマンド(<NUM VAL=XXX>)を新設し、テストする。よーし、順調だ。キーボードから、数字を入れては読み上げさせ、悦に入る。次はいよいよP-10からの出力である。

データの取りこぼしが多い(1/11/2014)
 すんなりAquesTalkの数字読み上げが出来たので、勢いづいて最後のステップ、P-10からのデータの読み上げに進む(ステップ4)。これが出来れば、ブレッドボードでの実験は一段落で、次の実装のステップに入れる。電池仕様を考えているので省電力化を考えねばならない。

 ソフト開発をさらに進める。コンソール入出力に使っていたソフトUARTの部分をP-10につなぎ換え、コマンド応答の部分を削除して、前に作ったP-10データ変換の部分を復活させる。動作確認をLEDにしようと思っていたが、P-10の方のUARTの出力側は使っていないことに気づいた。

Ws000000  そうだ、これをデバッグ用に使えば、動きを完全に把握できる。LEDより遥かに沢山の情報を出せる。AquesTalkに送るデータと同じところに、P-10側の出力を使って前と同じようなメッセージが出るようにする。これはうまくいきそうだ。

 半日でソフトが完成した。意気揚々とコンパイルする。ありゃ、コンパイルエラーがなかなかとれない。ルーチンが複雑になってきて、プログラムの最後の制御ループの整合性がおかしい。どうも}の数が合わない。頭を冷やして最初から見直してやっと原因をつきとめた。

 一番最初のfor(;;)ループの次の{がUARTを切り替えるときにコメントと一緒に消えていた。「デバッグは外へ外へ」の格言どおりである。一生懸命、プログラムの最後の}の数を調べていてもわからないはずである。

 コンパイルエラーがとれた。ほとんどのコードは動作済みなので、一発で動く公算は高い。わくわくしながら電源をONする。よし、初期化が終了したメッセージが出た。P-10の電源を入れる。おおお、読み上げ始めた。良いぞ。しかし読み上げる数値が出鱈目だ。

 ときどき合う時もある。暫く様子を見る。同時に出るPCコンソールのUARTのデータがそもそもおかしい。デコードの部分が悪いのでなく、読み込んだデータが間違っている。気を落ち着けて原因究明を考え始める。

データは出たが古いデータの読み上げばかり(1/12/2014)
 すぐに思い当たったのが、UART読み込みである。AquesTalkの読み上げは平均で2秒近くかかっている。それに対してP-10が出すデータの頻度は、1秒に3回近い。ああ、これはバッファーのオーバーランに違いない。

 現在のルーチンは、バッファーからデータを取り出すときに、P-10のデータフォーマットの特性を生かして(上位4ビットがデータシーケンス番号)、決められた配列にデータを移し、最初のデータを読んだ時、必ずこのデータ配列をクリアして正確な1ブロックのデータを得るようにしている。

 しかし、その前の生データが汚れてしまっていては何にもならない。このデータフォーマットは2バイトでひとつの数字をデコードする構造になっているので、厳密にデータが揃っていないと出鱈目になる。

 ソースを確かめる。なんだ、ここのバッファーサイズは16バイトしかない。これではパンクするはずだ。80バイトに広げて再度テストする。殆どエラーはなくなった。しかし、今度はバッファーが大きすぎて、最新のデータの発声が遅れる。

 AquesTalkが発声している時は、割り込みルーチンが動いてせっせとデータを貯めこみ、制御が戻ってきた時にバッファーの古いデータから読み始めるからだ。まあ、厳密な機械ではないので少々遅れても問題はないのだが、大分前の表示が声になって出てくるのは気分が良くない。

 割り込みルーチンに最新のデータを渡すような仕掛けにしないとまずい。しかし、受信割り込みのところで余り時間をとられると、AquesTalkにデータを送るときのUARTに差しさわりがでる可能性がでてくる。このあたりが難しい。

思い切ってデータを捨てる(1/13/2014)
 AquesTalkが喋っている間は、マルチメーターP-10のデータ送信は止めておきたい。しかしP-10のUART送信を制御することは出来ない。しかもP-10側のUARTはソフトUARTなので簡単にUARTをdisableには出来ない。

UARTは非同期通信なので最初のスタートビットの把握が命である。ここからボーレートに応じた時間を8ビットとってデータを取り込む。受信割り込みは常にスタートビットで起きないといけない。下手に途中で止めたり、スタートさせると目茶目茶なデータになる。

 最新のデータだけをワンセット(14バイトが1ブロック)残しておくという手順はそう簡単には思いつかなかった。寝床に入ってからも、あれこれ考えていた。こういうことは下手をすると不眠の原因になるが、久しぶりのソフト開発が面白くてつい寝ながら考えてしまう。

 現役の頃なら、明日のことを考えて余計眠れなくなるところだが、気楽な年金生活者にとっては、そんな心配も無用である。逆にかえって早く寝付けてしまう。面白いものだ。現在の境遇の有難さをかみしめる。

 こういう問題解決のノウハウも、デバッグと同じで「外へ、外へ」である。問題そのものを突き詰めるのでなく、その環境の前提をもういちど基本から考え直す。そういうことから言えば、データが直前の情報でないと絶対まずいわけではない....そうか、何も難しく考える必要はなかった。

 UARTのバッファーにデータを貯めるのを止めようと思っていたが、何もとめる必要はない。喋った直後にデータをとりなおせば良い。1秒に3回はデータが来る。喋った後、一旦バッファーをクリアし、新たに最新のデータを読んでそれをP-10のデータにすればよい。そうか、これは素晴らしい解決だ。

 早速、ソフトを修正する。仕掛けはとても簡単で、受信データをフラッシュ(クリア)する関数(データポインターを等しくするだけ)を追加し、これをAquesTalkの発声終了を待って発行するだけである。

 試してみる。見事に最新のデータをAquesTalkが喋るようになった。嬉しくて動画(音付き)を撮る。ちょっと音が悪いが読み上げている様子が何とかわかると思う(冒頭に表示)。

回路図とソースコードの公開(1/14/2014)
 本体はまだブレッドボードにあるだけだが、開発が一段落したので、このあたりで回路図とソースコードをウェブに公開することにする。実装版には、AquesTalkの動作状態を示すLEDなどを付けたいのだが、AquesTalkをすぐにでも動かしたいという方のためにとりあえずご紹介することにした。

Aquestalk_reader ソースコードには多量のデバッグ用のUART出力メッセージを出すコードが残っている。これは入れておいても実害はない(ハングしない)ので、残すことにした。またPCコンソール入力からP-10のデータに変換する部分(ステップ3)も参考になるかと思い、あえてコメントとして残した。

マイコンは、Mega328Pを使っているが、現在のフラッシュサイズは4KB以下なので、Mega88程度で十分である(もっとも価格は殆ど変わらないが)。スピーカーは、秋月の録音再生キットに付属していた小さなダイナミックスピーカーで、このあたりはもう少し考えたいところだ。

 使い方は簡単で、電源を入れると、「準備が出来ました」というメッセージが出る。P-10の測定レンジを所定のところへ回せば、勝手に読み上げてくれる。読み上げる数値は、AquesTalkが喋り終わった直後のメーターの表示である。電源を入れた当初は、どのデータが読み上げられるかは不定である。

 現在は、同じ数値のときも発声する。長期間データをログするときは止めた方が良いかもしれない。省電力化のためにクロックを下げ、スリープを使うことも必要か。

 例によって、AVRStudioのフォルダーの形でソース一式をzipで固めたものを以下に置きます。回路図のce3ファイルも中に入っています。

「aques168.zip」をダウンロード

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

« 2014年1月5日 - 2014年1月11日 | トップページ | 2014年1月26日 - 2014年2月1日 »