« VM39S5G(VCTCXO)を使ってみた - 2 - 電源電圧と出力レベル | トップページ | VM39S5G(VCTCXO) - 温度補償型水晶発振器の温度係数を測る »

2015年3月 2日 (月)

RTC(リアルタイムクロック)の時刻を合わせる方法 - DS3234Sを例に

今使っているRTC、DS3234Sはほとんど進み遅れがないのであんまり時刻合わせの必要がないので時刻を合わせるときはその場限りのプログラムを書いてすませていました。
最近いろいろテストしているとときどき“事故”で時刻がクリアされてしまうことがあるのでめんどうになって時刻合わせの機能も取り入れることにしました。

時刻をGPSに同期させたいという方もいらっしゃると思います。やり方を解説したものがありますので紹介しておきます。

  ほよほよのブログ - DS3234S(超高精度RTC)をGPSと同期する

ソースはありませんので、時刻設定部分はこの記事を参考にしていただければと思います。

======

これまで作成してきた

  「PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計+周波数カウンタ(技術要素一覧表)
    (各種のデバイスの操作に関する説明やソースの記事へのリンクがあります)
  「PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計のソース - main()
    (この記事にある関数の上位部分のソースがあります)

にある“測定装置”とプログラムを前提にしています。
Imgp87031200

黄色いタクトスイッチ(メニューボタン)を押したまま起動するとAging Offset(時計の歩度=発振周波数の微調整の機能)の設定画面に入ります(上の写真はSDカードへの記録のインターバルの設定画面です)

AgingOffsetの値を可変抵抗で設定し青いタクトスイッチ(決定ボタン)を押すと値が保存されます。可変抵抗を動かさずに決定ボタンを押すと現在の値がそのまま保存されます。

メニューボタンを押したまま、AgingOffsetの決定ボタンを押すとさらに時刻の設定画面に入ります。秒から順番に可変抵抗での値の設定、決定ボタンによる値の保存を繰り返していきます。

下のプログラムでは可変抵抗にさわらず(値を変更せずに)決定ボタンを押すと現在の値がそのまま保存されるようになっていますが、よく考えるとこれはあんまりよくなくて、この場合は“保存せずに次の設定画面に進む”というのが適切だったように思いますが後の祭りです (^^;;

DS3234Sの場合時刻設定のときはたいてい秒の設定をするのでこのプログラムでもとくに使いにくいというわけでもないのですが....

---------------------------

関連

  「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方」 (ソース付き)
  「
PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装
  「
RTC(リアルタイムクロック)の時刻を合わせる方法 - DS3234Sを例に
  「
超高精度SPIバスRTC(リアルタイムクロック)DS3234Sは一ヶ月に0.2秒進む

  「
超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの実力
  「
超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの限界

  「測定対象別記事一覧(測定、電子工作、天文計算)
  「
PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計+周波数カウンタ(技術要素一覧表)
  「
PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計のソース - main()

  「過去記事の一覧(測定、電子工作、天文計算)
-------

可変抵抗で値を設定する関数

// 可変抵抗の抵抗値から設定値を求めます。
// low     設定値の下限
// high     設定値の上限
// interval 設定値の間隔
// start    設定値の初期値
// clm      値の表示エリアの開始カラム
// row      値の表示エリアの開始行
// Disp     値の表示形式 1: 十進、2: 16進、 3: 両方
//
int getValFromVR(int low, int high,
        int interval, int start, int clm, int row,int Disp)
{
    int val;
    int val_t, step, old_val=0x0FFF;
    char buf[16];
    // 可変抵抗を動かさなかったときは初期値を戻り値とするため
    val = start;
    // ADコンバータの値を変換するときの比率を決めます
    step = 0x0400 / ( high - low ) * interval;
    while(1) {
        ADCON0 = 0b00000011 ;             // AN0のAD変換開始
        while(ADCON0 & 0b00000010) ;      // ADC変換終了待ち
        val_t = ADRESH * 256 + ADRESL;
        // ADコンバータの値を設定値に変換します。
        val_t = val_t / step * interval+ low;
        // 可変抵抗が動いているかいないかによって処理が異なります。
        if( old_val == 0xFFF ) old_val = val_t;
        if( val_t != old_val ) {
            val = val_t;
            old_val = val_t;
        }
        // 設定値を表示します。
        if( Disp == 3 ) {
            sprintf(buf,"%4d %02X ",val,val & 0x00FF);
        } else if( Disp == 2 ) {
            sprintf(buf,"%02X      ",val & 0x00FF);
        } else {
            sprintf(buf,"%4d    ",val);
        }
        LCD_SetCursor(clm,row);
        LCD_Puts(buf);
        putLCDhex(start);
        // 決定ボタンが押されたら設定値が確定します。
        if( PORTAbits.RA2 == 0 ) break;
    }
    // 決定ボタンが押し終わったのを確認します。
    // ウェイトはチャタリング対策です。
    __delay_ms(31);
    while(PORTAbits.RA2 == 0);
    __delay_ms(31);
    return val;
}


Aging Offsetと時刻を設定する関数

この関数はプログラムの最初に必ず実行されます。
Aging Offsetの値は重要で取得してSDカードに書き込む必要があるためです。
起動されたときメニューバタンが押されているとその後の処理に進みます。

// http://datasheets.maximintegrated.com/en/ds/DS3234.pdf

unsigned char SetRTC(void)
{
    unsigned char i, d1, d2, d3;
    int val, AgingOffset;
    char title[7][8]={"Sec.   ","Min.   ","Hour   ","Day    ","Date   ","Month  ","Year   "};
    // 設定値の範囲
    // ほんとうは最小値の設定もしなければならないのですがめんどうでぜんぶ0にしています。
    short maxvalue[7]={59,59,23,7,31,12,20};
    // SPI MODE 0
    SSP2STAT &= 0xBF;
    SSP2CON1 &= 0xEF;
    // 1PPS出力を開始します。
    // RTCの内部時刻データがぐちゃぐちゃになっても1PPSだけは出力されるようにします。
    CS_RTC = 0;
    d1=SPI_transfer(0x0E) ;
    d1=SPI_transfer(0x00) ;
    CS_RTC = 1;
    CS_RTC = 0;
    d2=SPI_transfer(0x8E) ;
    d3=SPI_transfer(d1 & 0xE3) ;
    CS_RTC = 1;
    // AgingOffsetの値を取得します。
    CS_RTC = 0;
    d1=SPI_transfer(0x10) ;
    AgingOffset=SPI_transfer(0x00) ;
    CS_RTC = 1;
    // AgingOffsett調整と時刻合わせはメニューボタンを押したまま起動したときに限られます。
    if( PORTAbits.RA1 != 0 ) return AgingOffset;
    // まずAgingOffsetを設定します
    LCD_Clear();
    LCD_Puts("Offset=");
    // 可変抵抗の抵抗値でAgingOffsetの値を決めます。
    // 可変抵抗に手をふれず決定ボタンを押せば値は変更されません。
    AgingOffset = getValFromVR(-10, 32,1, AgingOffset, 8, 0, 3);
    // 設定値を保存します
    CS_RTC = 0;
    d1=SPI_transfer(0x90) ;
    d1=SPI_transfer(AgingOffset) ;
    CS_RTC = 1;
    // 時刻合わせはメニューボタンを押したまま決定ボタンを押したときに限られます。
    if( PORTAbits.RA1 != 0 ) return AgingOffset;
    // 時刻合わせが多いと思われる下の桁(秒)から合わせていきます。
    // 可変抵抗に手をふれず決定ボタンを押して行けば値は変更されません。
    for(i=0; i<7; i++ ) {
        // 現在の設定値を取得します。
        CS_RTC = 0;
        d1=SPI_transfer(i) ;
        d1=SPI_transfer(0x00) ;
        CS_RTC = 1;
        LCD_Clear();
        LCD_Puts(title[i]);
        // BCDを10進数に変換します。
        d1 = (d1>>4)*10+(d1 & 0x000F);
       
        // 可変抵抗で設定値を決めます
        // 可変抵抗の抵抗値が変化しないときは現在の設定値が保存されます
        val = getValFromVR(0, maxvalue[i],1, d1, 8, 0, 1);
       
        // BCDに変換します。
        val = (( val /10 ) << 4) + ( val % 10);
        // 設定値を保存します。
        CS_RTC = 0;
        d1=SPI_transfer(i+0x80) ;
        d1=SPI_transfer(val) ;
        CS_RTC = 1;
          
    }
    return AgingOffset;
}

« VM39S5G(VCTCXO)を使ってみた - 2 - 電源電圧と出力レベル | トップページ | VM39S5G(VCTCXO) - 温度補償型水晶発振器の温度係数を測る »

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

コメント

コメントを書く

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

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1994983/59118047

この記事へのトラックバック一覧です: RTC(リアルタイムクロック)の時刻を合わせる方法 - DS3234Sを例に:

« VM39S5G(VCTCXO)を使ってみた - 2 - 電源電圧と出力レベル | トップページ | VM39S5G(VCTCXO) - 温度補償型水晶発振器の温度係数を測る »

フォト

サイト内検索

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

新着記事

リンク元別アクセス数

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

人気記事ランキング

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