« 続・サーミスタで正確な温度を測るコツ - 基準抵抗(R0)、B定数、熱拡散係数、... | トップページ | VFコンバータ(VCO)の製作(3) - 自動周波数特性測定器に向けて »

2015年2月19日 (木)

GPS/RTC(DS3234)の1PPS出力を利用した超高精度周波数カウンター

(“データシートの上では”ですが)±10nsの不確かさを誇るGPS受信モジュールGM-5157Aの1PPS出力を使って不確かさ0.01ppm(のはず)の高精度周波数カウンタを作ってみました。つまり100MHzを測定しても最後の1Hzの桁まで正確(なはず)です。水晶発振器の温度係数を調べるというような目的を想定しています。

100MHzじゃPICが追いつかないでしょうが...
でもこれはハードウェアを追加すれば対応が可能だと思います。つまり100MHz超えでも1Hz単位で測定できる周波数カウンターは作れると思います(構想はしています)


その後の調べではこの周波数カウンターはそのままでもけっこう高い周波数まで測定が可能です。

  「
PIC18F26K22のカウンター(タイマー)の測定できる周波数の上限を調べてみた
  「
PICのタイマー(T1CKI)の使用可能最大周波数 - あるいはリングオッシレーターの発振周波数

100MHzが測定できるのは確認できたのでタイトルには100MHzというのを入れました。メーカーが保証する動作ではないと思いますが...
なお上限は未確認です。165MHzあたりが測れないのは確認済みです。

と書いてしまったのですが...

  「PICで作った100MHz周波数カウンターの動作検証で困った問題

タイトルから100MHzというのをはずします (^^;;


ほんとうに0.01ppmの不確かさの測定ができるかはわかりません。しかし「続・GPS受信モジュール GM-5157A vs GE-612T 1PPS対決」では“GM-5157Aの1PPS信号がGE-612Tに対しだいたい0.2μ秒先行して出力されているようだ”ということを書きました。逆に言うとこのときの1/800万分の1秒の分解能で調べても相対的な時間的な関係は保たれているわけで少なくとも0.1ppmつまり10MHzで1Hzくらいのところまで正しく測定できそうに思えます。それ以上の精度で測定できるかどうかは今後の課題です。
ただGPSの特性から言えばサンプル時間を長くすればどんどん精度は上がって行くわけなのでこれは他の方法では得られない大きなメリットです。


GPSの1PPS出力が面倒な方は秋月にもある“超高精度SPIバスRTC(リアルタイムクロック)DS3234S”なんかを使うといいと思います。1ppm以下の不確かさに持っていくのはGPSの1PPS出力との突き合わせが必要ですが、そういうことをしなくても少なくとも2ppm以下にはなると思います。DS3234Sの時計は一週間に1秒違うか違わないかくらいに正確です。
  「超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの実力
  「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方

 =======

具体的な作り方なんですがまずPICは18F26K22を使います。これはこの周波数カウンタを「PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計のソース - main()」の中に組み込もうとしているからです。

TIMER1を使うことにします(たぶん3でも5でも同じでしょう)
TIMER1/3/5にはTimer Gateの機能があるのでこれを利用します。

タイマーをカウント状態にしてもゲートが開くまで実際にはカウントされません。ゲートが開いたらカウントを開始しゲートが閉じたところでカウントが終了します。

ゲートをGPS受信モジュールの1PPS信号にします。ただこれだけだと1PPSがHighになったときだけ、つまり0.1秒間だけしかカウントされません。1秒間カウントするためにはTOGGLE MODEを使います。これを使うと最初の1PPS信号でゲートを開け、次の1PPS信号でゲートを閉じるようにできます。つまり1秒間ゲートが開きます。

周波数カウンタを作るのが目的ではなくすでにあるシステムに周波数カウンタの機能を組み込むのが目的なので周波数の測定は任意のタイミングでできるようにしたいです。このためにはSINGLE-PULSE MODEを使います。これを使うと一回カウントが行われると次にゲートが開いてもカウントはされなくなります。

タイマーは16bitなので最大カウント数は65535です。それ以上のカウントをするために割込みを使うことにします。TIMER1のオーバーフロー回数をTIMER3でカウントできる、とかあれば割込みを使う必要はなくなるのですがタイマーのブロックダイアグラムを見る限りそういう機能はなさそうです。この周波数計測中に割込みが発生するということがシングルパルスモードを使う理由でもあります。SDカードの入出力中に割込みが発生したりするとすべてがぶち壊しになります。

まとめると次のようになります。

・タイマーのソースはExternal Clock(T1CKIピン)とし、ここに測定対象の出力をつなぎます。

・タイマーゲートを有効にします。タイマーゲートソースはTimer1/3/5 Gate pin(T1G)とします。

・1秒間での計測を行うためトグルモードを有効にします(そんなに精度は要求しないときはトグルモードを無効にすればいいです。これだと毎秒計測可能です)

・ゲートの極性はGM-5157Aの場合はどちらでもそんなに違いはないと思いますが、1PPSの立ち上がりの極性に合わせていた方が余計な心配をしなくていいでしょう。

・一回限りの測定にしたいのでシングルパルスモードにします。

・タイマーゲートを使った場合ゲートが閉じるとT1GGO_NOT_DONEビットがLowに落ちますのでそれを待ってタイマーのカウント数を調べます。割込みの回数*65536+タイマーのカウント数が周波数ということになります。
(トグルモードをオフにした場合はこの数値に10を掛けたものが周波数です)

-------

この方法だとタイマーソースを周波数がわかっている信号源にし、タイマーゲートソースに未知の周波数を入れると周期がわかります。周期の逆数からタイマーゲートソースに入力された信号の周波数がわかります。
VFコンバータ(VCO)の製作(1) - 自動周波数特性測定器に向けて」にある周波数測定機能はこれを利用して作るつもりです。

-------

次に回路図になるわけですが面倒なのでどう結線されているかだけ書きます。

01 MCLR ..... プルアップ
08 VSS
10 OSC2 ..... FOSC/4出力
    FOSC/4をTimer1ソースの入力にしてテストに使います
    ソフト的に切り替えてももちろんOKです。
11 T1CKI ....  Timer1ソース、測定対象信号源に接続します。テストのときは隣のピンへ
14 SCL1 ..... I2C/SCL ..... LCD(AM3201)に測定結果を表示します
15 SDA1 ..... I2C/SDA ..... 〃
19 VSS
20 VDD
26 T1G .... Timer1 Gate、GPS受信モジュールまたはRTCの1PPS出力に接続します。


確度0.0005ppmの周波数測定 - GPSの1PPS出力を使った高精度周波数カウンタ
超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの実力
ほんとうに超高精度かもしれないRTC・DS3234Sを使った周波数カウンター
  へ続く
-----

関連記事のリスト

  趣味の電子工作
    PIC
  趣味の気象観測
  趣味の実験

-----

ソース

// PIC18F26K22
// 01 RE3/VPP/MCLR .....(1) .... プルアップ
// 02 RA0/C12IN0-/AN0 ..... 
// 03 RA1/C12IN1-/AN1 /..... 
// 04 RA2/C2IN+/AN2/DACOUT/VREF ....   Reserved DACOUT
// 05 RA3/C1IN+/AN3/VREF+ .... 
// 06 RA4/CCP5/C1OUT/SRQ/T0CKI .....   Reserved CCPイベント
// 07 RA5/C2OUT/SRNQ/SS1/HLVDIN/AN4 .... 
// 08 VSS
// 09 RA7/CLKI/OSC1 .... 
// 10 RA6/CLKO/OSC2 ..... FOSC/4出力(テスト用)
// 11 RC0/P2B/T3CKI/T3G/T1CKI/SOSCO .....  Timer1ソース
// 12 RC1/P2A/CCP2/SOSCI ..... 
// 13 RC2/CTPLS/P1A/CCP1/T5CKI/AN14 ..... 
// 14 RC3/SCK1/SCL1/AN15 ..... I2C/SCL ..... AM3201
// 15 RC4/SDI1/SDA1/AN16 ..... I2C/SDA
// 16 RC5/SDO1/AN17 .... つかっちゃまずい?
// 17 RC6/P3A/CCP3/TX1/CK1/AN18 ..... Reserved TX1
// 18 RC7/P3B/RX1/DT1/AN19 ..... Reserved RX1
// 19 VSS .....(3)
// 20 VDD .....(2)
// 21 RB0/INT0/CCP4/FLT0/SRI/SS2/AN12 ..... Reserved INT0
// 22 RB1/INT1/P1C/SCK2/SCL2/C12IN3-/AN10 ...... Reserved SPI/SCK
// 23 RB2/INT2/CTED1/P1B/SDI2/SDA2/AN8 ..... Reserved SPI/SDI
// 24 RB3/CTED2/P2A/CCP2/SDO2/C12IN2-/AN9 ..... Reserved SPI/SDO
// 25 RB4/IOC0/P1D/T5G/AN11 .... 
// 26 RB5/IOC1/P2B/P3A/CCP3/T3CKI/T1G/AN13 .... Timer1 Gate
// 27 RB6/IOC2/TX2/CK2/PGC .....(5)
// 28 RB7/IOC3/RX2/DT2/PGD .....(4)

#include <xc.h>

#include <stdio.h>

#include "..\..\include\common\MyDef.h" #include "..\..\include\common\I2CLib.h" #include "..\..\include\common\ACM1602lib.h" // C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html #ifdef _18F26K22 //#pragma config FOSC = INTIO67 #pragma config FOSC = INTIO7    // PIC発振周波数測定テスト用 #pragma config WDTEN = OFF #pragma config MCLRE = INTMCLR #endif // 割込みがあったかどうか確認するためのフラグです。 static int Interrupt=0; // センサーから読み込んだデータをLCDに16進表示するため // sprintf()を使いたくないとき用 void putLCDhex(unsigned char ch) {     char hex[]="0123456789ABCDEF";     LCD_Putc(hex[ch>>4]) ;     LCD_Putc(hex[ch & 0x0f]) ; } // 割込みがあったときはフラグを立てるだけで // 割込みルーチンの中では何もしていません。 void interrupt InterFunction( void ) {     // TIMER1割込み     if( TMR1IF == 1 ) {         Interrupt = 1;         TMR1IF = 0;     // I2C関連の割り込み処理     } else {         InterI2C() ;     } } void main() {     unsigned char i,F_High,F_Low;     unsigned int count=0;     unsigned long frq;     char buf[16];     OSCCON = MyOSCCON ; // for I2C     ANSELCbits.ANSC3 = 0;     ANSELCbits.ANSC4 = 0; // for Timer1 Gate     ANSELBbits.ANSB5 = 0;     // 1PPS出力がオープンコレクタでも使えるように     INTCON2bits.NOT_RBPU = 0;     WPUBbits.WPUB5 =1;     //  それぞれのビットの意味がわかるように書いています。     //  実際にコーディングするときはふつうに書いてください。     //  10 =Timer1/3/5 clock source is pin or oscillator:     //      If TxSOSCEN = 0:     //          External clock from TxCKI pin (on the rising edge)     //      If TxSOSCEN = 1:     //          Crystal oscillator on SOSCI/SOSCO pins     //  01 =Timer1/3/5 clock source is system clock (FOSC)     //  00 =Timer1/3/5 clock source is instruction clock (FOSC/4)     T1CONbits.TMR1CS = 2;   //  T1CKI pin         //  3 1:8 Prescale value, 2 1:4, 1 1:2, 0 1:1     T1CONbits.T1CKPS = 0;     // Secondary Oscillator Enable Control bit     T1CONbits.T1SOSCEN = 0;     //  Timer1/3/5 External Clock Input Synchronization Control bit     //  TMRxCS<1:0> = 1X     //      1 = Do not synchronize external clock input     //      0 = Synchronize external clock input with system clock (FOSC)     //  TMRxCS<1:0> = 0X     //      This bit is ignored. Timer1/3/5 uses the internal clock when TMRxCS<1:0> = 1X.     T1CONbits.T1SYNC = 1;     //  16-Bit Read/Write Mode Enable bit     T1CONbits.RD16 = 0;     //  TMRxON: Timer1/3/5 On bit     //      1 = Enables Timer1/3/5     //      0 = Stops Timer1/3/5     //          Clears Timer1/3/5 Gate flip-flop     T1CONbits.TMR1ON = 1;     // 割込み許可     TMR1IE = 1;     PEIE = 1;     GIE = 1;     //  それぞれのビットの意味がわかるように書いています。     //  実際にコーディングするときはふつうに書いてください。     //  TMRxGE: Timer1/3/5 Gate Enable bit     //  If TMRxON = 0:     //      This bit is ignored     //  If TMRxON = 1:     //      1 = Timer1/3/5 counting is controlled by the Timer1/3/5 gate function     //      0 = Timer1/3/5 counts regardless of Timer1/3/5 gate function     T1GCONbits.TMR1GE = 1;     //    TxGPOL: Timer1/3/5 Gate Polarity bit     //      1: active High, 0: active Low     T1GCONbits.T1GPOL = 0;     //  TxGTM: Timer1/3/5 Gate Toggle Mode bit     //  RTC,GPS等のときはセット、たいていの場合セットした方がいいはずです。     T1GCONbits.T1GTM = 1;     //TxGSPM: Timer1/3/5 Gate Single-Pulse Mode bit     T1GCONbits.T1GSPM = 1;     //  TxGGO/DONE: Timer1/3/5 Gate Single-Pulse Acquisition Status bit     T1GCONbits.T1GGO_NOT_DONE = 1;     //  TxGVAL: Timer1/3/5 Gate Current State bit     //  Indicates the current state of the Timer1/3/5 gate that could be provided to TMRxH:TMRxL.     //  Unaffected by Timer1/3/5 Gate Enable (TMRxGE).     //  Read Only     //  TxGSS<1:0>: Timer1/3/5 Gate Source Select bits     //      00 = Timer1/3/5 Gate pin     //      01 = Timer2/4/6 Match PR2/4/6 output (See Table 12-6 for proper timer match selection)     //      10 = Comparator 1 optionally synchronized output (sync_C1OUT)     //      11 = Comparator 2 optionally synchronized output (sync_C2OUT)     T1GCONbits.T1GSS = 0;     InitI2C_Master() ;     LCD_Init() ;     LCD_Clear();     LCD_Puts("Start!");     while(1) {         //  割込みの処理はさっさと済ませて次の割込みに備えます。         if( Interrupt == 1 ) {             count++;             Interrupt = 0;             continue;         }         // カウント終了まで待ちます。         if( T1GCONbits.T1GGO_NOT_DONE == 1 ) continue;         F_Low = TMR1L;         F_High = TMR1H;         frq = count;         frq = (frq << 8) + F_High;         frq = (frq << 8) + F_Low;         sprintf(buf,"%12ld",frq);         LCD_SetCursor(0,0);         LCD_Puts(buf);
// タイマーソースに周波数既知の信号源、タイマーゲートソースに未知の信号源の場合         if( frq != 0 ) frq = 20000000 / frq;         sprintf(buf,"%12ld",frq);         LCD_SetCursor(0,1);         LCD_Puts(buf);         for(i=0; i <20; i++ ) __delay_ms(10); // 表示が確認できるように.....         //  次の計測に入ります。         TMR1H =0;         TMR1L =0;         count = 0;         T1GCONbits.T1GGO_NOT_DONE=1;     }; }

 

« 続・サーミスタで正確な温度を測るコツ - 基準抵抗(R0)、B定数、熱拡散係数、... | トップページ | VFコンバータ(VCO)の製作(3) - 自動周波数特性測定器に向けて »

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

コメント

着々と進んでますね(^-^)
カウンタのアーキテクチャは例の方を参考にされたのでしょうか。
GPSの信号を使えば確かに正確なゲート時間が得られますよね。たしかにこれ以上正確なソースは他では手軽に得られないかも。ますます完成が楽しみです^^。

例の方を始めあちこち散策したのですが、結論としてMicrocchipのデータシートがいちばん役にたちました (^^;;
ほよほよさんの正弦波的なブレークスルーを期待していたのですが、やっぱりそういうのはめったにあるものじゃなさそうです (^^)

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: GPS/RTC(DS3234)の1PPS出力を利用した超高精度周波数カウンター:

« 続・サーミスタで正確な温度を測るコツ - 基準抵抗(R0)、B定数、熱拡散係数、... | トップページ | VFコンバータ(VCO)の製作(3) - 自動周波数特性測定器に向けて »

フォト

サイト内検索

  • 記事を探されるんでしたらこれがいちばん早くて確実です。私も使ってます (^^;; 検索窓が表示されるのにちょっと時間がかかるのはどうにかしてほしいです。

新着記事

リンク元別アクセス数

  • (アクセス元≒リンク元、原則PCのみ・ドメイン別、サイト内等除く)

人気記事ランキング

  • (原則PCのみ、直近2週間)
無料ブログはココログ