これは?

パソコンを利用してミリ秒単位の時間を測定するものです。レースのラップタイムなど低頻度(毎秒数回以下)だが間隔が長いスイッチOn/Offの測定に向いています。以下に他の方法との比較を載せます。

方法長所短所
市販のオシロスコープ非常に高精度非常に高価
サウンドカード安価かつ高精度On/Offの頻度が低いと信頼性確保が困難 (*1)
OSが提供する時間関数追加費用無し・扱い易い低精度 (*2)
本方法最長5日弱に渡る測定が可能回路とプログラムを作らないといけない・激しい繰り返しには追従できない
*1
サウンドカードの入力にはDCをカットする回路が搭載されていることが多く、On/Offの頻度が低いと測定値が徐々に0に近づきます。サウンドカードにもよりますが、On/Off間隔が1秒以上だと現実的ではありません。
*2
少なくともWindowsの時間関数はミリ秒単位では不正確。たとえ正確でも、外部センサーの変化を検出し時間関数を呼ぶ部分にかかる時間が不安定。

特徴

適さない使用法

回路の写真

右側ユニバーサル基板部分に載っている白いIC(フォトカプラ)やヒートシンク(電圧レギュレータ)、及びそれより右のコネクタ類はこの時使用したセンサとの接続用で、用途に応じて変更が必要です。

回路写真

動作説明

接続

接続図

AVRの動作

AVRでは割り込み処理により10KHz・毎秒1万回内部カウンタを増加させています。 この時PB0-PB7の状態が前回と変化している場合その時のカウンタの値を記録、USBを通してPC側にカウンタ値とポートの番号を連絡します。 PC側はこのカウンタ値を前回のものと差を取ることで時間を測定できます。

動作説明図

PC側の動作

プルアップされたPB0とGND間にスイッチが接続されているとします。スイッチOffの時はPB0=Highとなり、OnでLowとなります。 BGCNT(後述)コマンドで内部カウンタをスタートした後スイッチを押すと、PCは以下のデータを受け取ります。

PRTRG 00 0 25460

00はポート番号、0はPB0=Low、25460がその時の内部カウンタとなります。 この時点では内部カウンタの値はあまり意味を持ちません。BGCNTコマンドが処理されてから2.546秒経過したというだけです。 後述注意点でも述べますが、PCがBGCNTコマンドを送ってから実際AVRが処理するまでの時間は不安定ですので、2.546秒=PCがBGCNTコマンドを発行してから経った時間とはなりません。

次にスイッチをOffにするとPCは以下のデータを受け取ります。

PRTRG 00 1 31621

00がポート番号、PB0=High、カウンタ値31621。PC側ではこの二つのカウンタ値の差6161=0.6161秒がPB0に繋がれたスイッチがOnであった時間と知ることができます。 この時間はPC-USB間の通信の依存しないため、ミリ秒単位で信頼できるものとなります。

応用

AVR側は単純な機能しか提供してませんので、どう使うかはPC側のプログラム次第ということになります。

注意点

ミリ秒という時間測定に対しては、PC-AVR間通信にかかる時間は不安定であると考えたほうがいいです。これは主に以下の処理にかかる時間がミリ秒単位では不安定なためです。

よって以下の注意点が発生します。

回路図

特に特殊なことはしてません。ストロベリーリナックス社のAVR-USBマイコンボード AT90USB162を使用すると作業がかなり楽になると思います。

回路図

PDF形式

AVR用プログラム

書き込み用Hexファイル

AVR内蔵プルアップ有効の有無の違いで二つのHexファイルを用意してます。Atmel FLIPなどを使ってAVRに書き込みます。

ソースファイル

AVRのソースをコンパイルする知識があることを前提にしています。AVR StudioWinAVRに関してはここでは説明しません。

  1. AVR USB Series2 software library template Revision 2.0.0を適当なところに展開
  2. cdc_task.cをこのページにあるもので置き換え
  3. demo\STK526-series2-cdc\conf\config.h内の#define FOSC 8000を16000に変更
  4. AVR Studioでビルドする。コンパイラにWinAVRを使用してerror: expected expression before 'do'とエラーが出る時は、lib_mcu\power_drv.hを以下のように()を外します。
  5. #ifdef  __GNUC__
       #define Clear_prescaler()   (clock_prescale_set(0))
        ↓
       #define Clear_prescaler()    clock_prescale_set(0)
    

PC側プログラム

ドライバ

Windows(98SE以降?)ではドライバはOS標準で提供されていますが、INFファイルが必要です。

Linux/Macその他のOSでも、USBで規格化されているCDC(Communication Driver Class)をサポートするドライバを使えばなんとかなるはずです。後日機会があれば更新します。

アプリケーション

目的によりアプリケーションの形態が大きく異なりますので、汎用的なものはここでは提供しません。 以下に示すコマンド表を参考に目的にあったものを作成してください。

Windowsの場合、通信はCOMポートと扱われます。 何番ポートに割り当てられるかは環境によりますが、上記のINFファイルを用いた場合COMポートには「AT90USBxxx CDC USB to UART MGM」の名前がつきます。 TeratermなどCOMポートを扱えるターミナルソフトを使えば手動でコマンドを実行することも可能です(基本的には専用アプリケーションと通信するように設計されています)。

チャタリング制御

チャタリング制御として、ある一定回数連続しないと状態が変わったとみなさない機能を備えてます。 例えばチャタリング制御値が5でPB0がHigh→Lowになる場合、Lowが5カウント連続(0.5ミリ秒)続かないとLowになったとしません。 チャタリング制御値はSTCHTコマンドで設定、PRCHTコマンドで確認できます。値の範囲は0-65535(6.5535秒)です。 設定した値はAVRのEEPROMに書き込まれ、次回以降も有効です。

校正

構造上、測定時間の精度はAVRの駆動クロックのそれに直結しているため、水晶発振器などなるべく高精度なクロックの使用を勧めますが、それでも微妙な誤差が出ます。 より厳密な測定を求めるなら、校正を行ったほうがいいでしょう。

方法の一例としては、NTP(W32TimeサービスではなくNTPDなど)などで時計を調整したPCにAVRを接続、 ある時間をおいてPRCNTコマンドを実行し、理論値毎秒1万カウントからどれくらいずれているかを見ます。 何度か述べているとおりPRCNTコマンドはPC-AVR間通信による不正確さを含みますので、その影響を打ち消すためPRCNTコマンド発行間隔を長くしたり、何回か行って平均をとるといいでしょう。 ちなみにこの方法でストロベリーリナックスのボードを使い、24時間かけて測定してみた所毎秒9999.67カウントでした。

校正値を管理するコマンドとしてSTCLB/PRCLBを用意してますが、この値はAVR側のプログラムになんの影響も与えません。 あくまで個体ごとの値を記録するためだけのもので、どういう値を記録するかを含めPC側のアプリケーションに任されています。 私の使用例としては前述の結果から1E+9*10000/9999.67を記録し、使用時には(カウンタ値の差)*校正値*1E-9を測定時間としています。

コマンド表

送信受信内容
BGCNTBGCNT内部カウンタを開始します(USBに接続した直後は停止してます)。PD0にLEDを接続している場合は、点滅を開始します。
ENCNTENCNT内部カウンタを停止します
PRCNTPRCNT カウンタ値現在のカウント値を表示します。PCがコマンドを発行してからAVR側で処理するまでの時間が誤差として含まれます。
STCHT 値STCHT 採用された値チャタリング制御値を変更します。最大値は65535です。
PRCHTPRCHT 現在の値現在のチャタリング制御値を返します。
STCLBSTCLB 採用された値校正値を変更します。最大値は4294967295です。
PRCLBPRCLB 現在の値現在の校正値を返します。
PRREVPRREVAVRプログラムのリビジョンを返します。
PRCLKPRCLK クロック プリスケーラ コンパレータAVRプログラムで設定されているクロック、プリスケーラ、コンパレータの値を返します。この組み合わせで10kHzになるはずです。詳しいことはAVRプロセッサの仕様書Timerに関する記述を参考にしてください。
(不正なコマンド)INVALID COMMAND間違ったコマンドを入力したときに返します。
(なし)PRTRG ポート番号 新状態 カウンタPB0-7の入力が変化したことを通知します。新状態は1=High/0=Lowです。

履歴

2010/9/25
リリース