« ピンクの電線が幅狭のリールでやってきた! | トップページ | パナの単4アルカリ電池に何があった?! »

2019年12月20日 (金)

Arduino UNOで周波数カウンタ

ありきたりなタイトルですが、目的は「VCOの直線性を調べる」ツールの
予備実験です。
   VCO:制御入力の電圧変化に従って出力周波数が変化するというデバイス。
これの特性を調べるためのジグ作りの前段階です。
周波数カンタが出力するシリアルデータを横取りしてごそごそするより、
Arduinoで作るのが手っ取り早いかと、まずは周波数測定の部分を試し
てみました。

「arduino 周波数カウンタ」
で検索するとあれこれサンプルが出てきます。
ざっと見たところ、
  Arduino Frequency Counter Library
を参考にされている記事が多いようです。
Arduinoの開発スタイル、どこかにあるスケッチやライブラリを探してきて、
それでもって簡単に作ってしまおう・・・ こんな感じかと。

この周波数カウンタ・ライブラリ、どんなものかざっと見てみますと・・・
・タイマー1のT1をクロック入力に。
・タイマー2を1mSタイマーにして割り込み許可。
・周波数計測を開始すると、
  タイマー0割り込みを禁止。(millisやdelayが使えなくなる)
  1mSごとにタイマー1のオーバーフロー(16bitカウント)を見て
    オーバーフローがあれば回数を+1。
・計測の完了は、
  指定回数の割り込みが完了(100回なら0.1秒=10Hzがゲート時間)
    すると、タイマー1を停止。タイマー2割り込みもオフ。
  オーバーフロー回数×65536+TCNT1で総カウント値を得る。
  この時、割り込み処理のための遅れをちょい時間待ちして補正。
  計測完了フラグをONして知らせる。
  タイマー0割り込みを再開。
こんな処理になってます。
つまり、カウント値を計数するための時間ゲートの処理はソフトウェア。
ソフト的な遅延があると誤差が生じます。
  ※周期的な割り込みを発生するタイマー0は止めていますが。
「計測を始めたら、計測が終わるまで何もするな」の処理というわけです。
計測中はシリアル出力もできないし(割り込み処理が入る)、割り込みを
使う処理とは共存できません。

※もうひとつ気になったのが、ゲート時間終了後タイマー1を止めるまで
 delayMicrosecondsで時間遅れを補正してるんですが、この間に発生した
 オーバーフローは無視しています。
 たまたまこの待ちの間にオーバーフローが起こったら65536カウント
 抜けてしまいます。 ちょいとまずいような。

このライブラリ、ちょいと不安だし計測中は何もしたらダメという仕様が
気になって自力製作することにしました。

※改善点
・主カウントに16bitのタイマー1を使うのは同じ。
・そのインプットキャプチャー機能を使う。
・ゲート時間の発生はタイマー2で行うが、
 タイマー2で1kHz方形波を発生させ、それをタイマー1の
 インプットキャプチャー端子に接続。
・つまり、物理的なゲートを構成し、ソフトの処理時間を無視
 できるようにする。  (遅れ補正などしなくて良いように)
・1kHz方形波の↓エッジでインプットキャプチャ割り込み。
    TCNT1の値がICR1に入る。
   前回とのカウント差を積算して総パルス数を得る。
     ※upカウントなのでオーバーフローは気に
      しなくて良い
・1kHz方形波の↓エッジのタイミングでゲートが作られるので
 ソフトが遅れても(割り込みが遅れても)誤差は出ない。
・測定完了待ちを待たなくても動き始めたらいつでも最新値を
 読める。 (1秒ゲート完了信号はある)
・割り込みがあってもOK。 タイマー0は止めない。

こんな具合にArduino UNOをつなぎます。
V1
こんなスケッチです。
ダウンロード - vcochk1.c (ファイルタイプをinoではなくcにしてます)
setupではATmega328のレジスタを直接触っています。

得られた周波数データを読む時は「割込禁止」にしてという
のが、割り込みで処理される多バイトデータを扱う時の基本です。

VCO性能の試験回路完成まではまだもうちょっと。 



※参考にした 「FreqCounter Library」の「FreqCounter.cpp」で
気になるところ。 タイマー2による1ms割込の処理。

ISR(TIMER2_COMPA_vect) {
 if(FreqCounter::f_tics >= FreqCounter::f_period){ // ゲート時間になった
  delayMicroseconds(FreqCounter::f_comp); // 時間補正でちょい待ち★1
  TCCR1B = TCCR1B & ~7;   // タイマー1停止★2
  TIMSK2 &= ~(1<<OCIE2A);  // タイマー2割込オフに
  TIMSK0 |=(1<<TOIE0);    // タイマー0割込再開
  FreqCounter::f_ready=1;   // データ確定
  FreqCounter::f_freq=0x10000 * FreqCounter::f_mlt; // 総カウント数
  FreqCounter::f_freq += TCNT1;   // 現カウント値を加算
  FreqCounter::f_mlt=0;
 }
 FreqCounter::f_tics++; // 割り込み回数+1
 if (TIFR1 & 1) {       // オーバーフローあれば★3
  FreqCounter::f_mlt++;  // mltを+1
  TIFR1 =(1<<TOV1);
 }
}

ここでタイマー1のカウント値を積算しています。
  ・オーバーフロー回数をカウント
  ・オーバーフロー1回で65536カウント
  ・タイマー停止後にTCNT1値を加算
というふうに総カウント値を得ています。

気になるのは★1と★2の間。
ここはまだタイマー1は動いていてカウントを継続しています。
もしここでオーバーフローが発生すると、総カウント値に反映
されません。
★2のあとに★3の処理を入れておかないといけません。

計測終了間際の一瞬ですんでまぁめったに起こる現象ではないでしょう。
しかし、起こるとアウト。周波数が低く測定されてしまいます。
現象をおこすの、むちゃむつかしそうです。

これ、オーバーフロー回数の積算をオーバーフロー割り込みでやる
のも手でしょう。
その時は、このタイマー割り込み内では割り込みはかかりませんから、
タイマーを停止する間、いったん割込許可にしとかなくちゃいけません。


※さらに
私が持ってるArduino UNO、発振子がセラロックになってます。
cstce16m0v53-r0
だもんで、周波数や周期がらみの処理をする時はちょい不満。
実測0.075%ほど周波数が高い。
セラロックの定格仕様だと±0.5%ほどなんでまだましかっと。
・・・水晶に変えてしまおうか


※水晶に変えました
セラロック発振子を外したところ。
ハンダを盛ってハンダゴテを当て、ピンセットでそろりと。
11_20191221105301

水晶は普通のHC-49U/S。
コンデンサは1608サイズのチップコン。
互い違いに置いてハンダ。
12_20191221105301

絶縁テープを貼って、水晶は寝かせています。
  これからほホットボンドで固定します

結果、発振周波数の精度「+23PPM」に。

※入力クロックのエッジとICPのタイミングのズレで
ICPごとに1クロック落とすかもしれない。
  (うまく数えてくれるか落とすかは運次第)
ICPの回数を減らす(ICPの周波数を下げる)しか
方法がないか。

※Arduino Frequency Counter Library 異常カウント現象
2021年5月4日:Arduino周波数カウンタ:FreqCounter Libraryを使った時のカウント異常を再現

|

« ピンクの電線が幅狭のリールでやってきた! | トップページ | パナの単4アルカリ電池に何があった?! »

電子工作」カテゴリの記事

Arduino」カテゴリの記事

コメント

※関連
・2020年8月16日:Arduino UNOのPWM出力を(ちょっと精密に)確かめる
http://igarage.cocolog-nifty.com/blog/2020/08/post-ba853b.html

・2020年8月13日:Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう
http://igarage.cocolog-nifty.com/blog/2020/08/post-0d2777.html

・2020年2月10日:ArduinoのanalogWrite 1/255なの?
http://igarage.cocolog-nifty.com/blog/2020/02/post-d4c821.html

・2020年2月 4日:Arduinoのタイマー OCRレジスタは「n」じゃなく「n - 1」の値を設定せよ
http://igarage.cocolog-nifty.com/blog/2020/02/post-c1f98a.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年8月16日 (日) 17時18分

2020年8月24日:Arduino PWM波形のデューティー比測定 これで完成形か?
http://igarage.cocolog-nifty.com/blog/2020/08/post-af3683.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年8月29日 (土) 16時26分

参考に
・2021年1月15日:アナデバの電力計用IC、arduinoで周波数(周期)を計る
http://igarage.cocolog-nifty.com/blog/2021/01/post-862b4b.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2021年1月16日 (土) 11時13分

・Arduino UNOで周波数カウンタ:アナデバの電力計用ICのために
http://igarage.cocolog-nifty.com/blog/2021/05/post-b7b463.html

ゲート時間を「1秒」にして周波数を計ってみます。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2021年5月 1日 (土) 13時47分

電力計測の続き
http://igarage.cocolog-nifty.com/blog/2021/05/post-f62f11.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2021年5月30日 (日) 22時30分

コメントを書く



(ウェブ上には掲載しません)




« ピンクの電線が幅狭のリールでやってきた! | トップページ | パナの単4アルカリ電池に何があった?! »