eepoo が 2021年02月21日09時31分06秒 に編集
初版
タイトルの変更
GPSのPPSを利用したRTCの精度測定器
タグの変更
秋葉原2021
GPS
PPS
RTC
本文の変更
DS3231を使ったRTCが安く出回っている。データシートによると2ppmを詠っているので一日0.2秒弱の誤差のはずだが結構当たりはずれがある。最初は選別するために電波時計と目視比較でチェックしていたが、0.2秒程度の解像度(笑)しか期待できない上に、電波時計も校正直後以外は案外ずれていることが分かった。 なんたって精度ならGPSでしょう。ということで手持ちのGPSが流してくれるシリアルデータを解析。特定のタグを毎秒流すのでそれを利用した。ところが短期間は安定しているものの、数時間でごそっとシフトすることが分かった。理由はわからないが、、 次に117の音声信号をマイクで拾ってLow Pass Filterをかけて信号の立ち上がりを比較するようにした。悪くないんだけど、117が案外お金がかかる。 ネット上のJJY的な信号を流しているところや原子時計アプリも使ってみたが、ちゃんとモニターしてみると信号が安定していない。 本家JJYを受信しようとキットも買ったが家の中では電波が弱くて、、 聞けばGPSは一秒ごとのパルスを出してくれるはずというではないか。 いや、私のGPSにはそんな端子がないんですけど、、ん、でもLEDにPPSって書いてあるぞ。 だめもとで高度な半田テクニック(笑)を用いて信号線を引き出した。(画像黄色のリード線)  モニターしてみるときれいなパルスが出ている、、が電圧が低いのでトランジスタでしゃっきりさせてarduino nanoの割込みポートへ。一方のRTCからもSQWという端子からPPSが出ているのでそちらも割込みへ。双方の割込み時の micros() を比較し、差を7セグ表示機(TM1637)に表示。一度に2つチェックできるようにnanoを二つ並べGPS信号は共用した。   これで適当な時間にチェックして表示の差を時間で割れば、一日当たりの精度を求めることができる。 ```GPSとRTCのトリガ差で精度チェック #include <DS3231.h> #include <Wire.h> #include <TM1637Display.h> #define CLK 6 #define DIO 5 TM1637Display display(CLK, DIO); volatile unsigned long cpuClock = 0; //GPSトリガー毎のcpuClock数をバッファする volatile unsigned long lastGPS = 0; //GPSトリガー毎のcpuClock数を算出するため volatile bool sqrInt = false; volatile bool d3Int = false; volatile unsigned long lastDS = 0; volatile unsigned long lastDelta = 0; DS3231 Clock; //DS3231からの一秒ごとの割込み void sqrSecIntHandler() { lastDS = micros(); } //GPSからのPPS D3に繋いだ void d3Out() { d3Int = true; unsigned long curr = micros(); cpuClock = curr - lastGPS; lastGPS = curr; lastDelta = micros() - lastDS; } void setup() { Serial.begin(115200); Wire.begin(); display.setBrightness(0x0f); display.showNumberDec(0, false); pinMode(2, INPUT);//DS3231からのオシレート Clock.enableOscillator(true, true, 0); attachInterrupt(0, sqrSecIntHandler, FALLING); pinMode(3, INPUT_PULLUP); attachInterrupt(1, d3Out, FALLING); } void loop() { //GPSのオシレート if (d3Int) { d3Int = false; //cpuの温度ドリフトによるクロック数変化をキャンセルする float delta = (float)lastDelta * 1000000.0 / (float)cpuClock; lastDelta = delta; display.showNumberDec(lastDelta / 100, false); } } ```