2009年3月27日金曜日

TinyでDRO!(ソフトウェア1)

ソフトウェアの説明です。例によってSourceForgeで公開します。


ヒューズの設定はZIPファイルの中のFuseMapping.jpgにAVRStudioの(中のAVRProgの)設定画面のスクリーンショットを入れてありますので参考にしてください。また、ソースコード中にもコメントで書き込んであります。要は内蔵RC発振器をONにして、1/8分周をOFFにするということです。

今回のプログラムの要点は、スケールから送られてくるデータをクロックに同期して取り込むこと、そして直列で送られてくるデータを切り出し---つまり頭出し---することです。

まずマクロな視点から。データブロックは約0.3秒の間隔でスケールから出力されています。


クロック(CLK)は出っぱなしではなく、データ(DATA)が送られるときのみ出ているのが分かります。クロックが出ていないときは論理"0"(-1.5V電位)にスタックしています。データブロックの部分をクローズアップしてみます。


クロックはデータ出力開始直前に"1"(GND電位)となり、しばらくしてからクロッキングを始めます。クロック周期は約12usですので、周波数にすると約83kHzです。

データは2種類送られてきます。先に絶対座標のデータ、後に相対座標のデータです。絶対座標はそのスケール固有の位置情報で、原点が絶対にずれることはありません。相対座標はスケールのゼロクリアボタンを押すごとに原点を設定するもので、通常はこちらが使われることになります。

これらのデータは24ビット長で、クロックパルスに同期して順次最下位ビットから送り出されます。図でA0~A23が絶対座標、R0~R23が相対座標です。R24(ダミー)と書いてあるビットがありますが、これは本来は取り込まないビットで、後ほど説明します。

図で分かる通りクロックの立下りエッジでデータを取り込むとよさそうな感じです。実際のプログラムでは、AVRに入ってくるときにレベルシフタにより論理反転していますので、クロックの立ち上がりエッジで捉えることにしています。ここでファイル"interrupt.c"の該当部分。(コメント部分で改行されてしまい読みにくいのでコメントをちょっといじってあります。)

// スケールからのデータ取り込み。検出エッジは立上がりエッジ。
ISR(INT1_vect)
{
*Rbufp++ = SCALE_PIN; /* 読んでバッファにためる */
if (Rbufp >= Rbuf + sizeof(Rbuf)) {/*バッファ端*/
Rbufp = Rbuf + sizeof(Rbuf) - 1;
Updated = 1; /* main()に更新を通知 */
}
TCNT1 = 0; /* 送信間隔タイマーをクリア */
}
INT1は立ち上がりエッジを検出するように設定されています。重要なことは割り込みセンスから割り込みプログラムが起動されるまでの時間がかなりかかることです。あまり時間がかかるとデータを読みそこなってしまいます。割り込み処理のシーケンスは、
  1. INT1エッジ認識
  2. 割り込みハンドラに分岐
  3. 使用するレジスタ群を退避
  4. ユーザの定義した割り込み処理プログラムを実行
上記の1.から2.までで約4クロックかそれ以上かかり、これはAVRハードウェアによるオーバーヘッドですので回避不能です。3.はコンパイラの出力するコードによるオーバーヘッドが含まれ、アセンブラで書かない限りは制御はやっかいです。コンパイラのアセンブラ出力を見るとここに16クロックかかっていることが分かります。そこでこの割り込み処理では、スケールのDATAがつながっている入力ポート(上記リストの"SCALE_PIN"=PIND)を何はともあれ読み込んで、バッファにためることだけを行っています(52行目)。その際にそのビットを抽出するなど余計なことはやっていません。ちょっとでも複雑なことをしようとすると、コンパイラはためらうことなくたくさんのレジスタを使おうとして、それらを退避するコードを割り込み処理の冒頭に突っ込んでくるからです。

今回データ読み込みはすべてクロックの立ち上がりエッジ(タイミング図上では立下り)で検出しているので、前出のタイミング図では、データ送出終わった後にクロックが"0"スタックする時点でもうひとつ検出エッジが来てしまいます。これが「R24(ダミー)」と書いてあるゆえんです。プログラムではこの部分も愚直に読み込んでしまうことで、割り込みプログラム中の無用な条件判定を回避しています。読み込んだとしても値を集計するときに使わなければいいのです。

2009年3月25日水曜日

TinyでDRO!(ハードウェア2)

このプロジェクトで何が一番難しかったかって、デジタルスケールにどうやってケーブルを接続するか考え出すことでした。プラグインできる汎用のコネクタなどありませんし、かといってケーブルをじかに出すのは気が引けるし。逡巡したあげく結局どこかのサイトで見た、コネクタヘッダをはんだ付けする方法を取りました。出来上がりはこんな風になります。



スケールを完全に分解する改造です。メーカー保証はあきらめましょう。分解して基板をむき出しにしたら基板用コネクタヘッダをはんだ付けします。基板エッジにでている接点パターンは、きちんと計測すると1.65mmピッチくらいだということが分かるのですが、ここでは2.0mmピッチのこれを使いました。4ピンなのでぎりぎりこれでも大丈夫です。ただ、このコネクターは非常に熱に弱くて少しでも余分に長くこてを当てようものならコネクタハウジングが融けてピンが泳ぎだすのが難点です。少々高くても他のメーカーのものを使うのが賢明でしょう。なお、分解しないで無理やりはんだ付けする方法もありますが、スケールのケースが溶けるのでお勧めはできません。後述のコネクタカバーが閉まらなくなってしまいます。



組み立てる前にスケールのプラスチックカバーの加工をします。下の写真の緑の四角で囲んである部分を削り落します。こうしないとコネクタヘッダの下半分が干渉してしまうからです。



組み立てた後はこうなります。


このままだとコネクタカバーが閉まりませんのでこいつも加工します。左下から11.0mm×2.5mmだけ削り込んでやると…

下側の「ツメ」がぎりぎり0.5mmほど残ります。このおかげでパチンと小気味よくカバーが閉まります。このポストの最初の写真がカバーを閉めたところです。

2009年3月19日木曜日

TinyでDRO!(ハードウェア1)

このシステム全体は+5V電源で動作するようになっています。5V出力のACアダプターで直接給電です。それを前提に回路の説明です。

図の左端にはスケールからのクロックおよびデータの信号入力があります。スケールの電源は電位の高いほうがフレーム=GND電位で、低いほうが-1.5Vと通常とは逆の電位になっているので、C3およびC4による容量結合で4049(hex inverter, IC1)でレベルシフト、増幅しています。4049から出力された両信号は元の信号の反転になっています。これらはTiny2313のポート入力につながります。

左上のNチャンネルMOSFET uPA2753GR(Q7)はゼロクリアをスケールに対して送るためにあります。ポート出力でスケールのGNDとクロック線を(抵抗を介して)ショートさせます(スケール本体のZEROボタンを押したのとまったく等価と思われる)。

図の上半分はLEDドライブ回路です。Tiny2313の少ないポートでこれだけのLEDセグメントを駆動するためダイナミック点灯をさせることにします。数字が6桁すなわちデューティ1/6なので、見掛け上の明るさを稼ぐために1セグメントあたり20mAずつ流します。1コモン端子あたりの最大電流は、7セグメント+1DPで8素子ですから×8で、160mAです。ドライブ用トランジスタをポピュラーな2SA1015ではなく2SA950にしたのはこのためです。実は160mAというのはTiny2313の「全ポートのIOLの合計が60mAを超えるべきではない」という注意書きから外れています(前モデルの90S2313にすればこの条件が100mAと若干軽減されます)。本来ならばドライバトランジスタを挿入するべきでしょう。…が、とりあえず動いているのでまあいいかと。

LEDコモンのドライバトランジスタの選択に74HC138(3-to-8 decoder, IC3)を使用しています。Tiny2313のピン数が足りないための苦肉の策。リセット直後のポート出力が確定していない時期に、特にフラッシュ書き込みを行っている最中に変な表示が出ないように、リセットが利いている間は出力を禁止するようHC138のG1にリセット線を接続しています。

図の右下にダイオードを介してスイッチがつながっているのが見えます。LEDの(ダイナミック点灯のための)スキャンをキーのスキャンにも利用しているのです。これもやはりポートが足りないのが理由です。LEDはダイナミック点灯により約360Hz周期で切り替えますので約60Hzで1周します。キーのスキャンにはちょうど良いくらいの周期です。この方法ならばあと4つもスイッチを増やすことも可能です。なおダイオードと反対側のスイッチの端子は1つの入力ポートに集められます。この入力ポートはプルアップされてなければいけません。ダイオードの役割は2つのスイッチが同時にONになったときHC138の出力同士がショートしてしまうのを防ぐためにあります。逆流防止ダイオードとかいいますね。

Tiny2313にはセラロックが接続されているように書いてありますが、内蔵のRC発振回路で十分だということが分かりましたので、実際は接続しません。ただ、90S2313を使用する場合は必要です。RC発振回路が内蔵されていないからです。

回路の簡単な説明でした。次は基板を設計してOLIMEXに発注するのですが、先人が苦労されてきたとおりやはり最初は一筋縄ではいかずちょっと苦労しました。その話はまたいずれ。

基板が届くまでにずいぶんと時間がありますから、その間にソフトのコーディングとブレッドボードによるプロトタイピングです。これはそのときの様子です。ここまでちゃんと動くのに結構悩みました…。

2009年3月18日水曜日

TinyでDRO!(概要)

以前このブログでデジタルスケールをフライスに装着した話を載せました。その中で、「そのうちLEDの表示器作ろっと」と書いたとおり作ってしまいました。

まずは先例の調査から。ググるためにはまずキーワードが必要です。「デジタルスケール」ちゅう言葉は実は「デジタル式の秤」--つまりキッチンスケール--の意味のほうが(英語でも)一般的らしい。いろいろ探し回ったところ、こういうのは「DRO (Digital Read-Out) 」と言うのだということが分かりました。NCフライスなどを使ったことのある人にとっては当たり前のことかもしれませんが、知らなかったなぁ…。あと、まったく同じメカニズムを持つ「デジタルノギス」「Digital Caliper」なども検索キーワードとしては役に立ちました。

果たして信号の解説をしているサイト(ここここ)や製作例を掲げるいくつかのサイト(ここここ)が見つかりました。信号の解説をしているサイトによれば、また、自身で測定してみたところこのデジタルスケールの信号は以下の特徴があることが分かります。
  • クロック線と1本のデータ線を持つ同期式シリアルである。
  • 電源はGNDと-1.5V。GNDはフレームに落ちている。
  • データは24ビットの2の補数で、最下位ビット(LSB)から送られてくる。
  • 1回のデータ送信で2つのデータ--先に絶対座標、後に相対座標--がつながって送られる。
  • データの送信間隔は約0.3秒。
  • クロックの周波数は約80kHz。データ送信していない間は-1.5Vに固定されている。
  • データの取り込みはクロックの立下りエッジで行うのが妥当。
  • 外からクロック線をGNDレベルに落とすことでゼロクリア信号入力となる。つまりZEROボタンを押したのと同じ。
  • 外からデータ線をGNDレベルに落とすことでモード切換え入力となる。これ相当のボタンは本体にはない。
  • スケール本体の電源がOFFでも信号だけは出力され続ける(液晶画面は消えている)。
負電圧になっているのが嫌だなあと思いつつ、ここは挑戦です。以下の目標を掲げて突進です。
  • とにかく安い部品を使って仕上げる。そのためATTiny2313を使う。できれば部品箱に眠っているAT90S2313でも動くようにする。
  • 軸ごとの独立とする。つまり、X・Y・Z軸それぞれに1基板を使う。
  • ボタンはゼロクリアとミリ/インチ切り替えのみ。
  • 枚数の少ない試作基板では一番安価と思われるブルガリアのOLIMEXに基板を発注する。
  • 最近になって秋月で販売し始めたプラスチックケース(195×110×76mm)に収める。これは500円で非常に安価だ。
  • スケール本体から出すケーブルにはUSBケーブルのデバイス側をちょん切って使う。切ったところに2mmピッチ×4ピンのコネクタをつける。
  • スケール本体から出るケーブルとDROの接続はUSB(A-Type=ホスト側)を使う。安く上げるため。A-Typeメスのパネル取り付け用ケーブルが2本入りで280円(@千石)。
  • 基板以外は1軸あたり1,000円程度に抑える。
写真は完成して動作させているところです。上からX軸、Y軸、Z軸なのですが、Z軸にはスケールそのものがついていない(まだ買ってない…)ので消えたままになっています。次回はハードウェアの説明をします。