PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方(ソース付き)
タイトルの「超高精度SPIバスRTC(リアルタイムクロック)DS3234S」というのは秋月電子通商のサイトにそう書いてありました。
「Maxim Integrated - DS3234 水晶およびSRAM内蔵、超高精度SPIバスRTC」には「全機能内蔵、高精度タイミングソリューションは、工業用温度範囲で年間±2.0分より優れた精度を提供し、ユーザ較正が不要」とありました。
秋月にはペラペラの資料しかありませんが、実際に使うにはデータシートを読む必要がありそれは「Maxim Integrated - DS3234 Datasheet」にあります。
このデータシートも日本語に翻訳された方がいらっしゃいます。
「DS3234 日本語マニュアル - Ne」
------
このデバイスは民生品(?)のDS3234S(0deg.C~70deg.C)と工業用のDS3234SN(-40deg.C~85deg.C)がありいずれも0deg.C~40deg.Cの範囲では±2ppmつまり10日で狂いは1秒以下という精度を誇るようです(ただこれでも10分で1/1000秒誤差が出る可能性があるわけで掩蔽観測用には精度が不十分でしょう)
今回はこうやったら動いた、というだけのソースです。GPSを基準にした精度検証を近いうちに書くつもりです。またRTCは時刻合わせをどうやるかがけっこう面倒なのでそれについても気が向いたら書いてみたいと思います。
時刻合わせについては別に記事を書きました。
「RTC(リアルタイムクロック)の時刻を合わせる方法 - DS3234Sを例に」
なお実装の状況については
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装」
に簡単に書いておきました。また“実用“に使った例が
「PIC/I2C大気圧センサーLPS331APの測定値をSDカード(SPI)に記録する - はじめに」
「超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの実力」
にあります。
ではさっそく使い方を....
=======
今回もPIC18F26K22を使います。なんでこれだけのために28ピンもあるPICを使わなければいけないんだろうとは思うのですが....
ちょっとはまりました。今度はSDOをDoutに接続したとかではなくコーディングでですが。
-------
回路図を書くのが面倒なのでどういう具合に接続されているかだけ書いておきます。
カッコつきの数字はPickKit3のピン番号です。
// 01 /MCLR .....(1)
// 02 RA0/AN0 ====> DS3234のNo.1 /CS
// 03 RA1/AN1 ====> 初期化するか(0)、しないか(1)の選択
// 14 RC3/SCL1 =====> I2Cバス
// 15 RC4/SDA1 =====> I2Cバス
// 19 VSS .....(3)
// 20 VDD .....(2)
// 22 RB1/INT1/P1C/SCK2/SCL2/C12IN3-/AN10 =====> DS3234のNo.18or20のSCLK
// 23 RB2/INT2/CTED1/P1B/SDI2/SDA2/AN8 =====> DS3234のNo.19のDOUT
// 24 RB3/CTED2/P2A/CCP2/SDO2/C12IN2-/AN9 =====> DS3234のNo.17のDIN
// 27 RB6/TX2/PGC .....(5)
// 28 RB7/RX2/PGD .....(4)
DS3234のNo.5の/INT/SQWには1PPSが出るようにしました。(今回はそうしていませんが)この出力で割り込みをかければ毎秒時刻表示を更新するということができます。
この端子はオープンドレインなのでプルアップが必要です。
DS3234のNo.16のVBATは3Vのリチウム電池に接続するのですが、テスト中でバックアップなしのときはGNDに落とします。
NCピンが大量にありデータシートの“No Connection. Not connected internally. Must be connected to ground.”という記述が気になりますが、今回はすべてオープンにしています。
------
以下記事の最後にあるソースも参考にしてください。
コマンドはアドレスを送るだけです。先頭ビットをクリアしたらread、セットしたらwriteと簡単です。
writeはコマンドを送った(先頭アドレスを指定した)あとデータを順番に送ればいいです。
readはコマンドを送った(先頭アドレスを指定した)あと、ダミーのデータを送信するたびにデータを1byte読み込むことができます。つまり指定のアドレスを1byte読み込むためには2バイト送信する必要があります。
なお曜日(1~7)は「PICでI2C - リアルタイムクロック(RTC) DS1307+の使い方」のときも日曜日が1だか月曜日が1だかわからないと書いたのですが、これは自分の好きな曜日を1にすればあとは順にカウントアップされていき7の次は1になるだけのようです。だからアラビア風(?)土曜日を1にしてもいいでしょう。
アドレスは0x00から順番に「秒、分、時、曜日、日、月、年」になっています。いずえもBCDで格納されています。
他にアラーム(2個)や制御のためのレジスタがいろいろあるのですが、注目を引くものが二つあります。
ひとつはAging Offset Registerです。0.1ppmくらいの単位で微調整ができます。0.1ppmとなると3ヶ月で1秒くらいの誤差まで追い込めそうですが、室温で温度による変化はもっと大きいのでそこまではムリでしょう。恒温槽に入れるという手はありそうですが。
もうひとつはTemperature Registersです。あんまり精度はよくないようですが、温度と聞くとテンションがあがります (^^;;
なお256バイトのSRAMがついています。自由に使っていいみたいですが、アクセスはアドレスを0x18レジスタに書き込んで指定したあと指定されたアドレスのSRAMの内容を0x19レジスタで読み書きするという方法をとります。ちょっと面倒ですが連続したアドレスの読み書きは可能なようです(まだやってみてません)
---------------------------
関連
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方」 (ソース付き)
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装」
「RTC(リアルタイムクロック)の時刻を合わせる方法 - DS3234Sを例に」
「超高精度SPIバスRTC(リアルタイムクロック)DS3234Sは一ヶ月に0.2秒進む」
「ほんとうに超高精度かもしれないRTC・DS3234Sを使った周波数カウンター」
「超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの実力」
「超高精度SPIバスRTC(リアルタイムクロック)DS3234Sを使った周波数カウンターの限界」
「測定対象別記事一覧(測定、電子工作、天文計算)」
「過去記事の一覧(測定、電子工作、天文計算)」
参考
「ほよほよのブログ - 超高精度リアルタイムクロックDS3234Sを動かす」
(一つのSSPをI2CとSPIで共用する方法があります)
--------
main.c
これ以外はすべて「PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き)」に書いたものと同じです。
#include <xc.h>
#include <stdio.h>
#include "MyDef.h"
#include "I2CLib.h"
#include "SPILib.h"
#include "ACM1602lib.h"
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html
#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF
void putLCDhex(unsigned char ch)
{
char hex[]="0123456789SBCDEF";
LCD_Putc(hex[ch>>4]) ;
LCD_Putc(hex[ch & 0x0f]) ;
}
void interrupt InterFunction( void )
{
// I2C関連の割り込み処理
InterI2C() ;
}
void main()
{
unsigned short i=0;
int j;
unsigned char d1,d2,d3;
unsigned char ct[7]={0x14,0x12,0x04,0x07,0x23,0x59,0x50};
float Vref=3.3;
float value;
char buf[20];
OSCCON = MyOSCCON ;
// for I2C
ANSELCbits.ANSC3 = 0;
ANSELCbits.ANSC4 = 0;
// for SPI
ANSELBbits.ANSB2 = 0;
ANSELBbits.ANSB1 = 0;
TRISB1 = 0;
TRISB3 = 0;
// OUTPUT /CS
TRISA0 = 0;
PORTAbits.RA0 = 1;
// INPUT
ANSELAbits.ANSA1 = 0;
SPI_Init(SPI_MODE0,SPI_CLOCK_DIV4) ;
InitI2C_Master() ;
LCD_Init() ;
LCD_Clear();
// RA1がLowに落ちているときは日時設定を設定します。
// 自分の好きな曜日を1にします。
if( PORTAbits.RA1 == 0 ) {
PORTAbits.RA0 = 0;
d1=SPI_transfer(0x80) ;
for( j =0; j < 7; j++ ) {
d1=SPI_transfer(ct[6-j]) ;
}
PORTAbits.RA0 = 1;
// 1PPS出力を開始します。
PORTAbits.RA0 = 0;
d1=SPI_transfer(0x0E) ;
d1=SPI_transfer(0x00) ;
PORTAbits.RA0 = 1;
PORTAbits.RA0 = 0;
d2=SPI_transfer(0x8E) ;
d3=SPI_transfer(d1 & 0xE3) ;
PORTAbits.RA0 = 1;
}
while(1) {
PORTAbits.RA0 = 0;
d1=SPI_transfer(0x00) ;
for( j =0; j < 7; j++ ) {
ct[6-j]=SPI_transfer(0x00) ;
}
PORTAbits.RA0 = 1;
LCD_SetCursor(0,0);
for( j=0; j < 7; j++ ) {
putLCDhex(ct[j]);
}
for( j=0; j < 12; j++ ) __delay_ms(40);
i++;
}
}
« 「写真から撮影方向を分析する」アプリ (2) | トップページ | 乾通り一般公開・経路と待ち時間(というか所要時間) (1) »
「趣味の電子工作」カテゴリの記事
- PICで作る100MHz周波数カウンタ検証用XOR(エクスクルーシブオア)逓倍器(2016.03.08)
- 150MHz(~200MHz?)周波数カウンター用プリスケーラー(1/4分周器)(2016.03.06)
- 測温抵抗体(Pt100、白金薄膜温度センサー)の抵抗値を温度に変換する(平方根を使わない)計算式(2016.03.01)
- GPS/JJY(標準電波)を基準周波数源とするためのPLLの詳細(2016.02.27)
- GPS受信モジュール1PPS対決 - GE-612T vs GM-5157A(2016.02.21)
コメント
この記事へのコメントは終了しました。
« 「写真から撮影方向を分析する」アプリ (2) | トップページ | 乾通り一般公開・経路と待ち時間(というか所要時間) (1) »
このRTCを先日入手しました^^。
そしてこちらのサンプルを見てプログラムを書き始めようとしているところです^^。
ところで、DS3234Sの添付資料には「4MHz SPI Bus Supports Modes 1 and 3」とありますが、上記のサンプルプログラムではSPI_InitでMODE0を指定しています。MODE0でも動いたということですか?
それとも#defineでの定義が実は違っているとか^^;
いずれ自分でも確認しますが、ちょっと気になったもので。
投稿: ほよほよ | 2016年4月19日 (火) 13時49分
このDS3234Sは超おすすめです。
キャリブレーションをちゃんとやっておくと(時計とか周波数カウンタ用としては、ですが)GPSなみです。
skSPIlib.hを確認したのですが
#define SPI_MODE0 0 // クロック極性(0:LOW) クロック位相(0:アイドル0Vで、0V->5Vに変化で転送)
となっていました。ソース自体はきむしげさんのをそのまま使っています。
SPIのモードの表現はいろいろあってよくわからないので、SPIのデバイスはモードを変えながらやって動いたものを採用しています (^^;;
他のモードで動いたかどうかはちょっと記憶がありません。お役にたてずすみません。
skSPIlibの方もそのまま使っているはずで次のようになっています。
con = 0b00100000 ; // クロック極性はLOW マスタモードでFOSC/4のクロックに設定
stat = 0b00000000 ; // クロック位相は立下りでデータを送信
con = con | divider ; // 指定のクロック速度を設定する
if (mode == SPI_MODE1 || mode == SPI_MODE3) {
stat = stat | 0x40 ; // 指定のクロック位相を設定する
}
if (mode == SPI_MODE2 || mode == SPI_MODE3) {
con = con | 0x10 ; // 指定のクロック極性を設定する
}
SPI_SSPCON1 = con ;
SPI_SSPSTAT = stat ;
投稿: セッピーナ | 2016年4月19日 (火) 17時47分
これが原因でSPI機器が複数あったとき同時に動かせなかった、なんてことになってはいまいか一瞬思ったので指摘してみました^^;
(実は私もモードが4つしかないのをいいことに、動くモードで動かしていたクチです^^;)
それはさておき、実はたったいま原因が判明しました。
http://wazalabo.com/pic-spi.html ←参考
私もきむしげさんの関数を使っていてモード0、2でDS3234Sが動いたので、マニュアルが言うモード1、3サポートとの食い違いを正そうと調べていました。
きむしげさんのプログラム上で
MODE1 || MODE3
の部分を
MODE0 || MODE2
に修正するのが正解だと思います。
PICのマニュアルに CKE=1の意味がクロックActive→Idleでデータ転送、と書いてあります。
で、ActiveというのはCKP(クロック極性)によってLowだったりHighだったりするので、立下り立ち上り表現はひっくり返るので適しません。
きむしげさんがコメント通りに理解しているのであれば、勘違いですね。
お騒がせいたしました。
投稿: ほよほよ | 2016年4月19日 (火) 18時21分
あ、そういうことなんですね。
SPIデバイスはいくつか使ったのですが、全体的iにモードが合わない(ずれている?)感じで、モードの解釈が人によって違うんだろうと自分を納得させていました (^^;;
これはきむしげさんにお知らせしていた方がよさそうですね。
修正済みで私が気づいていなかっただけなのかもしれませんが。
複数デバイスが使えない(SDカードが使えない)件は理由が__というかどういう場合エラーが起きるか__だいたいわかり、最近はすぐに対応できるようになりました。
投稿: セッピーナ | 2016年4月19日 (火) 19時05分
きむしげさんちへの連絡方法がわからないのでどうしようかと思っていましたが、掲示板をさきほど発見しました^^。
ご挨拶がてら書き込んでこようかと思います。
投稿: ほよほよ | 2016年4月19日 (火) 23時52分
あ、そうなんです。別に掲示板を用意されているんですよね。
ほよほよさんの書き込み拝見しました。
また記事を訂正せねば (^^;;
投稿: セッピーナ | 2016年4月20日 (水) 10時21分